IEnumerator CubemapToEquirectangularCpu(uint[] cameraPixels, int cameraWidth, int cameraHeight, byte[] pixelValues,
int stride, int panoramaWidth, int panoramaHeight, int ssaaFactor, bool async)
{
Log("Converting to equirectangular");
yield return null; // Wait for next frame at beginning - already used up some time capturing snapshot
float startTime = Time.realtimeSinceStartup;
float processingTimePerFrame = cpuMillisecondsPerFrame / 1000.0f;
float maxWidth = 1.0f - 1.0f / cameraWidth;
float maxHeight = 1.0f - 1.0f / cameraHeight;
int numPixelsAveraged = ssaaFactor * ssaaFactor;
// For efficiency we're going to do a series of rectangles each drawn from only one texture,
// only using the slow general-case reprojection where necessary.
int endYPositive = (int)Mathf.Floor(panoramaHeight * 0.25f);
int startYNegative = (int)Mathf.Ceil(panoramaHeight * 0.75f);
// 0.195913f is angle in radians between (1, 0, 1) and (1, 1, 1) over pi
int endTopMixedRegion = (int)Mathf.Ceil (panoramaHeight * (0.5f - 0.195913f));
int startBottomMixedRegion = (int)Mathf.Floor(panoramaHeight * (0.5f + 0.195913f));
int startXNegative = (int)Mathf.Ceil (panoramaWidth * 1.0f / 8.0f);
int endXNegative = (int)Mathf.Floor(panoramaWidth * 3.0f / 8.0f);
int startZPositive = (int)Mathf.Ceil (panoramaWidth * 3.0f / 8.0f);
int endZPositive = (int)Mathf.Floor(panoramaWidth * 5.0f / 8.0f);
int startXPositive = (int)Mathf.Ceil(panoramaWidth * 5.0f / 8.0f);
int endXPositive = (int)Mathf.Floor(panoramaWidth * 7.0f / 8.0f);
int startZNegative = (int)Mathf.Ceil(panoramaWidth * 7.0f / 8.0f);
int endZNegative = (int)Mathf.Floor(panoramaWidth * 1.0f / 8.0f); // z negative wraps/loops around
if (async)
{
yield return StartCoroutine(CubemapToEquirectangularCpuPositiveY(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
0, 0, panoramaWidth, endYPositive));
yield return StartCoroutine(CubemapToEquirectangularCpuNegativeY(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
0, startYNegative, panoramaWidth, panoramaHeight));
yield return StartCoroutine(CubemapToEquirectangularCpuPositiveX(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
startXPositive, endTopMixedRegion, endXPositive, startBottomMixedRegion));
yield return StartCoroutine(CubemapToEquirectangularCpuNegativeX(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
startXNegative, endTopMixedRegion, endXNegative, startBottomMixedRegion));
yield return StartCoroutine(CubemapToEquirectangularCpuPositiveZ(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
startZPositive, endTopMixedRegion, endZPositive, startBottomMixedRegion));
// Do in two pieces since z negative wraps/loops around
yield return StartCoroutine(CubemapToEquirectangularCpuNegativeZ(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
startZNegative, endTopMixedRegion, panoramaWidth, startBottomMixedRegion));
yield return StartCoroutine(CubemapToEquirectangularCpuNegativeZ(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
0, endTopMixedRegion, endZNegative, startBottomMixedRegion));
// Handle all remaining image areas with the general case
yield return StartCoroutine(CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
0, endYPositive, panoramaWidth, endTopMixedRegion));
yield return StartCoroutine(CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
0, startBottomMixedRegion, panoramaWidth, startYNegative));
// If width is not multiple of 8, due to rounding, there may be one-column strips where the X/Z textures mix together
if (endZNegative < startXNegative)
yield return StartCoroutine(CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
endZNegative, endTopMixedRegion, startXNegative, startBottomMixedRegion));
if (endXNegative < startZPositive)
yield return StartCoroutine(CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
endXNegative, endTopMixedRegion, startZPositive, startBottomMixedRegion));
if (endZPositive < startXPositive)
yield return StartCoroutine(CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
endZPositive, endTopMixedRegion, startXPositive, startBottomMixedRegion));
if (endXPositive < startZNegative)
yield return StartCoroutine(CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
endXPositive, endTopMixedRegion, startZNegative, startBottomMixedRegion));
}
else
{
IEnumerator enumerator;
enumerator = CubemapToEquirectangularCpuPositiveY(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
0, 0, panoramaWidth, endYPositive);
while (enumerator.MoveNext()) { }
enumerator = CubemapToEquirectangularCpuNegativeY(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
0, startYNegative, panoramaWidth, panoramaHeight);
while (enumerator.MoveNext()) { }
enumerator = CubemapToEquirectangularCpuPositiveX(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
startXPositive, endTopMixedRegion, endXPositive, startBottomMixedRegion);
while (enumerator.MoveNext()) { }
enumerator = CubemapToEquirectangularCpuNegativeX(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
startXNegative, endTopMixedRegion, endXNegative, startBottomMixedRegion);
while (enumerator.MoveNext()) { }
enumerator = CubemapToEquirectangularCpuPositiveZ(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
startZPositive, endTopMixedRegion, endZPositive, startBottomMixedRegion);
while (enumerator.MoveNext()) { }
// Do in two pieces since z negative wraps/loops around
enumerator = CubemapToEquirectangularCpuNegativeZ(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
startZNegative, endTopMixedRegion, panoramaWidth, startBottomMixedRegion);
while (enumerator.MoveNext()) { }
enumerator = CubemapToEquirectangularCpuNegativeZ(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, numPixelsAveraged,
0, endTopMixedRegion, endZNegative, startBottomMixedRegion);
while (enumerator.MoveNext()) { }
// Handle all remaining image areas with the general case
enumerator = CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
0, endYPositive, panoramaWidth, endTopMixedRegion);
while (enumerator.MoveNext()) { }
enumerator = CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
0, startBottomMixedRegion, panoramaWidth, startYNegative);
while (enumerator.MoveNext()) { }
// If width is not multiple of 8, due to rounding, there may be one-column strips where the X/Z textures mix together
if (endZNegative < startXNegative)
{
enumerator = CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
endZNegative, endTopMixedRegion, startXNegative, startBottomMixedRegion);
while (enumerator.MoveNext()) { }
}
if (endXNegative < startZPositive)
{
enumerator = CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
endXNegative, endTopMixedRegion, startZPositive, startBottomMixedRegion);
while (enumerator.MoveNext()) { }
}
if (endZPositive < startXPositive)
{
enumerator = CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
endZPositive, endTopMixedRegion, startXPositive, startBottomMixedRegion);
while (enumerator.MoveNext()) { }
}
if (endXPositive < startZNegative)
{
enumerator = CubemapToEquirectangularCpuGeneralCase(cameraPixels, pixelValues, stride, panoramaWidth, panoramaHeight, ssaaFactor, startTime, processingTimePerFrame, maxWidth, maxHeight, numPixelsAveraged,
endXPositive, endTopMixedRegion, startZNegative, startBottomMixedRegion);
while (enumerator.MoveNext()) { }
}
}
yield return null;
}