|
|
@@ -13,7 +13,7 @@
|
|
|
#include <shaders/Pack.glsl>
|
|
|
#include <shaders/LightFunctions.glsl>
|
|
|
|
|
|
-layout(local_size_x = 6, local_size_y = 1, local_size_z = 1) in;
|
|
|
+layout(local_size_x = INPUT_TEXTURES_HEIGHT, local_size_y = INPUT_TEXTURES_HEIGHT, local_size_z = 1) in;
|
|
|
|
|
|
layout(set = 0, binding = 0) uniform sampler u_nearestAnyClampSampler;
|
|
|
layout(set = 0, binding = 1) uniform texture2D u_lightShadingTex;
|
|
|
@@ -22,96 +22,141 @@ layout(set = 0, binding = 3) uniform texture2D u_gbufferTex1;
|
|
|
layout(set = 0, binding = 4) uniform texture2D u_gbufferTex2;
|
|
|
layout(set = 0, binding = 5) uniform writeonly image3D u_irradianceVolumes[6];
|
|
|
|
|
|
+// This is a temporary buffer used instead of shared memory because it's too large
|
|
|
+layout(set = 0, binding = 6) buffer ssbo_
|
|
|
+{
|
|
|
+ Vec3 u_integrationResults[6][INPUT_TEXTURES_HEIGHT * INPUT_TEXTURES_HEIGHT];
|
|
|
+};
|
|
|
+
|
|
|
layout(push_constant, std430) uniform pc_
|
|
|
{
|
|
|
IVec3 u_volumeTexel;
|
|
|
I32 u_padding;
|
|
|
};
|
|
|
|
|
|
-shared Vec3 s_diceColors[6];
|
|
|
+shared Vec3 s_diceIrradiance[6];
|
|
|
|
|
|
void main()
|
|
|
{
|
|
|
const F32 INPUT_TEXTURES_HEIGHT_F = F32(INPUT_TEXTURES_HEIGHT);
|
|
|
- const U32 diceFace = gl_LocalInvocationID.x;
|
|
|
+ const Vec2 INPUT_TEXTURES_SIZE = Vec2(INPUT_TEXTURES_HEIGHT * 6u, INPUT_TEXTURES_HEIGHT);
|
|
|
|
|
|
- // Get the r coordinate of the current direction of the dice
|
|
|
- const Vec3 ri = getCubemapDirection(Vec2(0.0), diceFace);
|
|
|
+ // Compute the NDC used in cubeCoordSolidAngle
|
|
|
+ const Vec2 faceUv = (Vec2(gl_LocalInvocationID.x, gl_LocalInvocationID.y) + 0.5) / INPUT_TEXTURES_HEIGHT_F;
|
|
|
+ const Vec2 ndc = UV_TO_NDC(faceUv);
|
|
|
|
|
|
- // For all the faces and texels of the environment map integrate to compute the irradiance for a face
|
|
|
- Vec3 irradiance = Vec3(0.0);
|
|
|
- ANKI_LOOP for(U32 f = 0u; f < 6u; ++f)
|
|
|
+ // Initialize
|
|
|
+ ANKI_UNROLL for(U32 f = 0u; f < 6u; ++f)
|
|
|
{
|
|
|
- ANKI_LOOP for(U32 i = 0u; i < INPUT_TEXTURES_HEIGHT; ++i)
|
|
|
+ const Vec2 uv = (Vec2(gl_LocalInvocationID.x + INPUT_TEXTURES_HEIGHT_F * f, gl_LocalInvocationID.y) + 0.5)
|
|
|
+ / INPUT_TEXTURES_SIZE;
|
|
|
+
|
|
|
+ // Get the direction of the dice face
|
|
|
+ const Vec3 diceDir = getCubemapDirection(Vec2(0.0), f);
|
|
|
+
|
|
|
+ const Vec3 r = getCubemapDirection(ndc, f);
|
|
|
+
|
|
|
+ // Compute integral part
|
|
|
+ const F32 lambert = max(0.0, dot(r, diceDir));
|
|
|
+ const Vec3 lightShading = textureLod(u_lightShadingTex, u_nearestAnyClampSampler, uv, 0.0).rgb;
|
|
|
+ const Vec3 irradiance = lightShading * lambert * cubeCoordSolidAngle(ndc, INPUT_TEXTURES_HEIGHT_F);
|
|
|
+
|
|
|
+ // Store
|
|
|
+ u_integrationResults[f][gl_LocalInvocationID.y * INPUT_TEXTURES_HEIGHT + gl_LocalInvocationID.x] = irradiance;
|
|
|
+ }
|
|
|
+
|
|
|
+ memoryBarrierBuffer();
|
|
|
+ barrier();
|
|
|
+
|
|
|
+ // Reduce using prefix sum
|
|
|
+ ANKI_UNROLL for(U32 f = 0u; f < 6u; ++f)
|
|
|
+ {
|
|
|
+ const U32 WG_SIZE = INPUT_TEXTURES_HEIGHT * INPUT_TEXTURES_HEIGHT;
|
|
|
+ ANKI_LOOP for(U32 s = WG_SIZE / 2u; s > 0u; s >>= 1u)
|
|
|
{
|
|
|
- ANKI_LOOP for(U32 j = 0u; j < INPUT_TEXTURES_HEIGHT; ++j)
|
|
|
+ if(gl_LocalInvocationIndex < s)
|
|
|
{
|
|
|
- const Vec2 uv = Vec2(j + f * INPUT_TEXTURES_HEIGHT_F, i)
|
|
|
- / Vec2(6.0 * INPUT_TEXTURES_HEIGHT_F, INPUT_TEXTURES_HEIGHT_F);
|
|
|
- const Vec2 ndc = UV_TO_NDC(uv);
|
|
|
-
|
|
|
- const Vec3 r = getCubemapDirection(ndc, f);
|
|
|
- const F32 lambert = dot(r, ri);
|
|
|
-
|
|
|
- if(lambert > 0.0)
|
|
|
- {
|
|
|
- const Vec3 lightShading = textureLod(u_lightShadingTex, u_nearestAnyClampSampler, uv, 0.0).rgb;
|
|
|
- irradiance += lightShading * lambert * cubeCoordSolidAngle(ndc, INPUT_TEXTURES_HEIGHT_F);
|
|
|
- }
|
|
|
+ u_integrationResults[f][gl_LocalInvocationIndex] +=
|
|
|
+ u_integrationResults[f][gl_LocalInvocationIndex + s];
|
|
|
}
|
|
|
+
|
|
|
+ memoryBarrierBuffer();
|
|
|
+ barrier();
|
|
|
}
|
|
|
+
|
|
|
+ s_diceIrradiance[f] = u_integrationResults[f][0];
|
|
|
}
|
|
|
|
|
|
- s_diceColors[diceFace] = irradiance;
|
|
|
memoryBarrierShared();
|
|
|
barrier();
|
|
|
|
|
|
- // 2nd bounce
|
|
|
- irradiance = Vec3(0.0);
|
|
|
- ANKI_LOOP for(U32 f = 0u; f < 6u; ++f)
|
|
|
+ // Initialize again for the 2nd bounce
|
|
|
+ ANKI_UNROLL for(U32 f = 0u; f < 6u; ++f)
|
|
|
+ {
|
|
|
+ const Vec2 uv = (Vec2(gl_LocalInvocationID.x + INPUT_TEXTURES_HEIGHT_F * f, gl_LocalInvocationID.y) + 0.5)
|
|
|
+ / INPUT_TEXTURES_SIZE;
|
|
|
+
|
|
|
+ // Get the direction of the dice face
|
|
|
+ const Vec3 diceDir = getCubemapDirection(Vec2(0.0), f);
|
|
|
+
|
|
|
+ const Vec3 r = getCubemapDirection(ndc, f);
|
|
|
+
|
|
|
+ // Compute integral part
|
|
|
+ const F32 lambert = max(0.0, dot(r, diceDir));
|
|
|
+
|
|
|
+ // Read the gbuffer
|
|
|
+ GbufferInfo gbuffer;
|
|
|
+ readGBuffer(u_gbufferTex0, u_gbufferTex1, u_gbufferTex2, u_nearestAnyClampSampler, uv, 0.0, gbuffer);
|
|
|
+
|
|
|
+ // Sample irradiance
|
|
|
+ Vec3 firstBounceIrradiance = sampleAmbientDice(s_diceIrradiance[0],
|
|
|
+ s_diceIrradiance[1],
|
|
|
+ s_diceIrradiance[2],
|
|
|
+ s_diceIrradiance[3],
|
|
|
+ s_diceIrradiance[4],
|
|
|
+ s_diceIrradiance[5],
|
|
|
+ gbuffer.m_normal);
|
|
|
+ firstBounceIrradiance = gbuffer.m_diffuse * firstBounceIrradiance / PI;
|
|
|
+
|
|
|
+ // Compute 2nd bounce
|
|
|
+ const Vec3 lightShading = textureLod(u_lightShadingTex, u_nearestAnyClampSampler, uv, 0.0).rgb;
|
|
|
+ const Vec3 irradiance =
|
|
|
+ firstBounceIrradiance + lightShading * lambert * cubeCoordSolidAngle(ndc, INPUT_TEXTURES_HEIGHT_F);
|
|
|
+
|
|
|
+ // Store
|
|
|
+ u_integrationResults[f][gl_LocalInvocationID.y * INPUT_TEXTURES_HEIGHT + gl_LocalInvocationID.x] = irradiance;
|
|
|
+ }
|
|
|
+
|
|
|
+ memoryBarrierBuffer();
|
|
|
+ barrier();
|
|
|
+
|
|
|
+ // Reduce using prefix sum again
|
|
|
+ ANKI_UNROLL for(U32 f = 0u; f < 6u; ++f)
|
|
|
{
|
|
|
- ANKI_LOOP for(U32 i = 0u; i < INPUT_TEXTURES_HEIGHT; ++i)
|
|
|
+ const U32 WG_SIZE = INPUT_TEXTURES_HEIGHT * INPUT_TEXTURES_HEIGHT;
|
|
|
+ ANKI_LOOP for(U32 s = WG_SIZE / 2u; s > 0u; s >>= 1u)
|
|
|
{
|
|
|
- ANKI_LOOP for(U32 j = 0u; j < INPUT_TEXTURES_HEIGHT; ++j)
|
|
|
+ if(gl_LocalInvocationIndex < s)
|
|
|
{
|
|
|
- const Vec2 uv = Vec2(j + f * INPUT_TEXTURES_HEIGHT_F, i)
|
|
|
- / Vec2(6.0 * INPUT_TEXTURES_HEIGHT_F, INPUT_TEXTURES_HEIGHT_F);
|
|
|
- const Vec2 ndc = UV_TO_NDC(uv);
|
|
|
-
|
|
|
- const Vec3 r = getCubemapDirection(ndc, f);
|
|
|
- const F32 lambert = dot(r, ri);
|
|
|
-
|
|
|
- if(lambert > 0.0)
|
|
|
- {
|
|
|
- // Read the gbuffer
|
|
|
- GbufferInfo gbuffer;
|
|
|
- readGBuffer(
|
|
|
- u_gbufferTex0, u_gbufferTex1, u_gbufferTex2, u_nearestAnyClampSampler, uv, 0.0, gbuffer);
|
|
|
-
|
|
|
- // Sample irradiance
|
|
|
- Vec3 firstBounceIrradiance = sampleAmbientDice(s_diceColors[0],
|
|
|
- s_diceColors[1],
|
|
|
- s_diceColors[2],
|
|
|
- s_diceColors[3],
|
|
|
- s_diceColors[4],
|
|
|
- s_diceColors[5],
|
|
|
- gbuffer.m_normal);
|
|
|
- firstBounceIrradiance = gbuffer.m_diffuse * firstBounceIrradiance / PI;
|
|
|
-
|
|
|
- // Compute 2nd bounce
|
|
|
- const Vec3 lightShading = textureLod(u_lightShadingTex, u_nearestAnyClampSampler, uv, 0.0).rgb;
|
|
|
- irradiance += firstBounceIrradiance
|
|
|
- + lightShading * lambert * cubeCoordSolidAngle(ndc, INPUT_TEXTURES_HEIGHT_F);
|
|
|
- }
|
|
|
+ u_integrationResults[f][gl_LocalInvocationIndex] +=
|
|
|
+ u_integrationResults[f][gl_LocalInvocationIndex + s];
|
|
|
}
|
|
|
+
|
|
|
+ memoryBarrierBuffer();
|
|
|
+ barrier();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Pre-divide
|
|
|
- irradiance *= (1.0 / PI);
|
|
|
-
|
|
|
- // Store the result
|
|
|
- imageStore(u_irradianceVolumes[nonuniformEXT(diceFace)], u_volumeTexel, Vec4(irradiance, 0.0));
|
|
|
+ // Store the results
|
|
|
+ ANKI_BRANCH if(gl_LocalInvocationIndex == 0u)
|
|
|
+ {
|
|
|
+ ANKI_UNROLL for(U32 f = 0u; f < 6u; ++f)
|
|
|
+ {
|
|
|
+ Vec3 irradiance = u_integrationResults[f][0];
|
|
|
+ irradiance /= PI; // Pre-divide
|
|
|
+ imageStore(u_irradianceVolumes[f], u_volumeTexel, Vec4(irradiance, 0.0));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#pragma anki end
|