Files
falling_rooms/Assets/CapturePanorama/Compute Shaders/ConvertPanoramaShader.compute
2025-07-09 11:02:37 +02:00

276 lines
10 KiB
Plaintext

#pragma kernel CubeMapToEquirectangular
#pragma kernel CubeMapToEquirectangularPositiveY
#pragma kernel CubeMapToEquirectangularNegativeY
RWStructuredBuffer<uint> result;
StructuredBuffer<uint> 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;
}