diff --git a/src/lightmap/gpuraytracer.cpp b/src/lightmap/gpuraytracer.cpp index 076a93f..12be42a 100644 --- a/src/lightmap/gpuraytracer.cpp +++ b/src/lightmap/gpuraytracer.cpp @@ -19,7 +19,6 @@ #include "glsl_miss.h" #include "glsl_closesthit.h" -extern int Multisample; extern int LightBounce; extern float GridSize; @@ -281,7 +280,29 @@ void GPURaytracer::Raytrace(LevelMesh* level) void GPURaytracer::RaytraceProbeSample(LightProbeSample* probe) { - Vec3 color(0.0f, 0.0f, 0.0f); + 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 < SAMPLE_COUNT; i++) + { + const Vec3& normal = directions[i % 6]; + Vec2 Xi = Hammersley(i, SAMPLE_COUNT); + 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)SAMPLE_COUNT / (float)LightBounce; + } for (ThingLight& light : mesh->map->ThingLights) { @@ -298,10 +319,15 @@ void GPURaytracer::RaytraceProbeSample(LightProbeSample* probe) float dist = dir.Unit(); dir.Normalize(); - color += light.rgb * (light.SpotAttenuation(dir) * light.DistAttenuation(dist) * light.intensity); + incoming += light.rgb * (light.SpotAttenuation(dir) * light.DistAttenuation(dist) * light.intensity); } - probe->Color = color; + 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; } void GPURaytracer::RaytraceSurfaceSample(Surface* surface, int x, int y) @@ -330,6 +356,15 @@ void GPURaytracer::RaytraceSurfaceSample(Surface* surface, int x, int y) incoming = incoming + GetSurfaceEmittance(surface, 0.0f) + GetLightEmittance(surface, pos); + const Vec3& sundir = mesh->map->GetSunDirection(); + float attenuation = normal.Dot(sundir); + if (attenuation > 0.0f) + { + LevelTraceHit trace = mesh->Trace(pos, pos + sundir * 32768.0f); + if (trace.fraction != 1.0f && trace.hitSurface->bSky) + incoming += mesh->map->GetSunColor() * attenuation; + } + size_t sampleWidth = surface->lightmapDims[0]; surface->samples[x + y * sampleWidth] = incoming; } @@ -369,20 +404,30 @@ Vec3 GPURaytracer::TracePath(const Vec3& pos, const Vec3& dir, int sampleIndex, if (depth >= LightBounce) return Vec3(0.0f); - LevelTraceHit hit = mesh->Trace(pos, pos + dir * 1000.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 + normal * 0.1f; + 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, SAMPLE_COUNT); Vec3 H = ImportanceSampleGGX(Xi, normal, 1.0f); Vec3 L = Vec3::Normalize(H * (2.0f * Vec3::Dot(normal, H)) - normal); - float NdotL = std::max(Vec3::Dot(normal, L), 0.0f); + float NdotL = Vec3::Dot(normal, L); if (NdotL <= 0.0f) return emittance; @@ -456,9 +501,10 @@ Vec3 GPURaytracer::GetSurfaceEmittance(Surface* surface, float distance) } } - if (def) + if (def && distance < def->distance + def->distance) { - float attenuation = std::max(1.0f - (distance / def->distance), 0.0f); + float radius = def->distance + def->distance; + float attenuation = std::max(1.0f - (distance / radius), 0.0f); return def->rgb * (attenuation * def->intensity); } else diff --git a/src/lightmap/gpuraytracer.h b/src/lightmap/gpuraytracer.h index 0f31a7d..e056e35 100644 --- a/src/lightmap/gpuraytracer.h +++ b/src/lightmap/gpuraytracer.h @@ -47,7 +47,7 @@ private: static Vec2 Hammersley(uint32_t i, uint32_t N); static Vec3 ImportanceSampleGGX(Vec2 Xi, Vec3 N, float roughness); - int SAMPLE_COUNT = 1024;// 128;// 1024; + int SAMPLE_COUNT = 1024; LevelMesh* mesh = nullptr; diff --git a/src/lightmap/raytracer.cpp b/src/lightmap/raytracer.cpp index 6f2b137..dc172c2 100644 --- a/src/lightmap/raytracer.cpp +++ b/src/lightmap/raytracer.cpp @@ -13,7 +13,6 @@ #include #include -extern int Multisample; extern int LightBounce; extern float GridSize; @@ -71,7 +70,29 @@ void Raytracer::Raytrace(LevelMesh* level) void Raytracer::RaytraceProbeSample(LightProbeSample* probe) { - Vec3 color(0.0f, 0.0f, 0.0f); + 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 < SAMPLE_COUNT; i++) + { + const Vec3& normal = directions[i % 6]; + Vec2 Xi = Hammersley(i, SAMPLE_COUNT); + 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)SAMPLE_COUNT / (float)LightBounce; + } for (ThingLight& light : mesh->map->ThingLights) { @@ -88,10 +109,15 @@ void Raytracer::RaytraceProbeSample(LightProbeSample* probe) float dist = dir.Unit(); dir.Normalize(); - color += light.rgb * (light.SpotAttenuation(dir) * light.DistAttenuation(dist) * light.intensity); + incoming += light.rgb * (light.SpotAttenuation(dir) * light.DistAttenuation(dist) * light.intensity); } - probe->Color = color; + 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; } void Raytracer::RaytraceSurfaceSample(Surface* surface, int x, int y) @@ -120,6 +146,15 @@ void Raytracer::RaytraceSurfaceSample(Surface* surface, int x, int y) incoming = incoming + GetSurfaceEmittance(surface, 0.0f) + GetLightEmittance(surface, pos); + const Vec3& sundir = mesh->map->GetSunDirection(); + float attenuation = normal.Dot(sundir); + if (attenuation > 0.0f) + { + LevelTraceHit trace = mesh->Trace(pos, pos + sundir * 32768.0f); + if (trace.fraction != 1.0f && trace.hitSurface->bSky) + incoming += mesh->map->GetSunColor() * attenuation; + } + size_t sampleWidth = surface->lightmapDims[0]; surface->samples[x + y * sampleWidth] = incoming; } @@ -159,20 +194,30 @@ Vec3 Raytracer::TracePath(const Vec3& pos, const Vec3& dir, int sampleIndex, int if (depth >= LightBounce) return Vec3(0.0f); - LevelTraceHit hit = mesh->Trace(pos, pos + dir * 1000.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 + normal * 0.1f; + 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, SAMPLE_COUNT); Vec3 H = ImportanceSampleGGX(Xi, normal, 1.0f); Vec3 L = Vec3::Normalize(H * (2.0f * Vec3::Dot(normal, H)) - normal); - float NdotL = std::max(Vec3::Dot(normal, L), 0.0f); + float NdotL = Vec3::Dot(normal, L); if (NdotL <= 0.0f) return emittance; @@ -246,9 +291,10 @@ Vec3 Raytracer::GetSurfaceEmittance(Surface* surface, float distance) } } - if (def) + if (def && distance < def->distance + def->distance) { - float attenuation = std::max(1.0f - (distance / def->distance), 0.0f); + float radius = def->distance + def->distance; + float attenuation = std::max(1.0f - (distance / radius), 0.0f); return def->rgb * (attenuation * def->intensity); } else diff --git a/src/lightmap/raytracer.h b/src/lightmap/raytracer.h index 0ffefda..82efbaf 100644 --- a/src/lightmap/raytracer.h +++ b/src/lightmap/raytracer.h @@ -23,7 +23,7 @@ private: static Vec2 Hammersley(uint32_t i, uint32_t N); static Vec3 ImportanceSampleGGX(Vec2 Xi, Vec3 N, float roughness); - int SAMPLE_COUNT = 1024;// 128;// 1024; + int SAMPLE_COUNT = 1024; LevelMesh* mesh = nullptr; }; diff --git a/src/main.cpp b/src/main.cpp index 50c0ad5..1a5a824 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -506,7 +506,7 @@ static void ShowUsage() " -P, --no-polyobjs Do not check for polyobject subsector splits\n" " -j, --threads=NNN Number of threads used for raytracing (default %d)\n" " -Q, --samples=NNN Set texel sampling size (lowest = higher quaility but\n" - " slow compile time) must be in powers of two\n" + " slow compile time) must be in powers of two (default %d)\n" " -S, --size=NNN lightmap texture dimensions for width and height\n" " must be in powers of two (1, 2, 4, 8, 16, etc)\n" " -M, --multisample=NNN Number of samples to use per texel (default %d)\n"