diff --git a/CMakeLists.txt b/CMakeLists.txt index 575da23..813b60a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,7 +175,6 @@ set( SOURCES src/lightmap/glsl_rchit_sun.h src/lightmap/glsl_rgen_bounce.h src/lightmap/glsl_rgen_light.h - src/lightmap/glsl_rgen_sun.h src/lightmap/glsl_rmiss_bounce.h src/lightmap/glsl_rmiss_light.h src/lightmap/glsl_rmiss_sun.h diff --git a/src/lightmap/glsl_rgen_bounce.h b/src/lightmap/glsl_rgen_bounce.h index b137131..496a8d9 100644 --- a/src/lightmap/glsl_rgen_bounce.h +++ b/src/lightmap/glsl_rgen_bounce.h @@ -59,23 +59,41 @@ void main() if (PassType != 0) incoming = imageLoad(outputs, texelPos); + vec3 origin = data0.xyz; int surfaceIndex = int(data0.w); - if (surfaceIndex >= 0) + if (surfaceIndex != -1) { - SurfaceInfo surface = surfaces[surfaceIndex]; - - vec3 origin = data0.xyz; - vec3 normal = surface.Normal; - if (PassType == 0) { - incoming.rgb = surface.EmissiveColor * surface.EmissiveIntensity; + if (surfaceIndex >= 0) + { + SurfaceInfo surface = surfaces[surfaceIndex]; + incoming.rgb = surface.EmissiveColor * surface.EmissiveIntensity; + } } else { if (PassType == 1) incoming.w = 1.0f / float(SampleCount); + vec3 normal; + if (surfaceIndex >= 0) + { + normal = surfaces[surfaceIndex].Normal; + } + else + { + switch (SampleIndex % 6) + { + case 0: normal = vec3( 1.0f, 0.0f, 0.0f); break; + case 1: normal = vec3(-1.0f, 0.0f, 0.0f); break; + case 2: normal = vec3( 0.0f, 1.0f, 0.0f); break; + case 3: normal = vec3( 0.0f, -1.0f, 0.0f); break; + case 4: normal = vec3( 0.0f, 0.0f, 1.0f); break; + case 5: normal = vec3( 0.0f, 0.0f, -1.0f); break; + } + } + vec3 H = ImportanceSample(normal); vec3 L = normalize(H * (2.0f * dot(normal, H)) - normal); @@ -94,7 +112,7 @@ void main() { float hitDistance = distance(origin, payload.hitPosition); surfaceIndex = payload.hitSurfaceIndex; - surface = surfaces[surfaceIndex]; + SurfaceInfo surface = surfaces[surfaceIndex]; origin = payload.hitPosition; if (surface.EmissiveDistance > 0.0) @@ -107,11 +125,11 @@ void main() incoming.w *= 0.25; // the amount of incoming light the surfaces emit } - - data0.xyz = origin; - data0.w = float(surfaceIndex); } + data0.xyz = origin; + data0.w = float(surfaceIndex); + imageStore(positions, texelPos, data0); imageStore(outputs, texelPos, incoming); } diff --git a/src/lightmap/glsl_rgen_light.h b/src/lightmap/glsl_rgen_light.h index 85e0244..be78d55 100644 --- a/src/lightmap/glsl_rgen_light.h +++ b/src/lightmap/glsl_rgen_light.h @@ -67,11 +67,12 @@ void main() vec4 incoming = imageLoad(outputs, texelPos); vec4 data0 = imageLoad(positions, texelPos); int surfaceIndex = int(data0.w); - if (surfaceIndex < 0 || incoming.w <= 0.0) + if (surfaceIndex == -1 || incoming.w <= 0.0) return; - SurfaceInfo surface = surfaces[surfaceIndex]; - vec3 normal = surface.Normal; + vec3 normal; + if (surfaceIndex >= 0) + normal = surfaces[surfaceIndex].Normal; vec3 origin = data0.xyz + normal * 0.1; @@ -82,7 +83,7 @@ void main() const float dist = 32768.0; float attenuation = 0.0; - if (PassType == 0) + if (PassType == 0 && surfaceIndex >= 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); @@ -116,7 +117,11 @@ void main() vec3 dir = normalize(light.Origin - origin); float distAttenuation = max(1.0 - (dist / light.Radius), 0.0); - float angleAttenuation = max(dot(normal, dir), 0.0); + float angleAttenuation = 1.0f; + if (surfaceIndex >= 0) + { + angleAttenuation = max(dot(normal, dir), 0.0); + } float spotAttenuation = 1.0; if (light.OuterAngleCos > -1.0) { @@ -130,7 +135,7 @@ void main() { float shadowAttenuation = 0.0; - if (PassType == 0) + if (PassType == 0 && surfaceIndex >= 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); diff --git a/src/lightmap/glsl_rgen_sun.h b/src/lightmap/glsl_rgen_sun.h deleted file mode 100644 index 422bd2f..0000000 --- a/src/lightmap/glsl_rgen_sun.h +++ /dev/null @@ -1,109 +0,0 @@ -static const char* glsl_rgen_sun = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -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 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 LightCount; - vec3 SunDir; - float SampleDistance; - vec3 SunColor; - float SunIntensity; - vec3 HemisphereVec; - 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, SunDir, dist, 0); - attenuation += payload.hitAttenuation; - } - attenuation *= 1.0 / float(SampleCount); - } - else - { - traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 2, 0, 2, origin, minDistance, SunDir, dist, 0); - attenuation = payload.hitAttenuation; - } - - incoming.rgb += SunColor * (attenuation * SunIntensity) * incoming.w; - imageStore(outputs, texelPos, incoming); -} - -float RadicalInverse_VdC(uint bits) -{ - bits = (bits << 16u) | (bits >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - return float(bits) * 2.3283064365386963e-10f; // / 0x100000000 -} - -vec2 Hammersley(uint i, uint N) -{ - return vec2(float(i) / float(N), RadicalInverse_VdC(i)); -} - -)glsl"; diff --git a/src/lightmap/gpuraytracer.cpp b/src/lightmap/gpuraytracer.cpp index 6c3b8ec..c71e3ae 100644 --- a/src/lightmap/gpuraytracer.cpp +++ b/src/lightmap/gpuraytracer.cpp @@ -14,7 +14,6 @@ #include #include "glsl_rgen_bounce.h" #include "glsl_rgen_light.h" -#include "glsl_rgen_sun.h" #include "glsl_rchit_bounce.h" #include "glsl_rchit_light.h" #include "glsl_rchit_sun.h" @@ -46,15 +45,15 @@ void GPURaytracer::Raytrace(LevelMesh* level) CreateVulkanObjects(); - printf("Tracing light probes\n"); - - Worker::RunJob((int)mesh->lightProbes.size(), [=](int id) { - RaytraceProbeSample(&mesh->lightProbes[id]); - }); - - printf("Tracing surfaces, %d bounce(s)\n", LightBounce); - - std::vector tasks; + std::vector tasks; + for (size_t i = 0; i < mesh->lightProbes.size(); i++) + { + TraceTask task; + task.id = -(int)(i + 2); + task.x = 0; + task.y = 0; + tasks.push_back(task); + } for (size_t i = 0; i < mesh->surfaces.size(); i++) { @@ -65,8 +64,8 @@ void GPURaytracer::Raytrace(LevelMesh* level) { for (int x = 0; x < sampleWidth; x++) { - SurfaceTask task; - task.surf = (int)i; + TraceTask task; + task.id = (int)i; task.x = x; task.y = y; tasks.push_back(task); @@ -87,6 +86,8 @@ void GPURaytracer::Raytrace(LevelMesh* level) HemisphereVectors.push_back(H); } + printf("Ray tracing with %d bounce(s)\n", LightBounce); + size_t maxTasks = (size_t)rayTraceImageSize * rayTraceImageSize; for (size_t startTask = 0; startTask < tasks.size(); startTask += maxTasks) { @@ -102,9 +103,9 @@ void GPURaytracer::Raytrace(LevelMesh* level) uniforms.SunColor = mesh->map->GetSunColor(); uniforms.SunIntensity = 1.0f; + uniforms.PassType = 0; uniforms.SampleIndex = 0; uniforms.SampleCount = bounceSampleCount; - uniforms.PassType = 0; RunTrace(uniforms, rgenBounceRegion); uniforms.SampleCount = coverageSampleCount; @@ -124,8 +125,8 @@ void GPURaytracer::Raytrace(LevelMesh* level) RunTrace(uniforms, rgenLightRegion); uniforms.PassType = 2; - uniforms.SampleCount = bounceSampleCount; uniforms.SampleIndex = (i + bounce) % uniforms.SampleCount; + uniforms.SampleCount = bounceSampleCount; uniforms.HemisphereVec = HemisphereVectors[uniforms.SampleIndex]; RunTrace(uniforms, rgenBounceRegion); } @@ -159,7 +160,7 @@ void GPURaytracer::CreateVulkanObjects() finishbuildbarrier.execute(cmdbuffer.get(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); } -void GPURaytracer::UploadTasks(const SurfaceTask* tasks, size_t size) +void GPURaytracer::UploadTasks(const TraceTask* tasks, size_t size) { if (!cmdbuffer) { @@ -176,12 +177,20 @@ void GPURaytracer::UploadTasks(const SurfaceTask* tasks, size_t size) Vec4* startPositions = (Vec4*)imageData; for (size_t i = 0; i < size; i++) { - const SurfaceTask& task = tasks[i]; - Surface* surface = mesh->surfaces[task.surf].get(); + const TraceTask& task = tasks[i]; - Vec3 pos = surface->lightmapOrigin + surface->lightmapSteps[0] * (float)task.x + surface->lightmapSteps[1] * (float)task.y; + if (task.id >= 0) + { + Surface* surface = mesh->surfaces[task.id].get(); + Vec3 pos = surface->lightmapOrigin + surface->lightmapSteps[0] * (float)task.x + surface->lightmapSteps[1] * (float)task.y; + startPositions[i] = Vec4(pos, (float)task.id); + } + else + { + LightProbeSample& probe = mesh->lightProbes[(size_t)(-task.id) - 2]; + startPositions[i] = Vec4(probe.Position, (float)-2); + } - startPositions[i] = Vec4(pos, (float)task.surf); } for (size_t i = size; i < maxTasks; i++) { @@ -276,7 +285,7 @@ void GPURaytracer::SubmitCommands() cmdbuffer.reset(); } -void GPURaytracer::DownloadTasks(const SurfaceTask* tasks, size_t size) +void GPURaytracer::DownloadTasks(const TraceTask* tasks, size_t size) { PipelineBarrier barrier4; barrier4.addImage(outputImage.get(), VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); @@ -299,11 +308,18 @@ void GPURaytracer::DownloadTasks(const SurfaceTask* tasks, size_t size) Vec4* output = (Vec4*)imageData; for (size_t i = 0; i < size; i++) { - const SurfaceTask& task = tasks[i]; - Surface* surface = mesh->surfaces[task.surf].get(); - - size_t sampleWidth = surface->lightmapDims[0]; - surface->samples[task.x + task.y * sampleWidth] = Vec3(output[i].x, output[i].y, output[i].z); + const TraceTask& task = tasks[i]; + if (task.id >= 0) + { + Surface* surface = mesh->surfaces[task.id].get(); + size_t sampleWidth = surface->lightmapDims[0]; + surface->samples[task.x + task.y * sampleWidth] = Vec3(output[i].x, output[i].y, output[i].z); + } + else + { + LightProbeSample& probe = mesh->lightProbes[(size_t)(-task.id) - 2]; + probe.Color = Vec3(output[i].x, output[i].y, output[i].z); + } } imageTransferBuffer->Unmap(); } @@ -412,7 +428,7 @@ void GPURaytracer::CreateVertexAndIndexBuffers() BufferBuilder lbuilder; lbuilder.setUsage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); lbuilder.setSize(lightbuffersize); - lightBuffer = sbuilder.create(device.get()); + lightBuffer = lbuilder.create(device.get()); lightBuffer->SetDebugName("lightBuffer"); BufferBuilder tbuilder; @@ -612,7 +628,6 @@ void GPURaytracer::CreateShaders() { rgenBounce = CompileRayGenShader(glsl_rgen_bounce, "rgen.bounce"); rgenLight = CompileRayGenShader(glsl_rgen_light, "rgen.light"); - rgenSun = CompileRayGenShader(glsl_rgen_sun, "rgen.sun"); rchitBounce = CompileClosestHitShader(glsl_rchit_bounce, "rchit.bounce"); rchitLight = CompileClosestHitShader(glsl_rchit_light, "rchit.light"); rchitSun = CompileClosestHitShader(glsl_rchit_sun, "rchit.sun"); @@ -693,7 +708,6 @@ void GPURaytracer::CreatePipeline() builder.setMaxPipelineRayRecursionDepth(1); builder.addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenBounce.get()); builder.addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenLight.get()); - builder.addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenSun.get()); builder.addShader(VK_SHADER_STAGE_MISS_BIT_KHR, rmissBounce.get()); builder.addShader(VK_SHADER_STAGE_MISS_BIT_KHR, rmissLight.get()); builder.addShader(VK_SHADER_STAGE_MISS_BIT_KHR, rmissSun.get()); @@ -702,13 +716,12 @@ void GPURaytracer::CreatePipeline() builder.addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, rchitSun.get()); builder.addRayGenGroup(0); builder.addRayGenGroup(1); - builder.addRayGenGroup(2); + builder.addMissGroup(2); builder.addMissGroup(3); builder.addMissGroup(4); - builder.addMissGroup(5); + builder.addTrianglesHitGroup(5); builder.addTrianglesHitGroup(6); builder.addTrianglesHitGroup(7); - builder.addTrianglesHitGroup(8); pipeline = builder.create(device.get()); pipeline->SetDebugName("pipeline"); @@ -722,7 +735,7 @@ void GPURaytracer::CreatePipeline() return value; }; - VkDeviceSize raygenCount = 3; + VkDeviceSize raygenCount = 2; VkDeviceSize missCount = 3; VkDeviceSize hitCount = 3; @@ -736,8 +749,6 @@ void GPURaytracer::CreatePipeline() rgenBounceRegion.size = rgenStride; rgenLightRegion.stride = rgenStride; rgenLightRegion.size = rgenStride; - rgenSunRegion.stride = rgenStride; - rgenSunRegion.size = rgenStride; missRegion.stride = handleSizeAligned; missRegion.size = align_up(missCount * handleSizeAligned, rtProperties.shaderGroupBaseAlignment); @@ -789,7 +800,6 @@ void GPURaytracer::CreatePipeline() rgenBounceRegion.deviceAddress = sbtAddress + rgenOffset; rgenLightRegion.deviceAddress = sbtAddress + rgenOffset + rgenStride; - rgenSunRegion.deviceAddress = sbtAddress + rgenOffset + 2 * rgenStride; missRegion.deviceAddress = sbtAddress + missOffset; hitRegion.deviceAddress = sbtAddress + hitOffset; } @@ -867,7 +877,7 @@ void GPURaytracer::CreateDescriptorSet() 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_DYNAMIC, uniformBuffer.get()); + write.addBuffer(descriptorSet.get(), 4, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, uniformBuffer.get(), 0, sizeof(Uniforms)); write.addBuffer(descriptorSet.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceIndexBuffer.get()); write.addBuffer(descriptorSet.get(), 6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceBuffer.get()); write.addBuffer(descriptorSet.get(), 7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, lightBuffer.get()); @@ -897,124 +907,9 @@ void GPURaytracer::PrintVulkanInfo() printf("Vulkan version: %s (api) %s (driver)\n", apiVersion.c_str(), driverVersion.c_str()); } -void GPURaytracer::RaytraceProbeSample(LightProbeSample* probe) +Vec2 GPURaytracer::Hammersley(uint32_t i, uint32_t N) { - Vec3 incoming(0.0f, 0.0f, 0.0f); - - if (LightBounce > 0) - { - Vec3 directions[6] = - { - { 1.0f, 0.0f, 0.0f }, - { -1.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f }, - { 0.0f, -1.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, }, - { 0.0f, 0.0f, -1.0f, } - }; - for (int i = 0; i < bounceSampleCount; i++) - { - const Vec3& normal = directions[i % 6]; - Vec2 Xi = Hammersley(i, bounceSampleCount); - Vec3 H = ImportanceSampleGGX(Xi, normal, 1.0f); - Vec3 L = Vec3::Normalize(H * (2.0f * Vec3::Dot(normal, H)) - normal); - incoming += TracePath(probe->Position, L, i); - } - incoming = incoming / (float)bounceSampleCount / (float)LightBounce; - } - - for (ThingLight& light : mesh->map->ThingLights) - { - Vec3 lightOrigin = light.LightOrigin(); - float lightRadius = light.LightRadius(); - - if (probe->Position.DistanceSq(lightOrigin) > (lightRadius * lightRadius)) - continue; - - if (mesh->TraceAnyHit(lightOrigin, probe->Position)) - continue; // this light is occluded by something - - Vec3 dir = (lightOrigin - probe->Position); - float dist = dir.Unit(); - dir.Normalize(); - - incoming += light.rgb * (light.SpotAttenuation(dir) * light.DistAttenuation(dist) * light.intensity); - } - - const Vec3& sundir = mesh->map->GetSunDirection(); - LevelTraceHit trace = mesh->Trace(probe->Position, probe->Position + sundir * 32768.0f); - if (trace.fraction != 1.0f && trace.hitSurface->bSky) - incoming += mesh->map->GetSunColor(); - - probe->Color = incoming; -} - -Vec3 GPURaytracer::GetLightEmittance(Surface* surface, const Vec3& pos) -{ - Vec3 emittance = Vec3(0.0f); - for (ThingLight& light : mesh->map->ThingLights) - { - Vec3 lightOrigin = light.LightOrigin(); - float lightRadius = light.LightRadius(); - - if (surface->plane.Distance(lightOrigin) - surface->plane.d < 0) - continue; // completely behind the plane - - if (pos.DistanceSq(lightOrigin) > (lightRadius * lightRadius)) - continue; // light too far away - - Vec3 dir = (lightOrigin - pos); - float dist = dir.Unit(); - dir.Normalize(); - - float attenuation = light.SpotAttenuation(dir) * light.DistAttenuation(dist) * surface->plane.Normal().Dot(dir); - if (attenuation <= 0.0f) - continue; - - if (mesh->TraceAnyHit(lightOrigin, pos)) - continue; // this light is occluded by something - - emittance += light.rgb * (attenuation * light.intensity); - } - return emittance; -} - -Vec3 GPURaytracer::TracePath(const Vec3& pos, const Vec3& dir, int sampleIndex, int depth) -{ - if (depth >= LightBounce) - return Vec3(0.0f); - - LevelTraceHit hit = mesh->Trace(pos + dir * 0.1f, pos + dir * 2000.0f); - if (hit.fraction == 1.0f) - return Vec3(0.0f); - - Vec3 normal = hit.hitSurface->plane.Normal(); - Vec3 hitpos = hit.start * (1.0f - hit.fraction) + hit.end * hit.fraction; - - Vec3 emittance = GetSurfaceEmittance(hit.hitSurface, pos.Distance(hitpos)) + GetLightEmittance(hit.hitSurface, hitpos) * 0.5f; - - const Vec3& sundir = mesh->map->GetSunDirection(); - float attenuation = normal.Dot(sundir); - if (attenuation > 0.0f) - { - Vec3 start = hitpos + normal * 0.1f; - LevelTraceHit trace = mesh->Trace(start, start + sundir * 32768.0f); - if (trace.fraction != 1.0f && trace.hitSurface->bSky) - emittance += mesh->map->GetSunColor() * (attenuation * 0.5f); - } - - Vec2 Xi = Hammersley(sampleIndex, bounceSampleCount); - Vec3 H = ImportanceSampleGGX(Xi, normal, 1.0f); - Vec3 L = Vec3::Normalize(H * (2.0f * Vec3::Dot(normal, H)) - normal); - - float NdotL = Vec3::Dot(normal, L); - if (NdotL <= 0.0f) - return emittance; - - const float p = 1 / (2 * M_PI); - Vec3 incoming = TracePath(hitpos, L, (sampleIndex + depth + 1) % bounceSampleCount, depth + 1); - - return emittance + incoming * NdotL / p; + return Vec2(float(i) / float(N), RadicalInverse_VdC(i)); } float GPURaytracer::RadicalInverse_VdC(uint32_t bits) @@ -1026,69 +921,3 @@ float GPURaytracer::RadicalInverse_VdC(uint32_t bits) bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); return float(bits) * 2.3283064365386963e-10f; // / 0x100000000 } - -Vec2 GPURaytracer::Hammersley(uint32_t i, uint32_t N) -{ - return Vec2(float(i) / float(N), RadicalInverse_VdC(i)); -} - -Vec3 GPURaytracer::ImportanceSampleGGX(Vec2 Xi, Vec3 N, float roughness) -{ - float a = roughness * roughness; - - float phi = 2.0f * M_PI * 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(std::cos(phi) * sinTheta, std::sin(phi) * sinTheta, cosTheta); - - // from tangent-space vector to world-space sample vector - Vec3 up = std::abs(N.z) < 0.999f ? Vec3(0.0f, 0.0f, 1.0f) : Vec3(1.0f, 0.0f, 0.0f); - Vec3 tangent = Vec3::Normalize(Vec3::Cross(up, N)); - Vec3 bitangent = Vec3::Cross(N, tangent); - - Vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z; - return Vec3::Normalize(sampleVec); -} - -Vec3 GPURaytracer::GetSurfaceEmittance(Surface* surface, float distance) -{ - SurfaceLightDef* def = nullptr; - if (surface->type >= ST_MIDDLESIDE && surface->type <= ST_LOWERSIDE) - { - int lightdefidx = mesh->map->Sides[surface->typeIndex].lightdef; - if (lightdefidx != -1) - { - def = &mesh->map->SurfaceLights[lightdefidx]; - } - } - else if (surface->type == ST_FLOOR || surface->type == ST_CEILING) - { - MapSubsectorEx* sub = &mesh->map->GLSubsectors[surface->typeIndex]; - IntSector* sector = mesh->map->GetSectorFromSubSector(sub); - - if (sector && surface->numVerts > 0) - { - if (sector->floorlightdef != -1 && surface->type == ST_FLOOR) - { - def = &mesh->map->SurfaceLights[sector->floorlightdef]; - } - else if (sector->ceilinglightdef != -1 && surface->type == ST_CEILING) - { - def = &mesh->map->SurfaceLights[sector->ceilinglightdef]; - } - } - } - - if (def && distance < def->distance + def->distance) - { - float radius = def->distance + def->distance; - float attenuation = std::max(1.0f - (distance / radius), 0.0f); - return def->rgb * (attenuation * def->intensity); - } - else - { - return Vec3(0.0f); - } -} diff --git a/src/lightmap/gpuraytracer.h b/src/lightmap/gpuraytracer.h index 8a66763..9e05465 100644 --- a/src/lightmap/gpuraytracer.h +++ b/src/lightmap/gpuraytracer.h @@ -44,9 +44,9 @@ struct LightInfo float Padding2; }; -struct SurfaceTask +struct TraceTask { - int surf, x, y; + int id, x, y; }; class GPURaytracer @@ -69,24 +69,17 @@ private: void CreatePipeline(); void CreateDescriptorSet(); - void UploadTasks(const SurfaceTask* tasks, size_t size); + void UploadTasks(const TraceTask* tasks, size_t size); void BeginTracing(); void RunTrace(const Uniforms& uniforms, const VkStridedDeviceAddressRegionKHR& rgenShader); void EndTracing(); - void DownloadTasks(const SurfaceTask* tasks, size_t size); + void DownloadTasks(const TraceTask* tasks, size_t size); void SubmitCommands(); void PrintVulkanInfo(); - void RaytraceProbeSample(LightProbeSample* probe); - Vec3 TracePath(const Vec3& pos, const Vec3& dir, int sampleIndex, int depth = 0); - - Vec3 GetLightEmittance(Surface* surface, const Vec3& pos); - Vec3 GetSurfaceEmittance(Surface* surface, float distance); - static float RadicalInverse_VdC(uint32_t bits); static Vec2 Hammersley(uint32_t i, uint32_t N); - static Vec3 ImportanceSampleGGX(Vec2 Xi, Vec3 N, float roughness); const int coverageSampleCount = 256; const int bounceSampleCount = 2048; @@ -117,7 +110,7 @@ private: std::unique_ptr tlAccelStructBuffer; std::unique_ptr tlAccelStruct; - std::unique_ptr rgenBounce, rgenLight, rgenSun; + std::unique_ptr rgenBounce, rgenLight; std::unique_ptr rmissBounce, rmissLight, rmissSun; std::unique_ptr rchitBounce, rchitLight, rchitSun; @@ -128,7 +121,7 @@ private: std::unique_ptr shaderBindingTable; std::unique_ptr sbtTransferBuffer; - VkStridedDeviceAddressRegionKHR rgenBounceRegion = {}, rgenLightRegion = {}, rgenSunRegion = {}; + VkStridedDeviceAddressRegionKHR rgenBounceRegion = {}, rgenLightRegion = {}; VkStridedDeviceAddressRegionKHR missRegion = {}; VkStridedDeviceAddressRegionKHR hitRegion = {}; VkStridedDeviceAddressRegionKHR callRegion = {};