diff --git a/src/lightmap/glsl_rchit_bounce.h b/src/lightmap/glsl_rchit_bounce.h index 28536a3..3ab7cfe 100644 --- a/src/lightmap/glsl_rchit_bounce.h +++ b/src/lightmap/glsl_rchit_bounce.h @@ -5,7 +5,9 @@ static const char* glsl_rchit_bounce = R"glsl( struct hitPayload { + vec3 hitPosition; float hitAttenuation; + int hitSurfaceIndex; }; struct SurfaceInfo @@ -25,9 +27,10 @@ layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; void main() { - // SurfaceInfo surface = surfaces[surfaceIndices[gl_PrimitiveID]]; - - payload.hitAttenuation = 0.0; + int surfaceIndex = surfaceIndices[gl_PrimitiveID]; + payload.hitPosition = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; + payload.hitSurfaceIndex = surfaceIndex; + payload.hitAttenuation = 1.0; } )glsl"; diff --git a/src/lightmap/glsl_rchit_light.h b/src/lightmap/glsl_rchit_light.h index add1c79..c8bde0a 100644 --- a/src/lightmap/glsl_rchit_light.h +++ b/src/lightmap/glsl_rchit_light.h @@ -5,7 +5,9 @@ static const char* glsl_rchit_light = R"glsl( struct hitPayload { + vec3 hitPosition; float hitAttenuation; + int hitSurfaceIndex; }; struct SurfaceInfo @@ -20,7 +22,7 @@ struct SurfaceInfo layout(location = 0) rayPayloadInEXT hitPayload payload; -layout(set = 0, binding = 5) buffer SurfaceIndexBuffer { int surfaceIndices[]; }; +layout(set = 0, binding = 5) buffer SurfaceIndexBuffer { uint surfaceIndices[]; }; layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; void main() diff --git a/src/lightmap/glsl_rchit_sun.h b/src/lightmap/glsl_rchit_sun.h index c43e80c..4f57ba5 100644 --- a/src/lightmap/glsl_rchit_sun.h +++ b/src/lightmap/glsl_rchit_sun.h @@ -5,7 +5,9 @@ static const char* glsl_rchit_sun = R"glsl( struct hitPayload { + vec3 hitPosition; float hitAttenuation; + int hitSurfaceIndex; }; struct SurfaceInfo diff --git a/src/lightmap/glsl_rgen_bounce.h b/src/lightmap/glsl_rgen_bounce.h index cf94309..c51aef7 100644 --- a/src/lightmap/glsl_rgen_bounce.h +++ b/src/lightmap/glsl_rgen_bounce.h @@ -5,30 +5,143 @@ static const char* glsl_rgen_bounce = R"glsl( struct hitPayload { + vec3 hitPosition; float hitAttenuation; + int hitSurfaceIndex; }; layout(location = 0) rayPayloadEXT hitPayload payload; layout(set = 0, binding = 0) uniform accelerationStructureEXT acc; -layout(set = 0, binding = 1, rgba32f) uniform image2D positions; -layout(set = 0, binding = 2, rgba32f) uniform image2D normals; +layout(set = 0, binding = 1, rgba32f) uniform image2D startpositions; +layout(set = 0, binding = 2, rgba32f) uniform image2D positions; layout(set = 0, binding = 3, rgba32f) uniform image2D outputs; layout(set = 0, binding = 4) uniform Uniforms { + uint SampleIndex; + uint SampleCount; + uint PassType; + uint Padding2; vec3 LightOrigin; - float PassType; + float Padding0; float LightRadius; float LightIntensity; float LightInnerAngleCos; float LightOuterAngleCos; - vec3 LightSpotDir; + vec3 LightDir; float SampleDistance; vec3 LightColor; - float Padding; + float Padding1; }; +struct SurfaceInfo +{ + vec3 Normal; + float EmissiveDistance; + vec3 EmissiveColor; + float EmissiveIntensity; + float Sky; + float Padding0, Padding1, Padding2; +}; + +layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; + +vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness); +vec2 Hammersley(uint i, uint N); +float RadicalInverse_VdC(uint bits); + +void main() +{ + ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy); + + vec4 data0; + if (PassType == 2) + data0 = imageLoad(positions, texelPos); + else + data0 = imageLoad(startpositions, texelPos); + + vec4 incoming = vec4(0.0, 0.0, 0.0, 1.0); + + int surfaceIndex = int(data0.w); + if (surfaceIndex >= 0) + { + SurfaceInfo surface = surfaces[surfaceIndex]; + + vec3 origin = data0.xyz; + vec3 normal = surface.Normal; + + if (PassType == 0) + { + incoming.rgb = surface.EmissiveColor * surface.EmissiveIntensity; + } + else + { + incoming = imageLoad(outputs, texelPos); + + if (PassType == 1) + incoming.w = 1.0f / float(SampleCount); + + vec2 Xi = Hammersley(SampleIndex, SampleCount); + vec3 H = ImportanceSampleGGX(Xi, normal, 1.0f); + vec3 L = normalize(H * (2.0f * dot(normal, H)) - normal); + + float NdotL = max(dot(normal, L), 0.0); + + const float p = 1 / (2 * 3.14159265359); + incoming.w *= NdotL / p; + + if (NdotL > 0.0f) + { + const float minDistance = 0.1; + + traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, origin, minDistance, L, 2000, 0); + if (payload.hitAttenuation == 1.0) + { + float hitDistance = distance(origin, payload.hitPosition); + surfaceIndex = payload.hitSurfaceIndex; + surface = surfaces[surfaceIndex]; + origin = payload.hitPosition; + + if (surface.EmissiveDistance > 0.0) + { + float attenuation = max(1.0 - (hitDistance / surface.EmissiveDistance), 0.0f); + incoming.rgb += surface.EmissiveColor * (surface.EmissiveIntensity * attenuation * incoming.w); + } + } + } + + incoming.w *= 0.25; // the amount of incoming light the surfaces emit + } + + data0.xyz = origin; + data0.w = float(surfaceIndex); + } + + imageStore(positions, texelPos, data0); + imageStore(outputs, texelPos, incoming); +} + +vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) +{ + float a = roughness * roughness; + + float phi = 2.0f * 3.14159265359 * Xi.x; + float cosTheta = sqrt((1.0f - Xi.y) / (1.0f + (a * a - 1.0f) * Xi.y)); + float sinTheta = sqrt(1.0f - cosTheta * cosTheta); + + // from spherical coordinates to cartesian coordinates + vec3 H = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); + + // from tangent-space vector to world-space sample vector + vec3 up = abs(N.z) < 0.999f ? vec3(0.0f, 0.0f, 1.0f) : vec3(1.0f, 0.0f, 0.0f); + vec3 tangent = normalize(cross(up, N)); + vec3 bitangent = cross(N, tangent); + + vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z; + return normalize(sampleVec); +} + float RadicalInverse_VdC(uint bits) { bits = (bits << 16u) | (bits >> 16u); @@ -44,67 +157,4 @@ vec2 Hammersley(uint i, uint N) return vec2(float(i) / float(N), RadicalInverse_VdC(i)); } -void main() -{ - ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy); - vec4 data0 = imageLoad(positions, texelPos); - vec4 data1 = imageLoad(normals, texelPos); - if (data1 == vec4(0)) - return; - - vec3 origin = data0.xyz; - vec3 normal = data1.xyz; - - vec4 emittance = vec4(0.0); - if (PassType == 1.0) - emittance = imageLoad(outputs, texelPos); - - const float minDistance = 0.01; - const uint sample_count = 1024; - - float dist = distance(LightOrigin, origin); - if (dist > minDistance && dist < LightRadius) - { - vec3 dir = normalize(LightOrigin - origin); - - float distAttenuation = max(1.0 - (dist / LightRadius), 0.0); - float angleAttenuation = max(dot(normal, dir), 0.0); - float spotAttenuation = 1.0; - if (LightOuterAngleCos > -1.0) - { - float cosDir = dot(dir, LightSpotDir); - spotAttenuation = smoothstep(LightOuterAngleCos, LightInnerAngleCos, cosDir); - spotAttenuation = max(spotAttenuation, 0.0); - } - - float attenuation = distAttenuation * angleAttenuation * spotAttenuation; - if (attenuation > 0.0) - { - float shadowAttenuation = 0.0; - vec3 e0 = cross(normal, abs(normal.x) < abs(normal.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0)); - vec3 e1 = cross(normal, e0); - e0 = cross(normal, e1); - for (uint i = 0; i < sample_count; i++) - { - vec2 offset = (Hammersley(i, sample_count) - 0.5) * SampleDistance; - vec3 origin2 = origin + offset.x * e0 + offset.y * e1; - - float dist2 = distance(LightOrigin, origin2); - vec3 dir2 = normalize(LightOrigin - origin2); - - traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, origin2, minDistance, dir2, dist2, 0); - shadowAttenuation += payload.hitAttenuation; - } - shadowAttenuation *= 1.0 / float(sample_count); - - attenuation *= shadowAttenuation; - - emittance.rgb += LightColor * (attenuation * LightIntensity); - } - } - - emittance.w += 1.0; - imageStore(outputs, texelPos, emittance); -} - )glsl"; diff --git a/src/lightmap/glsl_rgen_light.h b/src/lightmap/glsl_rgen_light.h index d8ce2fe..5908c10 100644 --- a/src/lightmap/glsl_rgen_light.h +++ b/src/lightmap/glsl_rgen_light.h @@ -5,30 +5,119 @@ static const char* glsl_rgen_light = R"glsl( struct hitPayload { + vec3 hitPosition; float hitAttenuation; + int hitSurfaceIndex; }; layout(location = 0) rayPayloadEXT hitPayload payload; layout(set = 0, binding = 0) uniform accelerationStructureEXT acc; -layout(set = 0, binding = 1, rgba32f) uniform image2D positions; -layout(set = 0, binding = 2, rgba32f) uniform image2D normals; +layout(set = 0, binding = 1, rgba32f) uniform image2D startpositions; +layout(set = 0, binding = 2, rgba32f) uniform image2D positions; layout(set = 0, binding = 3, rgba32f) uniform image2D outputs; layout(set = 0, binding = 4) uniform Uniforms { + uint SampleIndex; + uint SampleCount; + uint PassType; + uint Padding2; vec3 LightOrigin; - float PassType; + float Padding0; float LightRadius; float LightIntensity; float LightInnerAngleCos; float LightOuterAngleCos; - vec3 LightSpotDir; + vec3 LightDir; float SampleDistance; vec3 LightColor; - float Padding; + float Padding1; }; +struct SurfaceInfo +{ + vec3 Normal; + float EmissiveDistance; + vec3 EmissiveColor; + float EmissiveIntensity; + float Sky; + float Padding0, Padding1, Padding2; +}; + +layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; + +vec2 Hammersley(uint i, uint N); +float RadicalInverse_VdC(uint bits); + +void main() +{ + ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy); + vec4 incoming = imageLoad(outputs, texelPos); + vec4 data0 = imageLoad(positions, texelPos); + int surfaceIndex = int(data0.w); + if (surfaceIndex < 0 || incoming.w <= 0.0) + return; + + const float minDistance = 0.01; + + vec3 origin = data0.xyz; + float dist = distance(LightOrigin, origin); + if (dist > minDistance && dist < LightRadius) + { + vec3 dir = normalize(LightOrigin - origin); + + SurfaceInfo surface = surfaces[surfaceIndex]; + vec3 normal = surface.Normal; + + float distAttenuation = max(1.0 - (dist / LightRadius), 0.0); + float angleAttenuation = max(dot(normal, dir), 0.0); + float spotAttenuation = 1.0; + if (LightOuterAngleCos > -1.0) + { + float cosDir = dot(dir, LightDir); + spotAttenuation = smoothstep(LightOuterAngleCos, LightInnerAngleCos, cosDir); + spotAttenuation = max(spotAttenuation, 0.0); + } + + float attenuation = distAttenuation * angleAttenuation * spotAttenuation; + if (attenuation > 0.0) + { + float shadowAttenuation = 0.0; + + if (PassType == 0) + { + vec3 e0 = cross(normal, abs(normal.x) < abs(normal.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0)); + vec3 e1 = cross(normal, e0); + e0 = cross(normal, e1); + for (uint i = 0; i < SampleCount; i++) + { + vec2 offset = (Hammersley(i, SampleCount) - 0.5) * SampleDistance; + vec3 origin2 = origin + offset.x * e0 + offset.y * e1; + + float dist2 = distance(LightOrigin, origin2); + vec3 dir2 = normalize(LightOrigin - origin2); + + traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 1, 0, 1, origin2, minDistance, dir2, dist2, 0); + shadowAttenuation += payload.hitAttenuation; + } + shadowAttenuation *= 1.0 / float(SampleCount); + } + else + { + traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 1, 0, 1, origin, minDistance, dir, dist, 0); + shadowAttenuation = payload.hitAttenuation; + } + + attenuation *= shadowAttenuation; + + incoming.rgb += LightColor * (attenuation * LightIntensity) * incoming.w; + } + } + + imageStore(outputs, texelPos, incoming); +} + float RadicalInverse_VdC(uint bits) { bits = (bits << 16u) | (bits >> 16u); @@ -44,67 +133,4 @@ vec2 Hammersley(uint i, uint N) return vec2(float(i) / float(N), RadicalInverse_VdC(i)); } -void main() -{ - ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy); - vec4 data0 = imageLoad(positions, texelPos); - vec4 data1 = imageLoad(normals, texelPos); - if (data1 == vec4(0)) - return; - - vec3 origin = data0.xyz; - vec3 normal = data1.xyz; - - vec4 emittance = vec4(0.0); - if (PassType == 1.0) - emittance = imageLoad(outputs, texelPos); - - const float minDistance = 0.01; - const uint sample_count = 1024; - - float dist = distance(LightOrigin, origin); - if (dist > minDistance && dist < LightRadius) - { - vec3 dir = normalize(LightOrigin - origin); - - float distAttenuation = max(1.0 - (dist / LightRadius), 0.0); - float angleAttenuation = max(dot(normal, dir), 0.0); - float spotAttenuation = 1.0; - if (LightOuterAngleCos > -1.0) - { - float cosDir = dot(dir, LightSpotDir); - spotAttenuation = smoothstep(LightOuterAngleCos, LightInnerAngleCos, cosDir); - spotAttenuation = max(spotAttenuation, 0.0); - } - - float attenuation = distAttenuation * angleAttenuation * spotAttenuation; - if (attenuation > 0.0) - { - float shadowAttenuation = 0.0; - vec3 e0 = cross(normal, abs(normal.x) < abs(normal.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0)); - vec3 e1 = cross(normal, e0); - e0 = cross(normal, e1); - for (uint i = 0; i < sample_count; i++) - { - vec2 offset = (Hammersley(i, sample_count) - 0.5) * SampleDistance; - vec3 origin2 = origin + offset.x * e0 + offset.y * e1; - - float dist2 = distance(LightOrigin, origin2); - vec3 dir2 = normalize(LightOrigin - origin2); - - traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 1, 0, 1, origin2, minDistance, dir2, dist2, 0); - shadowAttenuation += payload.hitAttenuation; - } - shadowAttenuation *= 1.0 / float(sample_count); - - attenuation *= shadowAttenuation; - - emittance.rgb += LightColor * (attenuation * LightIntensity); - } - } - - emittance.w += 1.0; - imageStore(outputs, texelPos, emittance); -} - )glsl"; diff --git a/src/lightmap/glsl_rgen_sun.h b/src/lightmap/glsl_rgen_sun.h index c5b4f43..ef47926 100644 --- a/src/lightmap/glsl_rgen_sun.h +++ b/src/lightmap/glsl_rgen_sun.h @@ -5,30 +5,96 @@ static const char* glsl_rgen_sun = R"glsl( struct hitPayload { + vec3 hitPosition; float hitAttenuation; + int hitSurfaceIndex; }; layout(location = 0) rayPayloadEXT hitPayload payload; layout(set = 0, binding = 0) uniform accelerationStructureEXT acc; -layout(set = 0, binding = 1, rgba32f) uniform image2D positions; -layout(set = 0, binding = 2, rgba32f) uniform image2D normals; +layout(set = 0, binding = 1, rgba32f) uniform image2D startpositions; +layout(set = 0, binding = 2, rgba32f) uniform image2D positions; layout(set = 0, binding = 3, rgba32f) uniform image2D outputs; layout(set = 0, binding = 4) uniform Uniforms { + uint SampleIndex; + uint SampleCount; + uint PassType; + uint Padding2; vec3 LightOrigin; - float PassType; + float Padding0; float LightRadius; float LightIntensity; float LightInnerAngleCos; float LightOuterAngleCos; - vec3 LightSpotDir; + vec3 LightDir; float SampleDistance; vec3 LightColor; - float Padding; + float Padding1; }; +struct SurfaceInfo +{ + vec3 Normal; + float EmissiveDistance; + vec3 EmissiveColor; + float EmissiveIntensity; + float Sky; + float Padding0, Padding1, Padding2; +}; + +layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; + +vec2 Hammersley(uint i, uint N); +float RadicalInverse_VdC(uint bits); + +void main() +{ + ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy); + vec4 incoming = imageLoad(outputs, texelPos); + vec4 data0 = imageLoad(positions, texelPos); + int surfaceIndex = int(data0.w); + if (surfaceIndex < 0 || incoming.w <= 0.0) + return; + + SurfaceInfo surface = surfaces[surfaceIndex]; + vec3 normal = surface.Normal; + + vec3 origin = data0.xyz; + origin += normal * 0.1; + + const float minDistance = 0; + const float dist = 32768.0; + + float attenuation = 0.0; + if (PassType == 0) + { + vec3 e0 = cross(normal, abs(normal.x) < abs(normal.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0)); + vec3 e1 = cross(normal, e0); + e0 = cross(normal, e1); + + for (uint i = 0; i < SampleCount; i++) + { + vec2 offset = (Hammersley(i, SampleCount) - 0.5) * SampleDistance; + vec3 origin2 = origin + offset.x * e0 + offset.y * e1; + + traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 2, 0, 2, origin2, minDistance, LightDir, dist, 0); + attenuation += payload.hitAttenuation; + } + attenuation *= 1.0 / float(SampleCount); + } + else + { + traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 2, 0, 2, origin, minDistance, LightDir, dist, 0); + attenuation = payload.hitAttenuation; + } + + incoming.rgb += LightColor * (attenuation * LightIntensity) * incoming.w; + imageStore(outputs, texelPos, incoming); +} + float RadicalInverse_VdC(uint bits) { bits = (bits << 16u) | (bits >> 16u); @@ -44,47 +110,4 @@ vec2 Hammersley(uint i, uint N) return vec2(float(i) / float(N), RadicalInverse_VdC(i)); } -void main() -{ - ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy); - vec4 data0 = imageLoad(positions, texelPos); - vec4 data1 = imageLoad(normals, texelPos); - if (data1 == vec4(0)) - return; - - vec3 origin = data0.xyz; - vec3 normal = data1.xyz; - - vec4 emittance = vec4(0.0); - if (PassType == 1.0) - emittance = imageLoad(outputs, texelPos); - - const float minDistance = 0.01; - const uint sample_count = 1024; - - vec3 e0 = cross(normal, abs(normal.x) < abs(normal.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0)); - vec3 e1 = cross(normal, e0); - e0 = cross(normal, e1); - - origin += normal * 0.1; - - float attenuation = 0.0; - for (uint i = 0; i < sample_count; i++) - { - vec2 offset = (Hammersley(i, sample_count) - 0.5) * SampleDistance; - vec3 origin2 = origin + offset.x * e0 + offset.y * e1; - - float dist2 = 32768.0; - vec3 dir2 = LightSpotDir; - - traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 2, 0, 2, origin2, minDistance, dir2, dist2, 0); - attenuation += payload.hitAttenuation; - } - attenuation *= 1.0 / float(sample_count); - emittance.rgb += LightColor * (attenuation * LightIntensity); - - emittance.w += 1.0; - imageStore(outputs, texelPos, emittance); -} - )glsl"; diff --git a/src/lightmap/glsl_rmiss_bounce.h b/src/lightmap/glsl_rmiss_bounce.h index 2f89031..3ed3b45 100644 --- a/src/lightmap/glsl_rmiss_bounce.h +++ b/src/lightmap/glsl_rmiss_bounce.h @@ -5,7 +5,9 @@ static const char* glsl_rmiss_bounce = R"glsl( struct hitPayload { + vec3 hitPosition; float hitAttenuation; + int hitSurfaceIndex; }; layout(location = 0) rayPayloadInEXT hitPayload payload; diff --git a/src/lightmap/glsl_rmiss_light.h b/src/lightmap/glsl_rmiss_light.h index 70e24f2..412abad 100644 --- a/src/lightmap/glsl_rmiss_light.h +++ b/src/lightmap/glsl_rmiss_light.h @@ -5,7 +5,9 @@ static const char* glsl_rmiss_light = R"glsl( struct hitPayload { + vec3 hitPosition; float hitAttenuation; + int hitSurfaceIndex; }; layout(location = 0) rayPayloadInEXT hitPayload payload; diff --git a/src/lightmap/glsl_rmiss_sun.h b/src/lightmap/glsl_rmiss_sun.h index 056f954..29df593 100644 --- a/src/lightmap/glsl_rmiss_sun.h +++ b/src/lightmap/glsl_rmiss_sun.h @@ -5,7 +5,9 @@ static const char* glsl_rmiss_sun = R"glsl( struct hitPayload { + vec3 hitPosition; float hitAttenuation; + int hitSurfaceIndex; }; layout(location = 0) rayPayloadInEXT hitPayload payload; diff --git a/src/lightmap/gpuraytracer.cpp b/src/lightmap/gpuraytracer.cpp index 0edfe4d..cbab28f 100644 --- a/src/lightmap/gpuraytracer.cpp +++ b/src/lightmap/gpuraytracer.cpp @@ -76,36 +76,62 @@ void GPURaytracer::Raytrace(LevelMesh* level) UploadTasks(tasks); - // Sunlight - { - Uniforms uniforms = {}; - uniforms.LightOrigin = Vec3(0.0f, 0.0f, 0.0f); - uniforms.LightRadius = -1.0f; - uniforms.LightIntensity = 1.0f; - uniforms.LightInnerAngleCos = -1.0f; - uniforms.LightOuterAngleCos = -1.0f; - uniforms.LightSpotDir = mesh->map->GetSunDirection(); - uniforms.LightColor = mesh->map->GetSunColor(); - uniforms.PassType = 0.0f; - uniforms.SampleDistance = (float)mesh->samples; - RunTrace(uniforms, rgenSunRegion); - } + Uniforms uniforms = {}; + uniforms.SampleDistance = (float)mesh->samples; + uniforms.SampleCount = SAMPLE_COUNT; + + uniforms.SampleIndex = 0; + uniforms.PassType = 0; + RunTrace(uniforms, rgenBounceRegion); + + uniforms.LightDir = mesh->map->GetSunDirection(); + uniforms.LightColor = mesh->map->GetSunColor(); + uniforms.LightIntensity = 1.0f; + RunTrace(uniforms, rgenSunRegion); for (ThingLight& light : mesh->map->ThingLights) { - Uniforms uniforms = {}; uniforms.LightOrigin = light.LightOrigin(); uniforms.LightRadius = light.LightRadius(); uniforms.LightIntensity = light.intensity; uniforms.LightInnerAngleCos = light.innerAngleCos; uniforms.LightOuterAngleCos = light.outerAngleCos; - uniforms.LightSpotDir = light.SpotDir(); + uniforms.LightDir = light.SpotDir(); uniforms.LightColor = light.rgb; - uniforms.PassType = 1.0f; - uniforms.SampleDistance = (float)mesh->samples; RunTrace(uniforms, rgenLightRegion); } + for (uint32_t i = 0; i < uniforms.SampleCount; i++) + { + uniforms.PassType = 1; + uniforms.SampleIndex = i; + RunTrace(uniforms, rgenBounceRegion); + + for (int bounce = 0; bounce < LightBounce; bounce++) + { + uniforms.LightDir = mesh->map->GetSunDirection(); + uniforms.LightColor = mesh->map->GetSunColor(); + uniforms.LightIntensity = 1.0f; + RunTrace(uniforms, rgenSunRegion); + + for (ThingLight& light : mesh->map->ThingLights) + { + uniforms.LightOrigin = light.LightOrigin(); + uniforms.LightRadius = light.LightRadius(); + uniforms.LightIntensity = light.intensity; + uniforms.LightInnerAngleCos = light.innerAngleCos; + uniforms.LightOuterAngleCos = light.outerAngleCos; + uniforms.LightDir = light.SpotDir(); + uniforms.LightColor = light.rgb; + RunTrace(uniforms, rgenLightRegion); + } + + uniforms.PassType = 2; + uniforms.SampleIndex = (i + bounce) % uniforms.SampleCount; + RunTrace(uniforms, rgenBounceRegion); + } + } + DownloadTasks(tasks); if (device->renderdoc) @@ -139,9 +165,8 @@ void GPURaytracer::UploadTasks(const std::vector& tasks) throw std::runtime_error("Ray trace task count is too large"); size_t imageSize = sizeof(Vec4) * rayTraceImageSize * rayTraceImageSize; - uint8_t* imageData = (uint8_t*)imageTransferBuffer->Map(0, imageSize * 2); - Vec4* positions = (Vec4*)imageData; - Vec4* normals = (Vec4*)(imageData + imageSize); + uint8_t* imageData = (uint8_t*)imageTransferBuffer->Map(0, imageSize); + Vec4* startPositions = (Vec4*)imageData; for (size_t i = 0; i < tasks.size(); i++) { const SurfaceTask& task = tasks[i]; @@ -150,19 +175,16 @@ void GPURaytracer::UploadTasks(const std::vector& tasks) Vec3 normal = surface->plane.Normal(); Vec3 pos = surface->lightmapOrigin + normal + surface->lightmapSteps[0] * (float)task.x + surface->lightmapSteps[1] * (float)task.y; - positions[i] = Vec4(pos, 1.0f); - normals[i] = Vec4(normal, 1.0f); + startPositions[i] = Vec4(pos, (float)task.surf); } for (size_t i = tasks.size(); i < maxTasks; i++) { - positions[i] = Vec4(0.0f, 0.0f, 0.0f, 0.0f); - normals[i] = Vec4(0.0f, 0.0f, 0.0f, 0.0f); + startPositions[i] = Vec4(0.0f, 0.0f, 0.0f, -1.0f); } imageTransferBuffer->Unmap(); PipelineBarrier barrier1; - barrier1.addImage(positionsImage.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT); - barrier1.addImage(normalsImage.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT); + barrier1.addImage(startPositionsImage.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT); barrier1.execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); VkBufferImageCopy region = {}; @@ -172,21 +194,12 @@ void GPURaytracer::UploadTasks(const std::vector& tasks) region.imageExtent.depth = 1; region.imageSubresource.layerCount = 1; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - cmdbuffer->copyBufferToImage(imageTransferBuffer->buffer, positionsImage->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - region = {}; - region.bufferOffset = imageSize; - region.imageExtent.width = rayTraceImageSize; - region.imageExtent.height = rayTraceImageSize; - region.imageExtent.depth = 1; - region.imageSubresource.layerCount = 1; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - cmdbuffer->copyBufferToImage(imageTransferBuffer->buffer, normalsImage->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + cmdbuffer->copyBufferToImage(imageTransferBuffer->buffer, startPositionsImage->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); PipelineBarrier barrier2; barrier2.addBuffer(uniformBuffer.get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); - barrier2.addImage(positionsImage.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); - barrier2.addImage(normalsImage.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + barrier2.addImage(startPositionsImage.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + barrier2.addImage(positionsImage.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, 0, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); barrier2.addImage(outputImage.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, 0, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); barrier2.execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); } @@ -303,7 +316,7 @@ void GPURaytracer::CreateVertexAndIndexBuffers() info.Normal = surface->plane.Normal(); if (def) { - info.EmissiveDistance = def->distance; + info.EmissiveDistance = def->distance + def->distance; info.EmissiveIntensity = def->intensity; info.EmissiveColor = def->rgb; } @@ -611,7 +624,7 @@ void GPURaytracer::CreatePipeline() setbuilder.addBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); setbuilder.addBinding(4, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); setbuilder.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - setbuilder.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); + setbuilder.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); descriptorSetLayout = setbuilder.create(device.get()); descriptorSetLayout->SetDebugName("descriptorSetLayout"); @@ -750,15 +763,15 @@ void GPURaytracer::CreateDescriptorSet() imgbuilder1.setUsage(VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); imgbuilder1.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT); imgbuilder1.setSize(rayTraceImageSize, rayTraceImageSize); - positionsImage = imgbuilder1.create(device.get()); - positionsImage->SetDebugName("positionsImage"); + startPositionsImage = imgbuilder1.create(device.get()); + startPositionsImage->SetDebugName("startPositionsImage"); ImageBuilder imgbuilder2; imgbuilder2.setUsage(VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); imgbuilder2.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT); imgbuilder2.setSize(rayTraceImageSize, rayTraceImageSize); - normalsImage = imgbuilder2.create(device.get()); - normalsImage->SetDebugName("normalsImage"); + positionsImage = imgbuilder2.create(device.get()); + positionsImage->SetDebugName("positionsImage"); ImageBuilder imgbuilder3; imgbuilder3.setUsage(VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); @@ -768,14 +781,14 @@ void GPURaytracer::CreateDescriptorSet() outputImage->SetDebugName("outputImage"); ImageViewBuilder viewbuilder1; - viewbuilder1.setImage(positionsImage.get(), VK_FORMAT_R32G32B32A32_SFLOAT); - positionsImageView = viewbuilder1.create(device.get()); - positionsImageView->SetDebugName("positionsImageView"); + viewbuilder1.setImage(startPositionsImage.get(), VK_FORMAT_R32G32B32A32_SFLOAT); + startPositionsImageView = viewbuilder1.create(device.get()); + startPositionsImageView->SetDebugName("startPositionsImageView"); ImageViewBuilder viewbuilder2; - viewbuilder2.setImage(normalsImage.get(), VK_FORMAT_R32G32B32A32_SFLOAT); - normalsImageView = viewbuilder2.create(device.get()); - normalsImageView->SetDebugName("normalsImageView"); + viewbuilder2.setImage(positionsImage.get(), VK_FORMAT_R32G32B32A32_SFLOAT); + positionsImageView = viewbuilder2.create(device.get()); + positionsImageView->SetDebugName("positionsImageView"); ImageViewBuilder viewbuilder3; viewbuilder3.setImage(outputImage.get(), VK_FORMAT_R32G32B32A32_SFLOAT); @@ -796,8 +809,8 @@ void GPURaytracer::CreateDescriptorSet() WriteDescriptors write; write.addAccelerationStructure(descriptorSet.get(), 0, tlAccelStruct.get()); - write.addStorageImage(descriptorSet.get(), 1, positionsImageView.get(), VK_IMAGE_LAYOUT_GENERAL); - write.addStorageImage(descriptorSet.get(), 2, normalsImageView.get(), VK_IMAGE_LAYOUT_GENERAL); + write.addStorageImage(descriptorSet.get(), 1, startPositionsImageView.get(), VK_IMAGE_LAYOUT_GENERAL); + write.addStorageImage(descriptorSet.get(), 2, positionsImageView.get(), VK_IMAGE_LAYOUT_GENERAL); write.addStorageImage(descriptorSet.get(), 3, outputImageView.get(), VK_IMAGE_LAYOUT_GENERAL); write.addBuffer(descriptorSet.get(), 4, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniformBuffer.get()); write.addBuffer(descriptorSet.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceIndexBuffer.get()); @@ -982,7 +995,7 @@ Vec3 GPURaytracer::TracePath(const Vec3& pos, const Vec3& dir, int sampleIndex, return emittance; const float p = 1 / (2 * M_PI); - Vec3 incoming = TracePath(hitpos, normal, (sampleIndex + depth + 1) % SAMPLE_COUNT, depth + 1); + Vec3 incoming = TracePath(hitpos, L, (sampleIndex + depth + 1) % SAMPLE_COUNT, depth + 1); return emittance + incoming * NdotL / p; } diff --git a/src/lightmap/gpuraytracer.h b/src/lightmap/gpuraytracer.h index e49e3c6..a53829e 100644 --- a/src/lightmap/gpuraytracer.h +++ b/src/lightmap/gpuraytracer.h @@ -8,16 +8,20 @@ class LevelMesh; struct Uniforms { + uint32_t SampleIndex; + uint32_t SampleCount; + uint32_t PassType; + uint32_t Padding2; Vec3 LightOrigin; - float PassType; + float Padding0; float LightRadius; float LightIntensity; float LightInnerAngleCos; float LightOuterAngleCos; - Vec3 LightSpotDir; + Vec3 LightDir; float SampleDistance; Vec3 LightColor; - float Padding; + float Padding1; }; struct SurfaceInfo @@ -110,8 +114,8 @@ private: VkStridedDeviceAddressRegionKHR hitRegion = {}; VkStridedDeviceAddressRegionKHR callRegion = {}; - std::unique_ptr positionsImage, normalsImage, outputImage; - std::unique_ptr positionsImageView, normalsImageView, outputImageView; + std::unique_ptr startPositionsImage, positionsImage, outputImage; + std::unique_ptr startPositionsImageView, positionsImageView, outputImageView; std::unique_ptr imageTransferBuffer; std::unique_ptr uniformBuffer; diff --git a/src/lightmap/raytracer.cpp b/src/lightmap/raytracer.cpp index a2b2478..6bd0390 100644 --- a/src/lightmap/raytracer.cpp +++ b/src/lightmap/raytracer.cpp @@ -220,7 +220,7 @@ Vec3 Raytracer::TracePath(const Vec3& pos, const Vec3& dir, int sampleIndex, int return emittance; const float p = 1 / (2 * M_PI); - Vec3 incoming = TracePath(hitpos, normal, (sampleIndex + depth + 1) % SAMPLE_COUNT, depth + 1); + Vec3 incoming = TracePath(hitpos, L, (sampleIndex + depth + 1) % SAMPLE_COUNT, depth + 1); return emittance + incoming * NdotL / p; }