mirror of
https://github.com/ZDoom/ZDRay.git
synced 2025-02-03 05:01:00 +00:00
Add a new raytracer that bounces using path tracing
This commit is contained in:
parent
f0c7e5fb9a
commit
47494dd3b2
8 changed files with 315 additions and 42 deletions
|
@ -274,8 +274,14 @@ public:
|
||||||
// returns address of first element
|
// returns address of first element
|
||||||
T* Data() const
|
T* Data() const
|
||||||
{
|
{
|
||||||
return &Array[0];
|
return Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T* begin() { return Array; }
|
||||||
|
T* end() { return Array + Count; }
|
||||||
|
const T* begin() const { return Array; }
|
||||||
|
const T* end() const { return Array + Count; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T *Array;
|
T *Array;
|
||||||
unsigned int Most;
|
unsigned int Most;
|
||||||
|
|
|
@ -179,3 +179,15 @@ T clamp (const T in, const T min, const T max)
|
||||||
{
|
{
|
||||||
return in <= min ? min : in >= max ? max : in;
|
return in <= min ? min : in >= max ? max : in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T smoothstep(const T edge0, const T edge1, const T x)
|
||||||
|
{
|
||||||
|
auto t = clamp<T>((x - edge0) / (edge1 - edge0), T(0.0), T(1.0));
|
||||||
|
return t * t * (T(3.0) - T(2.0) * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float radians(float degrees)
|
||||||
|
{
|
||||||
|
return degrees * 3.14159265359f / 180.0f;
|
||||||
|
}
|
||||||
|
|
|
@ -2,10 +2,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/tarray.h"
|
#include "framework/tarray.h"
|
||||||
|
#include "framework/templates.h"
|
||||||
#include "math/mathlib.h"
|
#include "math/mathlib.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <cmath>
|
||||||
#undef MIN
|
#undef MIN
|
||||||
#undef MAX
|
#undef MAX
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -271,6 +275,44 @@ struct ThingLight
|
||||||
bool bCeiling;
|
bool bCeiling;
|
||||||
IntSector *sector;
|
IntSector *sector;
|
||||||
MapSubsectorEx *ssect;
|
MapSubsectorEx *ssect;
|
||||||
|
|
||||||
|
Vec3 LightOrigin() const
|
||||||
|
{
|
||||||
|
float originZ;
|
||||||
|
if (!bCeiling)
|
||||||
|
originZ = sector->floorplane.zAt(origin.x, origin.y) + height;
|
||||||
|
else
|
||||||
|
originZ = sector->ceilingplane.zAt(origin.x, origin.y) - height;
|
||||||
|
return Vec3(origin.x, origin.y, originZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
float LightRadius() const
|
||||||
|
{
|
||||||
|
return radius + radius; // 2.0 because gzdoom's dynlights do this and we want them to match
|
||||||
|
}
|
||||||
|
|
||||||
|
float SpotAttenuation(const Vec3& dir) const
|
||||||
|
{
|
||||||
|
float spotAttenuation = 1.0f;
|
||||||
|
if (outerAngleCos > -1.0f)
|
||||||
|
{
|
||||||
|
float negPitch = -radians(mapThing->pitch);
|
||||||
|
float xyLen = std::cos(negPitch);
|
||||||
|
Vec3 spotDir;
|
||||||
|
spotDir.x = -std::cos(radians(mapThing->angle)) * xyLen;
|
||||||
|
spotDir.y = -std::sin(radians(mapThing->angle)) * xyLen;
|
||||||
|
spotDir.z = -std::sin(negPitch);
|
||||||
|
float cosDir = Vec3::Dot(dir, spotDir);
|
||||||
|
spotAttenuation = smoothstep(outerAngleCos, innerAngleCos, cosDir);
|
||||||
|
spotAttenuation = std::max(spotAttenuation, 0.0f);
|
||||||
|
}
|
||||||
|
return spotAttenuation;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DistAttenuation(float distance) const
|
||||||
|
{
|
||||||
|
return std::max(1.0f - (distance / LightRadius()), 0.0f);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SurfaceLightDef
|
struct SurfaceLightDef
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "level/level.h"
|
#include "level/level.h"
|
||||||
#include "lightmap/lightmap.h"
|
#include "lightmap/lightmap.h"
|
||||||
|
#include "lightmap/raytracer.h"
|
||||||
//#include "rejectbuilder.h"
|
//#include "rejectbuilder.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -690,8 +691,13 @@ void FProcessor::BuildLightmaps()
|
||||||
{
|
{
|
||||||
Level.SetupLights();
|
Level.SetupLights();
|
||||||
LightmapMesh = std::make_unique<LevelMesh>(Level, Samples, LMDims);
|
LightmapMesh = std::make_unique<LevelMesh>(Level, Samples, LMDims);
|
||||||
|
#if 1
|
||||||
DLightRaytracer raytracer;
|
DLightRaytracer raytracer;
|
||||||
raytracer.Raytrace(LightmapMesh.get());
|
raytracer.Raytrace(LightmapMesh.get());
|
||||||
|
#else
|
||||||
|
Raytracer raytracer;
|
||||||
|
raytracer.Raytrace(LightmapMesh.get());
|
||||||
|
#endif
|
||||||
LightmapMesh->CreateTextures();
|
LightmapMesh->CreateTextures();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,18 +121,6 @@ bool DLightRaytracer::EmitFromCeiling(const Surface *surface, const Vec3 &origin
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T smoothstep(const T edge0, const T edge1, const T x)
|
|
||||||
{
|
|
||||||
auto t = clamp<T>((x - edge0) / (edge1 - edge0), 0.0, 1.0);
|
|
||||||
return t * t * (3.0 - 2.0 * t);
|
|
||||||
}
|
|
||||||
|
|
||||||
static float radians(float degrees)
|
|
||||||
{
|
|
||||||
return degrees * 3.14159265359f / 180.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Traces a line from the texel's origin to the sunlight direction and against all nearby thing lights
|
// Traces a line from the texel's origin to the sunlight direction and against all nearby thing lights
|
||||||
Vec3 DLightRaytracer::LightTexelSample(const Vec3 &origin, Surface *surface)
|
Vec3 DLightRaytracer::LightTexelSample(const Vec3 &origin, Surface *surface)
|
||||||
{
|
{
|
||||||
|
@ -147,13 +135,7 @@ Vec3 DLightRaytracer::LightTexelSample(const Vec3 &origin, Surface *surface)
|
||||||
{
|
{
|
||||||
ThingLight *tl = &mesh->map->ThingLights[i];
|
ThingLight *tl = &mesh->map->ThingLights[i];
|
||||||
|
|
||||||
float originZ;
|
Vec3 lightOrigin = tl->LightOrigin();
|
||||||
if (!tl->bCeiling)
|
|
||||||
originZ = tl->sector->floorplane.zAt(tl->origin.x, tl->origin.y) + tl->height;
|
|
||||||
else
|
|
||||||
originZ = tl->sector->ceilingplane.zAt(tl->origin.x, tl->origin.y) - tl->height;
|
|
||||||
|
|
||||||
Vec3 lightOrigin(tl->origin.x, tl->origin.y, originZ);
|
|
||||||
|
|
||||||
if (surface && plane.Distance(lightOrigin) - plane.d < 0)
|
if (surface && plane.Distance(lightOrigin) - plane.d < 0)
|
||||||
{
|
{
|
||||||
|
@ -161,8 +143,7 @@ Vec3 DLightRaytracer::LightTexelSample(const Vec3 &origin, Surface *surface)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float radius = tl->radius * 2.0f; // 2.0 because gzdoom's dynlights do this and we want them to match
|
float radius = tl->LightRadius();
|
||||||
float intensity = tl->intensity;
|
|
||||||
|
|
||||||
if (origin.DistanceSq(lightOrigin) > (radius*radius))
|
if (origin.DistanceSq(lightOrigin) > (radius*radius))
|
||||||
{
|
{
|
||||||
|
@ -174,23 +155,9 @@ Vec3 DLightRaytracer::LightTexelSample(const Vec3 &origin, Surface *surface)
|
||||||
float dist = dir.Unit();
|
float dist = dir.Unit();
|
||||||
dir.Normalize();
|
dir.Normalize();
|
||||||
|
|
||||||
float spotAttenuation = 1.0f;
|
float spotAttenuation = tl->SpotAttenuation(dir);
|
||||||
if (tl->outerAngleCos > -1.0f)
|
if (spotAttenuation == 0.0f)
|
||||||
{
|
|
||||||
float negPitch = -radians(tl->mapThing->pitch);
|
|
||||||
float xyLen = std::cos(negPitch);
|
|
||||||
Vec3 spotDir;
|
|
||||||
spotDir.x = -std::cos(radians(tl->mapThing->angle)) * xyLen;
|
|
||||||
spotDir.y = -std::sin(radians(tl->mapThing->angle)) * xyLen;
|
|
||||||
spotDir.z = -std::sin(negPitch);
|
|
||||||
float cosDir = Vec3::Dot(dir, spotDir);
|
|
||||||
spotAttenuation = smoothstep(tl->outerAngleCos, tl->innerAngleCos, cosDir);
|
|
||||||
if (spotAttenuation <= 0.0f)
|
|
||||||
{
|
|
||||||
// outside spot light
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mesh->TraceAnyHit(lightOrigin, origin))
|
if (mesh->TraceAnyHit(lightOrigin, origin))
|
||||||
{
|
{
|
||||||
|
@ -202,7 +169,7 @@ Vec3 DLightRaytracer::LightTexelSample(const Vec3 &origin, Surface *surface)
|
||||||
attenuation *= spotAttenuation;
|
attenuation *= spotAttenuation;
|
||||||
if (surface)
|
if (surface)
|
||||||
attenuation *= plane.Normal().Dot(dir);
|
attenuation *= plane.Normal().Dot(dir);
|
||||||
attenuation *= intensity;
|
attenuation *= tl->intensity;
|
||||||
|
|
||||||
// accumulate results
|
// accumulate results
|
||||||
color += tl->rgb * attenuation;
|
color += tl->rgb * attenuation;
|
||||||
|
|
|
@ -28,4 +28,231 @@ Raytracer::~Raytracer()
|
||||||
void Raytracer::Raytrace(LevelMesh* level)
|
void Raytracer::Raytrace(LevelMesh* level)
|
||||||
{
|
{
|
||||||
mesh = level;
|
mesh = level;
|
||||||
|
|
||||||
|
printf("Tracing light probes\n");
|
||||||
|
|
||||||
|
Worker::RunJob((int)mesh->lightProbes.size(), [=](int id) {
|
||||||
|
RaytraceProbeSample(&mesh->lightProbes[id]);
|
||||||
|
});
|
||||||
|
|
||||||
|
printf("Tracing surfaces (%d bounces)\n", LightBounce);
|
||||||
|
|
||||||
|
struct SurfaceTask
|
||||||
|
{
|
||||||
|
int surf, x, y;
|
||||||
|
};
|
||||||
|
std::vector<SurfaceTask> tasks;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mesh->surfaces.size(); i++)
|
||||||
|
{
|
||||||
|
Surface* surface = mesh->surfaces[i].get();
|
||||||
|
int sampleWidth = surface->lightmapDims[0];
|
||||||
|
int sampleHeight = surface->lightmapDims[1];
|
||||||
|
for (int y = 0; y < sampleHeight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < sampleWidth; x++)
|
||||||
|
{
|
||||||
|
SurfaceTask task;
|
||||||
|
task.surf = (int)i;
|
||||||
|
task.x = x;
|
||||||
|
task.y = y;
|
||||||
|
tasks.push_back(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Worker::RunJob((int)tasks.size(), [=](int id) {
|
||||||
|
const SurfaceTask& task = tasks[id];
|
||||||
|
RaytraceSurfaceSample(mesh->surfaces[task.surf].get(), task.x, task.y);
|
||||||
|
});
|
||||||
|
|
||||||
|
printf("Raytrace complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Raytracer::RaytraceProbeSample(LightProbeSample* probe)
|
||||||
|
{
|
||||||
|
Vec3 color(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
color += light.rgb * (light.SpotAttenuation(dir) * light.DistAttenuation(dist) * light.intensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
probe->Color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Raytracer::RaytraceSurfaceSample(Surface* surface, int x, int y)
|
||||||
|
{
|
||||||
|
Vec3 normal = surface->plane.Normal();
|
||||||
|
Vec3 pos = surface->lightmapOrigin + normal + surface->lightmapSteps[0] * (float)x + surface->lightmapSteps[1] * (float)y;
|
||||||
|
|
||||||
|
Vec3 incoming(0.0f, 0.0f, 0.0f);
|
||||||
|
if (LightBounce > 0)
|
||||||
|
{
|
||||||
|
float totalWeight = 0.0f;
|
||||||
|
for (int i = 0; i < SAMPLE_COUNT; i++)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
float NdotL = std::max(Vec3::Dot(normal, L), 0.0f);
|
||||||
|
if (NdotL > 0.0f)
|
||||||
|
{
|
||||||
|
incoming += TracePath(pos, L, i) * NdotL;
|
||||||
|
totalWeight += NdotL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
incoming = incoming / totalWeight / (float)LightBounce;
|
||||||
|
}
|
||||||
|
|
||||||
|
incoming = incoming + GetSurfaceEmittance(surface, 0.0f) + GetLightEmittance(surface, pos);
|
||||||
|
|
||||||
|
size_t sampleWidth = surface->lightmapDims[0];
|
||||||
|
surface->samples[x + y * sampleWidth] = incoming;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 Raytracer::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 Raytracer::TracePath(const Vec3& pos, const Vec3& dir, int sampleIndex, int depth)
|
||||||
|
{
|
||||||
|
if (depth >= LightBounce)
|
||||||
|
return Vec3(0.0f);
|
||||||
|
|
||||||
|
LevelTraceHit hit = mesh->Trace(pos, pos + dir * 1000.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 emittance = GetSurfaceEmittance(hit.hitSurface, pos.Distance(hitpos)) + GetLightEmittance(hit.hitSurface, hitpos) * 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);
|
||||||
|
if (NdotL <= 0.0f)
|
||||||
|
return emittance;
|
||||||
|
|
||||||
|
const float p = 1 / (2 * M_PI);
|
||||||
|
Vec3 incoming = TracePath(hitpos, normal, (sampleIndex + depth + 1) % SAMPLE_COUNT, depth + 1);
|
||||||
|
|
||||||
|
return emittance + incoming * NdotL / p;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Raytracer::RadicalInverse_VdC(uint32_t 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 Raytracer::Hammersley(uint32_t i, uint32_t N)
|
||||||
|
{
|
||||||
|
return Vec2(float(i) / float(N), RadicalInverse_VdC(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 Raytracer::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 Raytracer::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)
|
||||||
|
{
|
||||||
|
float attenuation = std::max(1.0f - (distance / def->distance), 0.0f);
|
||||||
|
return def->rgb * (attenuation * def->intensity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Vec3(0.0f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,5 +12,18 @@ public:
|
||||||
void Raytrace(LevelMesh* level);
|
void Raytrace(LevelMesh* level);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void RaytraceProbeSample(LightProbeSample* probe);
|
||||||
|
void RaytraceSurfaceSample(Surface* surface, int x, int y);
|
||||||
|
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);
|
||||||
|
|
||||||
|
int SAMPLE_COUNT = 1024;// 128;// 1024;
|
||||||
|
|
||||||
LevelMesh* mesh = nullptr;
|
LevelMesh* mesh = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -457,7 +457,7 @@ static void ParseArgs(int argc, char **argv)
|
||||||
case 'B':
|
case 'B':
|
||||||
LightBounce = atoi(optarg);
|
LightBounce = atoi(optarg);
|
||||||
if (LightBounce < 0) LightBounce = 0;
|
if (LightBounce < 0) LightBounce = 0;
|
||||||
if (LightBounce > 1) LightBounce = 1;
|
if (LightBounce > 8) LightBounce = 8;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
GridSize = std::stof(optarg);
|
GridSize = std::stof(optarg);
|
||||||
|
@ -510,7 +510,7 @@ static void ShowUsage()
|
||||||
" -S, --size=NNN lightmap texture dimensions for width and height\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"
|
" 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"
|
" -M, --multisample=NNN Number of samples to use per texel (default %d)\n"
|
||||||
" -B, --bounce=NNN Number of indirect light bounces (default %d, max 1)\n"
|
" -B, --bounce=NNN Number of indirect light bounces (default %d, max 8)\n"
|
||||||
" -i, --gridsize=NNN Automatic light probe grid size, floating point\n"
|
" -i, --gridsize=NNN Automatic light probe grid size, floating point\n"
|
||||||
" Lower values increase granularity at the expense of performance\n"
|
" Lower values increase granularity at the expense of performance\n"
|
||||||
" Recommended: 32.0, 64.0, 128.0, etc (default %.1f)\n"
|
" Recommended: 32.0, 64.0, 128.0, etc (default %.1f)\n"
|
||||||
|
|
Loading…
Reference in a new issue