private IEnumerator CubemapToEquirectangularCpuGeneralCase(uint[] cameraPixels, byte[] pixelValues, int stride, int panoramaWidth, int panoramaHeight, int ssaaFactor, float startTime, float processingTimePerFrame, float maxWidth, float maxHeight, int numPixelsAveraged,
int startX, int startY, int endX, int endY)
{
for (int y = startY; y < endY; y++)
for (int x = startX; x < endX; x++)
{
int rTotal = 0, gTotal = 0, bTotal = 0, aTotal = 0;
for (int ySsaa = y * ssaaFactor; ySsaa < (y + 1) * ssaaFactor; ySsaa++)
for (int xSsaa = x * ssaaFactor; xSsaa < (x + 1) * ssaaFactor; xSsaa++)
{
float xcoord = (float)xSsaa / (panoramaWidth * ssaaFactor);
float ycoord = (float)ySsaa / (panoramaHeight * ssaaFactor);
float latitude = (ycoord - 0.5f) * Mathf.PI;
float longitude = (xcoord * 2.0f - 1.0f) * Mathf.PI;
// Equivalent to: Vector3 equirectRayDirection =
// Quaternion.Euler(-latitude * 360/(2*Mathf.PI), longitude * 360/(2*Mathf.PI), 0.0f) * new Vector3(0, 0, 1);
float cosLat = Mathf.Cos(latitude);
Vector3 equirectRayDirection = new Vector3(
cosLat * Mathf.Sin(longitude), -Mathf.Sin(latitude), cosLat * Mathf.Cos(longitude));
float distance = 0.0f;
CubemapFace face;
float u, v;
{
distance = 1.0f / equirectRayDirection.y;
u = equirectRayDirection.x * distance; v = equirectRayDirection.z * distance;
if (equirectRayDirection.y > 0.0f)
{
face = CubemapFace.PositiveY;
}
else
{
face = CubemapFace.NegativeY;
u = -u;
}
}
if (Mathf.Abs(u) > 1.0f || Mathf.Abs(v) > 1.0f)
{
distance = 1.0f / equirectRayDirection.x;
u = -equirectRayDirection.z * distance; v = equirectRayDirection.y * distance;
if (equirectRayDirection.x > 0.0f)
{
face = CubemapFace.PositiveX;
v = -v;
}
else
{
face = CubemapFace.NegativeX;
}
}
if (Mathf.Abs(u) > 1.0f || Mathf.Abs(v) > 1.0f)
{
distance = 1.0f / equirectRayDirection.z;
u = equirectRayDirection.x * distance; v = equirectRayDirection.y * distance;
if (equirectRayDirection.z > 0.0f)
{
face = CubemapFace.PositiveZ;
v = -v;
}
else
{
face = CubemapFace.NegativeZ;
}
}
u = (u + 1.0f) / 2.0f;
v = (v + 1.0f) / 2.0f;
// Boundary: should blend between cubemap views, but for now just grab color
// of nearest pixel in selected cubemap view
u = Mathf.Min(u, maxWidth);
v = Mathf.Min(v, maxHeight);
Color32 c = GetCameraPixelBilinear(cameraPixels, (int)face, u, v);
rTotal += c.r; gTotal += c.g; bTotal += c.b; aTotal += c.a;
}
int baseIdx = stride * (panoramaHeight - 1 - y) + x * 4;
pixelValues[baseIdx + 0] = (byte)(bTotal / numPixelsAveraged);
pixelValues[baseIdx + 1] = (byte)(gTotal / numPixelsAveraged);
pixelValues[baseIdx + 2] = (byte)(rTotal / numPixelsAveraged);
pixelValues[baseIdx + 3] = (byte)(aTotal / numPixelsAveraged);
if ((x & 0xFF) == 0 && Time.realtimeSinceStartup - startTime > processingTimePerFrame)
{
yield return null; // Wait until next frame
startTime = Time.realtimeSinceStartup;
}
}
}