#pragma kernel CubeMapToEquirectangular #pragma kernel CubeMapToEquirectangularPositiveY #pragma kernel CubeMapToEquirectangularNegativeY RWStructuredBuffer result; StructuredBuffer cameraPixels; SamplerState MyLinearClampSampler; uint equirectangularWidth; uint equirectangularHeight; uint ssaaFactor; uint cameraWidth; uint cameraHeight; uint startY; uint sliceHeight; uint cameraPixelsSentinelIdx; uint sentinelIdx; [numthreads(32,32,1)] // Must match threadsX, threadsY in CapturePanorama.cs void CubeMapToEquirectangular (uint3 dtid : SV_DispatchThreadID) { if (dtid.x >= equirectangularWidth || dtid.y >= sliceHeight) // In case width/height not multiple of numthreads return; if (dtid.x == 0u && dtid.y == 0u) result[sentinelIdx] = cameraPixels[cameraPixelsSentinelIdx]; // Sentinel value - set correctly only if set correctly in input buffer // Must match enum UnityEngine.CubemapFace static const uint PositiveX = 0u; static const uint NegativeX = 1u; static const uint PositiveY = 2u; static const uint NegativeY = 3u; static const uint PositiveZ = 4u; static const uint NegativeZ = 5u; static const float pi = 3.14159265f; float4 totalColor = float4(0.0f, 0.0f, 0.0f, 0.0f); uint2 pos = uint2(dtid.x, dtid.y + startY); uint2 loopStart = pos * ssaaFactor; uint2 loopEnd = loopStart + uint2(ssaaFactor, ssaaFactor); for (uint y = loopStart.y; y < loopEnd.y; y++) { for (uint x = loopStart.x; x < loopEnd.x; x++) { float xcoord = (float)x / (equirectangularWidth * ssaaFactor); float ycoord = (float)y / (equirectangularHeight * ssaaFactor); float latitude = (ycoord - 0.5f) * pi; float longitude = (xcoord * 2.0f - 1.0f) * pi; float cosLat = cos(latitude); float equirectRayDirectionX = cosLat * sin (longitude); float equirectRayDirectionY = sin (latitude); float equirectRayDirectionZ = cosLat * cos (longitude); float distance; float u, v; uint cameraNum; distance = 1.0f / equirectRayDirectionY; u = equirectRayDirectionX * distance; v = equirectRayDirectionZ * distance; if (u * u <= 1.0f && v * v <= 1.0f) { if (equirectRayDirectionY > 0.0f) { cameraNum = PositiveY; } else { u = -u; cameraNum = NegativeY; } } else { distance = 1.0f / equirectRayDirectionX; u = -equirectRayDirectionZ * distance; v = equirectRayDirectionY * distance; if (u * u <= 1.0f && v * v <= 1.0f) { if (equirectRayDirectionX > 0.0f) { v = -v; cameraNum = PositiveX; } else { cameraNum = NegativeX; } } else { distance = 1.0f / equirectRayDirectionZ; u = equirectRayDirectionX * distance; v = equirectRayDirectionY * distance; if (u * u <= 1.0f && v * v <= 1.0f) { if (equirectRayDirectionZ > 0.0f) { v = -v; cameraNum = PositiveZ; } else { cameraNum = NegativeZ; } } } } u = (u + 1.0f) * 0.5f; v = (v + 1.0f) * 0.5f; // GetCameraPixelBilinear(cameraPixels, cameraNum, u, v); u *= cameraWidth; v *= cameraHeight; uint left = min(cameraWidth - 1u, (uint)floor(u)); // Modified to add check uint right = min(cameraWidth - 1u, left + 1u); uint top = min(cameraHeight - 1u, (uint)floor(v)); // Modified to add check uint bottom = min(cameraHeight - 1u, top + 1u); float uFrac = frac(u); float vFrac = frac(v); uint baseIdx = cameraNum * cameraWidth * cameraHeight; uint topRow = baseIdx + top * cameraWidth; uint bottomRow = baseIdx + bottom * cameraWidth; uint topLeft = cameraPixels[topRow + left ]; uint topRight = cameraPixels[topRow + right]; uint bottomLeft = cameraPixels[bottomRow + left ]; uint bottomRight = cameraPixels[bottomRow + right]; float r = lerp(lerp( topLeft >> 16u , bottomLeft >> 16u , vFrac), lerp( topRight >> 16u , bottomRight >> 16u , vFrac), uFrac); float g = lerp(lerp((topLeft >> 8u) & 0xFFu, (bottomLeft >> 8u) & 0xFFu, vFrac), lerp((topRight >> 8u) & 0xFFu, (bottomRight >> 8u) & 0xFFu, vFrac), uFrac); float b = lerp(lerp( topLeft & 0xFFu, bottomLeft & 0xFFu, vFrac), lerp( topRight & 0xFFu, bottomRight & 0xFFu, vFrac), uFrac); totalColor += float4(r, g, b, 255.0f); } } totalColor /= ssaaFactor * ssaaFactor; result[(dtid.y * equirectangularWidth) + dtid.x] = ((uint)totalColor.r << 16u) | ((uint)totalColor.g << 8u) | (uint)totalColor.b; } [numthreads(32,32,1)] // Must match threadsX, threadsY in CapturePanorama.cs void CubeMapToEquirectangularPositiveY (uint3 dtid : SV_DispatchThreadID) { if (dtid.x >= equirectangularWidth || dtid.y >= sliceHeight) // In case width/height not multiple of numthreads return; if (dtid.x == 0u && dtid.y == 0u) result[sentinelIdx] = cameraPixels[cameraPixelsSentinelIdx]; // Sentinel value - set correctly only if set correctly in input buffer static const uint cameraNum = 2; /* PositiveY */ static const float pi = 3.14159265f; float4 totalColor = float4(0.0f, 0.0f, 0.0f, 0.0f); uint2 pos = uint2(dtid.x, dtid.y + startY); uint2 loopStart = pos * ssaaFactor; uint2 loopEnd = loopStart + uint2(ssaaFactor, ssaaFactor); for (uint y = loopStart.y; y < loopEnd.y; y++) { for (uint x = loopStart.x; x < loopEnd.x; x++) { float xcoord = (float)x / (equirectangularWidth * ssaaFactor); float ycoord = (float)y / (equirectangularHeight * ssaaFactor); float latitude = (ycoord - 0.5f) * pi; float longitude = (xcoord * 2.0f - 1.0f) * pi; float cosLat = cos(latitude); float equirectRayDirectionX = cosLat * sin (longitude); float equirectRayDirectionY = sin (latitude); float equirectRayDirectionZ = cosLat * cos (longitude); float distance = 1.0f / equirectRayDirectionY; float u = equirectRayDirectionX * distance, v = equirectRayDirectionZ * distance; u = (u + 1.0f) * 0.5f; v = (v + 1.0f) * 0.5f; // GetCameraPixelBilinear(cameraPixels, cameraNum, u, v); u *= cameraWidth; v *= cameraHeight; uint left = (uint)floor(u); uint right = min(cameraWidth - 1u, left + 1u); uint top = (uint)floor(v); uint bottom = min(cameraHeight - 1u, top + 1u); float uFrac = frac(u); float vFrac = frac(v); uint baseIdx = cameraNum * cameraWidth * cameraHeight; uint topRow = baseIdx + top * cameraWidth; uint bottomRow = baseIdx + bottom * cameraWidth; uint topLeft = cameraPixels[topRow + left ]; uint topRight = cameraPixels[topRow + right]; uint bottomLeft = cameraPixels[bottomRow + left ]; uint bottomRight = cameraPixels[bottomRow + right]; float r = lerp(lerp( topLeft >> 16u , bottomLeft >> 16u , vFrac), lerp( topRight >> 16u , bottomRight >> 16u , vFrac), uFrac); float g = lerp(lerp((topLeft >> 8u) & 0xFFu, (bottomLeft >> 8u) & 0xFFu, vFrac), lerp((topRight >> 8u) & 0xFFu, (bottomRight >> 8u) & 0xFFu, vFrac), uFrac); float b = lerp(lerp( topLeft & 0xFFu, bottomLeft & 0xFFu, vFrac), lerp( topRight & 0xFFu, bottomRight & 0xFFu, vFrac), uFrac); totalColor += float4(r, g, b, 255.0f); } } totalColor /= ssaaFactor * ssaaFactor; result[(dtid.y * equirectangularWidth) + dtid.x] = ((uint)totalColor.r << 16u) | ((uint)totalColor.g << 8u) | (uint)totalColor.b; } [numthreads(32,32,1)] // Must match threadsX, threadsY in CapturePanorama.cs void CubeMapToEquirectangularNegativeY (uint3 dtid : SV_DispatchThreadID) { if (dtid.x >= equirectangularWidth || dtid.y >= sliceHeight) // In case width/height not multiple of numthreads return; if (dtid.x == 0u && dtid.y == 0u) result[sentinelIdx] = cameraPixels[cameraPixelsSentinelIdx]; // Sentinel value - set correctly only if set correctly in input buffer static const uint cameraNum = 3; /* NegativeY */ static const float pi = 3.14159265f; float4 totalColor = float4(0.0f, 0.0f, 0.0f, 0.0f); uint2 pos = uint2(dtid.x, dtid.y + startY); uint2 loopStart = pos * ssaaFactor; uint2 loopEnd = loopStart + uint2(ssaaFactor, ssaaFactor); for (uint y = loopStart.y; y < loopEnd.y; y++) { for (uint x = loopStart.x; x < loopEnd.x; x++) { float xcoord = (float)x / (equirectangularWidth * ssaaFactor); float ycoord = (float)y / (equirectangularHeight * ssaaFactor); float latitude = (ycoord - 0.5f) * pi; float longitude = (xcoord * 2.0f - 1.0f) * pi; float cosLat = cos(latitude); float equirectRayDirectionX = cosLat * sin (longitude); float equirectRayDirectionY = sin (latitude); float equirectRayDirectionZ = cosLat * cos (longitude); float distance = 1.0f / equirectRayDirectionY; float u = equirectRayDirectionX * distance, v = equirectRayDirectionZ * distance; u = -u; u = (u + 1.0f) * 0.5f; v = (v + 1.0f) * 0.5f; // GetCameraPixelBilinear(cameraPixels, cameraNum, u, v); u *= cameraWidth; v *= cameraHeight; uint left = (uint)floor(u); uint right = min(cameraWidth - 1u, left + 1u); uint top = (uint)floor(v); uint bottom = min(cameraHeight - 1u, top + 1u); float uFrac = frac(u); float vFrac = frac(v); uint baseIdx = cameraNum * cameraWidth * cameraHeight; uint topRow = baseIdx + top * cameraWidth; uint bottomRow = baseIdx + bottom * cameraWidth; uint topLeft = cameraPixels[topRow + left ]; uint topRight = cameraPixels[topRow + right]; uint bottomLeft = cameraPixels[bottomRow + left ]; uint bottomRight = cameraPixels[bottomRow + right]; float r = lerp(lerp( topLeft >> 16u , bottomLeft >> 16u , vFrac), lerp( topRight >> 16u , bottomRight >> 16u , vFrac), uFrac); float g = lerp(lerp((topLeft >> 8u) & 0xFFu, (bottomLeft >> 8u) & 0xFFu, vFrac), lerp((topRight >> 8u) & 0xFFu, (bottomRight >> 8u) & 0xFFu, vFrac), uFrac); float b = lerp(lerp( topLeft & 0xFFu, bottomLeft & 0xFFu, vFrac), lerp( topRight & 0xFFu, bottomRight & 0xFFu, vFrac), uFrac); totalColor += float4(r, g, b, 255.0f); } } totalColor /= ssaaFactor * ssaaFactor; result[(dtid.y * equirectangularWidth) + dtid.x] = ((uint)totalColor.r << 16u) | ((uint)totalColor.g << 8u) | (uint)totalColor.b; }