From cb0ed4f6ea70a772c596892fc45878364d439835 Mon Sep 17 00:00:00 2001 From: ZhiQing-R <119010253@link.cuhk.edu.cn> Date: Fri, 6 Dec 2024 13:52:34 -0500 Subject: [PATCH] fix gbuffer normal & improve stochastic samping --- shaders/gbuffer.vert | 4 +- shaders/lightPass.frag | 2 +- shaders/reflection_generation.comp | 170 +++++++++++++-------------- shaders/shaderUtils_surfel_cell.glsl | 42 ++++--- shaders/temporal_spatial_pass.comp | 12 +- src/gbuffer_pass.cpp | 1 + src/gbuffer_pass.h | 1 + src/main.cpp | 4 +- 8 files changed, 121 insertions(+), 115 deletions(-) diff --git a/shaders/gbuffer.vert b/shaders/gbuffer.vert index c6b23ad..9fe2231 100644 --- a/shaders/gbuffer.vert +++ b/shaders/gbuffer.vert @@ -14,6 +14,7 @@ layout(set = 0, binding = 0, scalar) uniform _SceneCamera { SceneCamera sceneCa layout(push_constant) uniform Instance { mat4 model; + mat4 modelInvTrp; uint id; } instanceData; @@ -26,7 +27,8 @@ layout(location = 1) out vec3 normal; void main() { instanceID = instanceData.id; - normal = decompress_unit_vec(in_normal); + vec3 normalL = decompress_unit_vec(in_normal); + normal = mat3(instanceData.modelInvTrp) * normalL; vec4 wpos = instanceData.model * vec4(in_pos, 1); wpos /= wpos.w; diff --git a/shaders/lightPass.frag b/shaders/lightPass.frag index c7d6013..9d0bf76 100644 --- a/shaders/lightPass.frag +++ b/shaders/lightPass.frag @@ -151,7 +151,7 @@ void main() vec3 indirectLight = texture(indirectLightMap, uv).rgb; //vec3 diffuseAlbedo = state.mat.albedo * (M_1_OVER_PI * (1.0 - state.mat.metallic)); vec3 diffuseAlbedo = state.mat.albedo * (1.0 - F_SchlickRoughness(state.mat.f0, max(0.0, dot(-camRay.direction, state.normal)), state.mat.roughness) - * (1.0 - state.mat.metallic)); + * (1.0 - state.mat.metallic)) * 0.5; vec3 directLighting = hit ? vec3(0) : directLight.radiance; vec3 reflectionColor = texelFetch(filteredReflectionColor, ivec2(gl_FragCoord.xy), 0).rgb; diff --git a/shaders/reflection_generation.comp b/shaders/reflection_generation.comp index 2bac9c9..10e2b91 100644 --- a/shaders/reflection_generation.comp +++ b/shaders/reflection_generation.comp @@ -141,109 +141,101 @@ void main() vec2 stocasticUV = uv + vec2(rand(randSeed) - 0.5, rand(randSeed) - 0.5) / vec2(imageRes); prd.seed = tea(rtxState.size.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, rtxState.totalFrames * rtxState.maxSamples); - vec2 d = stocasticUV * 2.0 - 1.0; - vec4 origin = sceneCamera.viewInverse * vec4(0, 0, 0, 1); - vec4 target = sceneCamera.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = sceneCamera.viewInverse * vec4(normalize(target.xyz), 0); - Ray ray = Ray(origin.xyz, direction.xyz); - - float firstDepth = -1.f; - BsdfSampleRec reflectBsdfSampleRec; - float weight; - vec3 radiance = surfelRefelctionTrace(ray, 8, firstDepth, reflectBsdfSampleRec, weight); - if (firstDepth == INFINITY) - { - imageStore(reflectionColor, imageCoords, vec4(0.0)); - imageStore(reflectionDirection, imageCoords, vec4(0.0)); - return; - } - float lum = dot(radiance, vec3(0.212671f, 0.715160f, 0.072169f)); - if(lum > rtxState.fireflyClampThreshold) - { - radiance *= rtxState.fireflyClampThreshold / lum; - } - float invPdf = 1.f / reflectBsdfSampleRec.pdf; - //radiance *= invPdf * reflectBsdfSampleRec.f * max(0.0, dot(reflectBsdfSampleRec.L, state.normal)); - - imageStore(reflectionColor, imageCoords, vec4(radiance, weight)); - imageStore(reflectionDirection, imageCoords, vec4(reflectBsdfSampleRec.L, invPdf)); - - - -// ivec2 gbufferCoords = ivec2(imageCoords * 2); -// uint primObjID = texelFetch(gbufferPrim, gbufferCoords, 0).r; + // path trace solution +// vec2 d = stocasticUV * 2.0 - 1.0; // -// // reconstruct world position from depth -// float depth = texelFetch(gbufferDepth, gbufferCoords, 0).r; -// if (depth == 1.0) -// { -// imageStore(reflectionColor, imageCoords, vec4(0.0)); -// imageStore(reflectionDirection, imageCoords, vec4(0.0)); -// return; -// } -// -// vec3 worldPos = WorldPosFromDepth(stocasticUV, depth); -// -// uint nodeID = primObjID >> 23; -// uint instanceID = sceneNodes[nodeID].primMesh; -// mat4 worldMat = sceneNodes[nodeID].worldMatrix; -// uint primID = primObjID & 0x007FFFFF; -// InstanceData pinfo = geoInfo[instanceID]; -// -// // Primitive buffer addresses -// Indices indices = Indices(pinfo.indexAddress); -// Vertices vertices = Vertices(pinfo.vertexAddress); -// -// // Indices of this triangle primitive. -// uvec3 tri = indices.i[primID]; -// -// // All vertex attributes of the triangle. -// VertexAttributes attr0 = vertices.v[tri.x]; -// VertexAttributes attr1 = vertices.v[tri.y]; -// VertexAttributes attr2 = vertices.v[tri.z]; -// -// // camera ray -// vec3 camPos = (sceneCamera.viewInverse * vec4(0, 0, 0, 1)).xyz; -// Ray camRay = Ray(camPos, normalize(worldPos - camPos)); +// vec4 origin = sceneCamera.viewInverse * vec4(0, 0, 0, 1); +// vec4 target = sceneCamera.projInverse * vec4(d.x, d.y, 1, 1); +// vec4 direction = sceneCamera.viewInverse * vec4(normalize(target.xyz), 0); +// Ray ray = Ray(origin.xyz, direction.xyz); // -// // decompress normal -// vec3 normal = decompress_unit_vec(texelFetch(gbufferNormal, gbufferCoords, 0).r); +// float firstDepth = -1.f; +// BsdfSampleRec reflectBsdfSampleRec; +// float weight; // -// // reflected direction and brdf -// State state = GetState(primObjID, normal, depth, uv); -// // ignore rough surface -// if (state.mat.roughness > 0.95) -// { -// imageStore(reflectionColor, imageCoords, vec4(0.0)); +// vec3 radiance = surfelRefelctionTrace(ray, 2, firstDepth, reflectBsdfSampleRec, weight); +// if (firstDepth == INFINITY) +// { +// imageStore(reflectionColor, imageCoords, vec4(0.0)); // imageStore(reflectionDirection, imageCoords, vec4(0.0)); // return; // } -// BsdfSampleRec reflectBsdfSampleRec; -// float weight = 0.0; -// uint maxItr = 0; -// -// while(weight < 1e-5 && maxItr < 3) +// float lum = dot(radiance, vec3(0.212671f, 0.715160f, 0.072169f)); +// if(lum > rtxState.fireflyClampThreshold) // { -// reflectBsdfSampleRec.f = SpecSample(state, -camRay.direction, state.ffnormal, reflectBsdfSampleRec.L, reflectBsdfSampleRec.pdf, prd.seed); -// // calculate brdf weight -// weight = brdfWeight(-camRay.direction, state.ffnormal, reflectBsdfSampleRec.L, state.mat.roughness); -// reflectBsdfSampleRec.pdf = max(1e-4, reflectBsdfSampleRec.pdf); -// maxItr++; +// radiance *= rtxState.fireflyClampThreshold / lum; // } -// -// // reflection color -// Ray reflectedRay = Ray(worldPos + 1e-2 * normal, normalize(reflectBsdfSampleRec.L)); - - -// float firstDepth = -1.f; -// vec3 radiance = surfelRefelctionTrace(reflectedRay, 1, firstDepth); // float invPdf = 1.f / reflectBsdfSampleRec.pdf; -// radiance *= invPdf * reflectBsdfSampleRec.f * max(0.0, dot(reflectBsdfSampleRec.L, state.normal)); +// //radiance *= invPdf * reflectBsdfSampleRec.f * max(0.0, dot(reflectBsdfSampleRec.L, state.normal)); // // imageStore(reflectionColor, imageCoords, vec4(radiance, weight)); // imageStore(reflectionDirection, imageCoords, vec4(reflectBsdfSampleRec.L, invPdf)); + + + ivec2 gbufferCoords = ivec2(imageCoords * 2); + uint primObjID = texelFetch(gbufferPrim, gbufferCoords, 0).r; + + // reconstruct world position from depth + float depth = texelFetch(gbufferDepth, gbufferCoords, 0).r; + if (depth == 1.0) + { + imageStore(reflectionColor, imageCoords, vec4(0.0)); + imageStore(reflectionDirection, imageCoords, vec4(0.0)); + return; + } + + vec3 worldPos = WorldPosFromDepth(stocasticUV, depth); + + uint nodeID = primObjID >> 23; + uint instanceID = sceneNodes[nodeID].primMesh; + mat4 worldMat = sceneNodes[nodeID].worldMatrix; + uint primID = primObjID & 0x007FFFFF; + InstanceData pinfo = geoInfo[instanceID]; + + // camera ray + vec3 camPos = (sceneCamera.viewInverse * vec4(0, 0, 0, 1)).xyz; + Ray camRay = Ray(camPos, normalize(worldPos - camPos)); + + // decompress normal + vec3 normal = decompress_unit_vec(texelFetch(gbufferNormal, gbufferCoords, 0).r); + + // reflected direction and brdf + State state = GetState(primObjID, normal, depth, uv); + // ignore rough surface + if (state.mat.roughness > 0.95) + { + imageStore(reflectionColor, imageCoords, vec4(0.0)); + imageStore(reflectionDirection, imageCoords, vec4(0.0)); + return; + } + BsdfSampleRec reflectBsdfSampleRec; + float weight = 0.0; + uint maxItr = 0; + + while(weight < 1e-5 && maxItr < 3) + { + reflectBsdfSampleRec.f = SpecSample(state, -camRay.direction, state.ffnormal, reflectBsdfSampleRec.L, reflectBsdfSampleRec.pdf, prd.seed); + // calculate brdf weight + weight = brdfWeight(-camRay.direction, state.ffnormal, reflectBsdfSampleRec.L, state.mat.roughness); + reflectBsdfSampleRec.pdf = max(1e-4, reflectBsdfSampleRec.pdf); + maxItr++; + } + + // reflection color + Ray reflectedRay = Ray(worldPos + 1e-2 * normal, normalize(reflectBsdfSampleRec.L)); + + float firstDepth = -1.f; + BsdfSampleRec tmp; + vec3 radiance = surfelRefelctionTrace(reflectedRay, 1, firstDepth, tmp, weight); + float invPdf = 1.f / reflectBsdfSampleRec.pdf; + radiance *= invPdf * reflectBsdfSampleRec.f * max(0.0, dot(reflectBsdfSampleRec.L, state.ffnormal)); + + imageStore(reflectionColor, imageCoords, vec4(radiance, weight)); + imageStore(reflectionDirection, imageCoords, vec4(vec3(state.matID + 1), invPdf)); + + //ClosestHit(reflectedRay); diff --git a/shaders/shaderUtils_surfel_cell.glsl b/shaders/shaderUtils_surfel_cell.glsl index c752d5a..d2cf8dd 100644 --- a/shaders/shaderUtils_surfel_cell.glsl +++ b/shaders/shaderUtils_surfel_cell.glsl @@ -159,10 +159,17 @@ bool finalizePathWithSurfel(vec3 worldPos, vec3 worldNor, inout vec4 irradiance) const uint searchRange = min(16, cellInfo.surfelCount); uint searchCnt = 0; - for (uint i = 0; i < cellInfo.surfelCount; i++) + uint randSeed = initRandom(uvec2(rtxState.totalFrames, floatBitsToUint(worldPos.x)), + uvec2(floatBitsToUint(worldPos.y), floatBitsToUint(worldPos.z)), rtxState.frame); + + uint targetCnt = min(64, cellInfo.surfelCount); + float surfelCntF = float(cellInfo.surfelCount); + + for (uint i = 0; i < targetCnt; i++) { - if (searchCnt == searchRange) break; - uint surfelIndex = cellToSurfel[cellOffset + i]; + uint currIndex = uint(rand(randSeed) * surfelCntF); + + uint surfelIndex = cellToSurfel[cellOffset + currIndex]; Surfel surfel = surfelBuffer[surfelIndex]; vec3 neiNor = decompress_unit_vec(surfel.normal); bool isSleeping = (surfelRecycleInfo[surfelIndex].status & 0x0001) != 0; @@ -208,7 +215,6 @@ bool finalizePathWithSurfel(vec3 worldPos, vec3 worldNor, inout vec4 irradiance) contribution *= pow(1.f - dist / surfel.radius, 2.0); irradiance += vec4(surfel.radiance, 1.f) * contribution; } - searchCnt++; surfelRecycleInfo[surfelIndex].status |= 0x0004u; } @@ -219,9 +225,7 @@ bool finalizePathWithSurfel(vec3 worldPos, vec3 worldNor, inout vec4 irradiance) { irradiance /= irradiance.w; } - - //uint randSeed = initRandom(uvec2(rtxState.totalFrames, floatBitsToUint(worldPos.x)), - // uvec2(floatBitsToUint(worldPos.y), floatBitsToUint(worldPos.z)), rtxState.frame); + // // spawn sleeping surfel if coverage is low. //if (surfelCounter.aliveSurfelCnt < kMaxSurfelCount && @@ -582,18 +586,18 @@ vec3 surfelRefelctionTrace(Ray r, int maxDepth, inout float firstDepth, inout Bs } // use surfel indirect when the path reach max depth - //if (depth == maxDepth && valid) - // { - // vec4 irradiance = vec4(0.0); - // bool rst = finalizePathWithSurfel(sstate.position, sstate.normal, irradiance); - // //bool rst = false; - // if (rst) - // { - // // apply diffuse ratio - // irradiance.rgb *= diffuseRatio; - // radiance += irradiance.xyz * throughput; - // } - // } + if (depth == maxDepth && valid) + { + vec4 irradiance = vec4(0.0); + bool rst = finalizePathWithSurfel(sstate.position, sstate.normal, irradiance); + //bool rst = false; + if (rst) + { + // apply diffuse ratio + irradiance.rgb *= diffuseRatio; + radiance += irradiance.xyz * throughput; + } + } return radiance; diff --git a/shaders/temporal_spatial_pass.comp b/shaders/temporal_spatial_pass.comp index 15c3562..3fe955f 100644 --- a/shaders/temporal_spatial_pass.comp +++ b/shaders/temporal_spatial_pass.comp @@ -138,9 +138,10 @@ void main() vec4 centerDirection = imageLoad(reflectionDirection, halfImageCoords); if (centerDirection == vec4(0.0)) { - //imageStore(filteredReflectionColor, imageCoords, vec4(0.0)); + imageStore(filteredReflectionColor, imageCoords, vec4(0.0)); return; } + float matID = centerDirection.x; //vec4 centerBrdf = imageLoad(reflectionPointBrdf, halfImageCoords); @@ -151,7 +152,7 @@ void main() result += centerContrib; weightSum += centerWeight; - uint quadID = (imageCoords.y & 0x1) << 1 + (imageCoords.x & 0x1); + uint quadID = (imageCoords.x & 0x1) << 1 + (imageCoords.y & 0x1); float variance = 0.0; for (int i = 0; i < 16; ++i) @@ -164,7 +165,12 @@ void main() continue; float brdfWeight = neighborColor.a; - float pdfInv = max(imageLoad(reflectionDirection, neighborCoords).a, 1e-3); + vec4 neiDir = imageLoad(reflectionDirection, neighborCoords); + float neiMatID = neiDir.x; + if (neiMatID != matID) + continue; + + float pdfInv = max(neiDir.a, 1e-3); // Combine BRDF weight with distance weight float weight = max(brdfWeight * pdfInv, 0.0); diff --git a/src/gbuffer_pass.cpp b/src/gbuffer_pass.cpp index acd6640..7ba396a 100644 --- a/src/gbuffer_pass.cpp +++ b/src/gbuffer_pass.cpp @@ -116,6 +116,7 @@ void GbufferPass::run(const VkCommandBuffer& cmdBuf, const VkExtent2D& size, nvv instanceData.id = nodeID++; uint32_t primID = node.primMesh; instanceData.model = node.worldMatrix; + instanceData.modelInvTrp = glm::mat4(glm::inverse(glm::transpose(glm::mat3(instanceData.model)))); // Sending the push constant information vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(InstanceData), &instanceData); diff --git a/src/gbuffer_pass.h b/src/gbuffer_pass.h index 58c131e..17e10b9 100644 --- a/src/gbuffer_pass.h +++ b/src/gbuffer_pass.h @@ -14,6 +14,7 @@ class GbufferPass : Renderer struct InstanceData { glm::mat4 model; + glm::mat4 modelInvTrp; uint32_t id; }; diff --git a/src/main.cpp b/src/main.cpp index 2530188..c3ef0ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -64,8 +64,8 @@ int main(int argc, char** argv) InputParser parser(argc, argv); //std::string sceneFile = parser.getString("-f", "Sponza/Sponza.gltf"); //std::string sceneFile = parser.getString("-f", "Street/scene.gltf"); - //std::string sceneFile = parser.getString("-f", "Hospital/scene.gltf"); - std::string sceneFile = parser.getString("-f", "station/station.gltf"); + std::string sceneFile = parser.getString("-f", "apocal/apocal.gltf"); + //std::string sceneFile = parser.getString("-f", "station/station.gltf"); std::string hdrFilename = parser.getString("-e", "std_env.hdr"); // Setup GLFW window