Add surface and sunlight to the new CPU ray tracer

This commit is contained in:
Magnus Norddahl 2021-11-05 23:31:23 +01:00
parent 75798fae9b
commit c7b220c2ba
5 changed files with 113 additions and 21 deletions

View file

@ -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

View file

@ -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;

View file

@ -13,7 +13,6 @@
#include <algorithm>
#include <zlib.h>
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

View file

@ -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;
};

View file

@ -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"