Move sample distance, bounces and light probe grid size settings to the zdrayinfo actor as they affect map visuals

This commit is contained in:
Magnus Norddahl 2021-11-11 05:51:00 +01:00
parent cd3563759c
commit 031dc4a4db
8 changed files with 62 additions and 61 deletions

View file

@ -1,13 +1,29 @@
# ZDRay baking utility for GZDoom
ZDRay is a node and lightmap generator. It is based on zdbsp for the node generation and dlight for the lightmap generation.
ZDRay is a node and lightmap generator for GZDoom. ZDRay is intended as a drop-in replacement for zdbsp, with the additional feature
that it can also bake lights. Once ZDRay has processed the level WAD it is ready to be used by GZDoom.
Special thanks to Randi Heit, Samuel Villarreal, Christoph Oelckers and anyone else involved in creating or maintaining those tools.
ZDRay is based on zdbsp for the node generation and originally used dlight for the lightmap generation. Special thanks to Randi Heit,
Samuel Villarreal, Christoph Oelckers and anyone else involved in creating or maintaining those tools.
The ray tracing code has been completely rewritten since. It now supports bounces and can do the ray tracing on the GPU.
## ZDRay UDMF properties
<pre>
thing // ZDRayInfo (zdray properties for the map)
{
type = 9890;
suncolor = &lt;int&gt; (color)
sundirx = &lt;float&gt; (X direction for the sun)
sundiry = &lt;float&gt; (Y direction for the sun)
sundirz = &lt;float&gt; (Z direction for the sun)
sampledistance = &lt;int&gt; (default: 8, map units each lightmap texel covers, must be in powers of two)
bounces = &lt;int&gt; (default: 1, how many times light bounces off walls)
gridsize = &lt;float&gt; (default: 32, grid density for the automatic light probes)
}
thing // StaticLight (point or spot light to be baked into the lightmap)
{
lightcolor = &lt;int&gt; (color)
@ -22,23 +38,14 @@ thing // LightProbe (light sampling point for actors)
type = 9875;
}
thing // Sunlight (sunlight properties for the map)
{
type = 9890;
suncolor = &lt;int&gt; (color)
sundirx = &lt;float&gt; (X direction for the sun)
sundiry = &lt;float&gt; (Y direction for the sun)
sundirz = &lt;float&gt; (Z direction for the sun)
}
linedef // Line surface emitting
linedef // Line emissive surface
{
lightcolor = &lt;int&gt; (color, default: white)
lightintensity = &lt;float&gt; (default: 1)
lightdistance = &lt;float&gt; (default: 0, no light)
}
sector // Sector planes emitting light
sector // Sector plane emissive surface
{
lightcolorfloor = &lt;int&gt; (color, default: white)
lightintensityfloor = &lt;float&gt; (default: 1)

View file

@ -387,8 +387,11 @@ struct FLevel
TArray<SurfaceLightDef> SurfaceLights;
TArray<int> ThingLightProbes;
Vec3 defaultSunColor = Vec3(1, 1, 1);
Vec3 defaultSunDirection = Vec3(0.45f, 0.3f, 0.9f);
Vec3 defaultSunColor;
Vec3 defaultSunDirection;
int Samples;
int LightBounce;
float GridSize;
void FindMapBounds ();
void RemoveExtraLines ();

View file

@ -30,7 +30,6 @@
#endif
extern int LMDims;
extern int Samples;
extern bool CPURaytrace;
extern void ShowView (FLevel *level);
@ -693,7 +692,7 @@ void FProcessor::BuildNodes()
void FProcessor::BuildLightmaps()
{
Level.SetupLights();
LightmapMesh = std::make_unique<LevelMesh>(Level, Samples, LMDims);
LightmapMesh = std::make_unique<LevelMesh>(Level, Level.Samples, LMDims);
if (CPURaytrace)
{

View file

@ -84,6 +84,13 @@ void FLevel::SetupLights()
}
}
// GG to whoever memset'ed FLevel
defaultSunColor = Vec3(1, 1, 1);
defaultSunDirection = Vec3(0.45f, 0.3f, 0.9f);
Samples = 8;
LightBounce = 1;
GridSize = 32.0f;
for (int i = 0; i < (int)Things.Size(); ++i)
{
IntThing* thing = &Things[i];
@ -91,7 +98,7 @@ void FLevel::SetupLights()
{
ThingLightProbes.Push(i);
}
else if (thing->type == 9890) // Sunlight
else if (thing->type == 9890) // ZDRayInfo
{
uint32_t lightcolor = 0xffffff;
Vec3 sundir(0.0f, 0.0f, 0.0f);
@ -116,6 +123,25 @@ void FLevel::SetupLights()
{
sundir.z = atof(key.value);
}
else if (!stricmp(key.key, "sampledistance"))
{
Samples = atoi(key.value);
if (Samples <= 0) Samples = 1;
if (Samples > 128) Samples = 128;
Samples = Math::RoundPowerOfTwo(Samples);
}
else if (!stricmp(key.key, "bounces"))
{
LightBounce = atoi(key.value);
if (LightBounce < 0) LightBounce = 0;
if (LightBounce > 8) LightBounce = 8;
}
else if (!stricmp(key.key, "gridsize"))
{
GridSize = atof(key.value);
if (GridSize < 0.f) GridSize = 0.f;
if (GridSize > 1024.f) GridSize = 1024.f;
}
}
if (Vec3::Dot(sundir, sundir) > 0.01f)

View file

@ -12,7 +12,6 @@
#include <algorithm>
#include <zlib.h>
extern int LightBounce;
extern bool VKDebug;
CPURaytracer::CPURaytracer()
@ -59,7 +58,7 @@ void CPURaytracer::Raytrace(LevelMesh* level)
CreateHemisphereVectors();
CreateLights();
printf("Ray tracing with %d bounce(s)\n", LightBounce);
printf("Ray tracing with %d bounce(s)\n", mesh->map->LightBounce);
Worker::RunJob((int)tasks.size(), [=](int id) { RaytraceTask(tasks[id]); });
@ -107,7 +106,7 @@ void CPURaytracer::RaytraceTask(const CPUTraceTask& task)
state.HemisphereVec = HemisphereVectors[state.SampleIndex];
RunBounceTrace(state);
for (int bounce = 0; bounce < LightBounce && !state.EndTrace; bounce++)
for (int bounce = 0; bounce < mesh->map->LightBounce && !state.EndTrace; bounce++)
{
state.SampleCount = coverageSampleCount;
RunLightTrace(state);

View file

@ -21,7 +21,6 @@
#include "glsl_rmiss_light.h"
#include "glsl_rmiss_sun.h"
extern int LightBounce;
extern bool VKDebug;
GPURaytracer::GPURaytracer()
@ -86,7 +85,7 @@ void GPURaytracer::Raytrace(LevelMesh* level)
HemisphereVectors.push_back(H);
}
printf("Ray tracing with %d bounce(s)\n", LightBounce);
printf("Ray tracing with %d bounce(s)\n", mesh->map->LightBounce);
size_t maxTasks = (size_t)rayTraceImageSize * rayTraceImageSize;
for (size_t startTask = 0; startTask < tasks.size(); startTask += maxTasks)
@ -119,7 +118,7 @@ void GPURaytracer::Raytrace(LevelMesh* level)
uniforms.HemisphereVec = HemisphereVectors[uniforms.SampleIndex];
RunTrace(uniforms, rgenBounceRegion);
for (int bounce = 0; bounce < LightBounce; bounce++)
for (int bounce = 0; bounce < mesh->map->LightBounce; bounce++)
{
uniforms.SampleCount = coverageSampleCount;
RunTrace(uniforms, rgenLightRegion);

View file

@ -34,8 +34,6 @@
#include "pngwriter.h"
#include <map>
extern float GridSize;
#ifdef _MSC_VER
#pragma warning(disable: 4267) // warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
#pragma warning(disable: 4244) // warning C4244: '=': conversion from '__int64' to 'int', possible loss of data
@ -392,12 +390,12 @@ void LevelMesh::CreateLightProbes(FLevel& map)
float maxX = std::floor(map.MaxX / 65536.0f) + 1.0f;
float maxY = std::floor(map.MaxY / 65536.0f) + 1.0f;
float halfGridSize = GridSize * 0.5f;
float doubleGridSize = GridSize * 2.0f;
float halfGridSize = map.GridSize * 0.5f;
float doubleGridSize = map.GridSize * 2.0f;
for (float y = minY; y < maxY; y += GridSize)
for (float y = minY; y < maxY; y += map.GridSize)
{
for (float x = minX; x < maxX; x += GridSize)
for (float x = minX; x < maxX; x += map.GridSize)
{
MapSubsectorEx* ssec = map.PointInSubSector((int)x, (int)y);
IntSector* sec = ssec ? map.GetSectorFromSubSector(ssec) : nullptr;

View file

@ -115,11 +115,8 @@ bool HaveSSE1, HaveSSE2;
int SSELevel;
int NumThreads = 0;
int LMDims = 1024;
int Samples = 8;
bool CPURaytrace = false;
bool VKDebug = false;
int LightBounce = 1;
float GridSize = 32.0f;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
@ -155,16 +152,13 @@ static option long_opts[] =
{"no-sse2", no_argument, 0, 1003},
{"comments", no_argument, 0, 'c'},
{"threads", required_argument, 0, 'j'},
{"samples", required_argument, 0, 'Q'},
{"size", required_argument, 0, 'S'},
{"cpu-raytrace", no_argument, 0, 'C'},
{"bounce", required_argument, 0, 'B'},
{"gridsize", required_argument, 0, 'i'},
{"vkdebug", no_argument, 0, 'D'},
{0,0,0,0}
};
static const char short_opts[] = "wVgGvbNrReEm:o:f:p:s:d:PqtzZXx5cj:Q:S:CD";
static const char short_opts[] = "wVgGvbNrReEm:o:f:p:s:d:PqtzZXx5cj:S:CD";
// CODE --------------------------------------------------------------------
@ -439,12 +433,6 @@ static void ParseArgs(int argc, char **argv)
case 'j':
NumThreads = atoi(optarg);
break;
case 'Q':
Samples = atoi(optarg);
if (Samples <= 0) Samples = 1;
if (Samples > 128) Samples = 128;
Samples = Math::RoundPowerOfTwo(Samples);
break;
case 'S':
LMDims = atoi(optarg);
if (LMDims <= 0) LMDims = 1;
@ -457,15 +445,6 @@ static void ParseArgs(int argc, char **argv)
case 'D':
VKDebug = true;
break;
case 'B':
LightBounce = atoi(optarg);
if (LightBounce < 0) LightBounce = 0;
if (LightBounce > 8) LightBounce = 8;
break;
case 'i':
GridSize = std::stof(optarg);
if (GridSize < 0.f) GridSize = 0.f;
break;
case 1000:
ShowUsage();
exit(0);
@ -508,15 +487,9 @@ static void ShowUsage()
" -d, --diagonal-cost=NNN Cost for avoiding diagonal splitters (default %d)\n"
" -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 (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"
" -C, --cpu-raytrace Use the CPU for ray tracing\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"
" Lower values increase granularity at the expense of performance\n"
" Recommended: 32.0, 64.0, 128.0, etc (default %.1f)\n"
" -D, --vkdebug Print messages from the vulkan validation layer\n"
" -w, --warn Show warning messages\n"
#if HAVE_TIMING
@ -531,9 +504,6 @@ static void ShowUsage()
, SplitCost
, AAPreference
, (int)std::thread::hardware_concurrency()
, Samples
, LightBounce
, GridSize
);
}