add portals/midtextures to ray-traced dynamic lights

This commit is contained in:
Ricardo Luís Vaz Silva 2024-12-30 15:32:19 -03:00 committed by Magnus Norddahl
commit 728b6c0039
15 changed files with 168 additions and 178 deletions

View file

@ -130,7 +130,7 @@ CVAR(Bool, gl_precache, true, CVAR_ARCHIVE)
CUSTOM_CVAR(Int, gl_light_shadows, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (self < 0 || self > 3)
if (self < 0 || self > 4)
self = 1;
}

View file

@ -154,9 +154,14 @@ void VkDescriptorSetManager::UpdateFixedSet()
else
{
update.AddBuffer(Fixed.Set.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetNodeBuffer());
update.AddBuffer(Fixed.Set.get(), 6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetVertexBuffer());
update.AddBuffer(Fixed.Set.get(), 7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetIndexBuffer());
}
update.AddBuffer(Fixed.Set.get(), 6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetVertexBuffer());
update.AddBuffer(Fixed.Set.get(), 7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetIndexBuffer());
update.AddBuffer(Fixed.Set.get(), 8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetSurfaceIndexBuffer());
update.AddBuffer(Fixed.Set.get(), 9, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetSurfaceBuffer());
update.AddBuffer(Fixed.Set.get(), 10, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetPortalBuffer());
update.Execute(fb->GetDevice());
}
@ -280,9 +285,12 @@ void VkDescriptorSetManager::CreateFixedLayout()
else
{
builder.AddBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
builder.AddBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
builder.AddBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
}
builder.AddBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
builder.AddBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
builder.AddBinding(8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
builder.AddBinding(9, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
builder.AddBinding(10, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
builder.DebugName("VkDescriptorSetManager.Fixed.SetLayout");
Fixed.Layout = builder.Create(fb->GetDevice());
}

View file

@ -255,6 +255,7 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername
if (key.Glowmap) definesBlock << "#define TEXF_Glowmap\n";
if (key.UseRaytrace) definesBlock << "#define USE_RAYTRACE\n";
if (key.UseRaytracePrecise) definesBlock << "#define USE_RAYTRACE_PRECISE\n";
if (key.UseShadowmap) definesBlock << "#define USE_SHADOWMAP\n";
if (key.UseLevelMesh) definesBlock << "#define USE_LEVELMESH\n";

View file

@ -100,7 +100,8 @@ public:
uint64_t AlphaTestOnly : 1; // ALPHATEST_ONLY
uint64_t LightBlendMode : 2; // LIGHT_BLEND_CLAMPED , LIGHT_BLEND_COLORED_CLAMP , LIGHT_BLEND_UNCLAMPED
uint64_t LightAttenuationMode : 1; // LIGHT_ATTENUATION_LINEAR , LIGHT_ATTENUATION_INVERSE_SQUARE
uint64_t Unused : 37;
uint64_t UseRaytracePrecise : 1; // USE_RAYTRACE_PRECISE
uint64_t Unused : 36;
};
uint64_t AsQWORD = 0;
};

View file

@ -303,7 +303,8 @@ void VkRenderState::ApplyRenderPass(int dt)
}
pipelineKey.ShaderKey.UseShadowmap = gl_light_shadows == 1;
pipelineKey.ShaderKey.UseRaytrace = gl_light_shadows == 2;
pipelineKey.ShaderKey.UseRaytrace = gl_light_shadows >= 2;
pipelineKey.ShaderKey.UseRaytracePrecise = gl_light_shadows >= 3;
pipelineKey.ShaderKey.GBufferPass = mRenderTarget.DrawBuffers > 1;
@ -1066,7 +1067,8 @@ void VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPip
// Global state that don't require rebuilding the mesh
pipelineKey.ShaderKey.NoFragmentShader = noFragmentShader;
pipelineKey.ShaderKey.UseShadowmap = gl_light_shadows == 1;
pipelineKey.ShaderKey.UseRaytrace = gl_light_shadows == 2;
pipelineKey.ShaderKey.UseRaytrace = gl_light_shadows >= 2;
pipelineKey.ShaderKey.UseRaytracePrecise = gl_light_shadows >= 3;
pipelineKey.ShaderKey.GBufferPass = mRenderTarget.DrawBuffers > 1;
// State overridden by the renderstate drawing the mesh

View file

@ -239,7 +239,7 @@ struct FDynamicLight
bool IsSpot() const { return !!((*pLightFlags) & LF_SPOT); }
bool IsAttenuated() const { return !!((*pLightFlags) & LF_ATTENUATE); }
bool Trace() const { return !!((*pLightFlags) & (LF_TRACE)); }
bool TraceActors() const { return Trace() || gl_light_shadows == 2; }
bool TraceActors() const { return Trace() || gl_light_shadows >= 2; }
bool DontShadowmap() const { return !!((*pLightFlags) & LF_NOSHADOWMAP); }
bool DontLightSelf() const { return !!((*pLightFlags) & (LF_DONTLIGHTSELF|LF_DONTLIGHTACTORS)); } // dontlightactors implies dontlightself.
bool DontLightActors() const { return !!((*pLightFlags) & LF_DONTLIGHTACTORS); }

View file

@ -2715,6 +2715,7 @@ OptionValue ShadowMode
0, "$OPTVAL_NONE"
1, "$OPTVAL_SHADOWMAP"
2, "$OPTVAL_RAYTRACE"
3, "$OPTVAL_RAYTRACE_PRECISE"
}
OptionValue ShadowFilter

View file

@ -1,3 +1,4 @@
#include <shaders/lightmap/binding_struct_definitions.glsl>
layout(set = 0, binding = 0) uniform readonly Uniforms
{
@ -7,63 +8,10 @@ layout(set = 0, binding = 0) uniform readonly Uniforms
float SunIntensity;
};
struct SurfaceInfo
{
vec3 Normal;
float Sky;
uint PortalIndex;
int TextureIndex;
float Alpha;
float Padding0;
uint LightStart;
uint LightEnd;
uint Padding1;
uint Padding2;
};
struct PortalInfo
{
mat4 Transformation;
};
struct LightInfo
{
vec3 Origin;
float Padding0;
vec3 RelativeOrigin;
float Padding1;
float Radius;
float Intensity;
float InnerAngleCos;
float OuterAngleCos;
vec3 SpotDir;
float SoftShadowRadius;
vec3 Color;
float Padding3;
};
layout(set = 0, binding = 1) buffer readonly SurfaceIndexBuffer { uint surfaceIndices[]; };
layout(set = 0, binding = 2) buffer readonly SurfaceBuffer { SurfaceInfo surfaces[]; };
layout(set = 0, binding = 3) buffer readonly LightBuffer { LightInfo lights[]; };
layout(set = 0, binding = 4) buffer readonly LightIndexBuffer { int lightIndexes[]; };
layout(set = 0, binding = 5) buffer readonly PortalBuffer { PortalInfo portals[]; };
struct LightmapRaytracePC
{
int SurfaceIndex;
int Padding0;
int Padding1;
int Padding2;
vec3 WorldToLocal;
float TextureSize;
vec3 ProjLocalToU;
float Padding3;
vec3 ProjLocalToV;
float Padding4;
float TileX;
float TileY;
float TileWidth;
float TileHeight;
};
layout(std430, set = 0, binding = 6) buffer readonly ConstantsBuffer { LightmapRaytracePC constants[]; };

View file

@ -1,3 +1,4 @@
#include <shaders/lightmap/binding_struct_definitions.glsl>
#if defined(USE_RAYQUERY)
@ -5,18 +6,6 @@ layout(set = 1, binding = 0) uniform accelerationStructureEXT acc;
#else
struct CollisionNode
{
vec3 center;
float padding1;
vec3 extents;
float padding2;
int left;
int right;
int element_index;
int padding3;
};
layout(std430, set = 1, binding = 0) buffer readonly NodeBuffer
{
int nodesRoot;
@ -28,13 +17,5 @@ layout(std430, set = 1, binding = 0) buffer readonly NodeBuffer
#endif
struct SurfaceVertex // Note: this must always match the FFlatVertex struct
{
vec3 pos;
float lindex;
vec2 uv;
vec2 luv;
};
layout(std430, set = 1, binding = 1) buffer readonly VertexBuffer { SurfaceVertex vertices[]; };
layout(std430, set = 1, binding = 2) buffer readonly ElementBuffer { int elements[]; };

View file

@ -0,0 +1,73 @@
struct SurfaceInfo
{
vec3 Normal;
float Sky;
uint PortalIndex;
int TextureIndex;
float Alpha;
float Padding0;
uint LightStart;
uint LightEnd;
uint Padding1;
uint Padding2;
};
struct PortalInfo
{
mat4 Transformation;
};
struct LightInfo
{
vec3 Origin;
float Padding0;
vec3 RelativeOrigin;
float Padding1;
float Radius;
float Intensity;
float InnerAngleCos;
float OuterAngleCos;
vec3 SpotDir;
float SoftShadowRadius;
vec3 Color;
float Padding3;
};
struct CollisionNode
{
vec3 center;
float padding1;
vec3 extents;
float padding2;
int left;
int right;
int element_index;
int padding3;
};
struct SurfaceVertex // Note: this must always match the FFlatVertex struct
{
vec3 pos;
float lindex;
vec2 uv;
vec2 luv;
};
struct LightmapRaytracePC
{
int SurfaceIndex;
int Padding0;
int Padding1;
int Padding2;
vec3 WorldToLocal;
float TextureSize;
vec3 ProjLocalToU;
float Padding3;
vec3 ProjLocalToV;
float Padding4;
float TileX;
float TileY;
float TileWidth;
float TileHeight;
};

View file

@ -1,38 +1,4 @@
struct SurfaceInfo
{
vec3 Normal;
float Sky;
uint PortalIndex;
int TextureIndex;
float Alpha;
float Padding0;
uint LightStart;
uint LightEnd;
uint Padding1;
uint Padding2;
};
struct PortalInfo
{
mat4 Transformation;
};
struct LightInfo
{
vec3 Origin;
float Padding0;
vec3 RelativeOrigin;
float Padding1;
float Radius;
float Intensity;
float InnerAngleCos;
float OuterAngleCos;
vec3 SpotDir;
float SoftShadowRadius;
vec3 Color;
float Padding3;
};
#include <shaders/lightmap/binding_struct_definitions.glsl>
layout(set = 0, binding = 0, std430) buffer readonly SurfaceIndexBuffer { uint surfaceIndices[]; };
layout(set = 0, binding = 1, std430) buffer readonly SurfaceBuffer { SurfaceInfo surfaces[]; };
@ -46,18 +12,6 @@ layout(set = 0, binding = 5) uniform accelerationStructureEXT acc;
#else
struct CollisionNode
{
vec3 center;
float padding1;
vec3 extents;
float padding2;
int left;
int right;
int element_index;
int padding3;
};
layout(set = 0, binding = 5, std430) buffer readonly NodeBuffer
{
int nodesRoot;
@ -69,14 +23,6 @@ layout(set = 0, binding = 5, std430) buffer readonly NodeBuffer
#endif
struct SurfaceVertex // Note: this must always match the FFlatVertex struct
{
vec3 pos;
float lindex;
vec2 uv;
vec2 luv;
};
layout(set = 0, binding = 6, std430) buffer readonly VertexBuffer { SurfaceVertex vertices[]; };
layout(set = 0, binding = 7, std430) buffer readonly ElementBuffer { int elements[]; };

View file

@ -277,8 +277,3 @@ TraceResult TraceFirstHit(vec3 origin, float tmin, vec3 dir, float tmax)
}
#endif
bool traceHit(vec3 origin, vec3 direction, float dist)
{
return TraceAnyHit(origin, 0.01f, direction, dist);
}

View file

@ -37,6 +37,21 @@ vec3 PassRayThroughSurface(SurfaceInfo surface, vec2 uv, vec3 rayColor)
}
}
float PassRayThroughSurfaceDynLight(SurfaceInfo surface, vec2 uv, float rayAlpha)
{
if (surface.TextureIndex == 0)
{
return rayAlpha;
}
else
{
vec4 color = texture(textures[surface.TextureIndex], uv);
// Assume the renderstyle is basic alpha blend for now.
return rayAlpha * (1.0 - color.a * surface.Alpha);
}
}
void TransformRay(uint portalIndex, inout vec3 origin, inout vec3 dir)
{
mat4 transformationMatrix = portals[portalIndex].Transformation;

View file

@ -1,3 +1,4 @@
#include <shaders/lightmap/binding_struct_definitions.glsl>
layout(set = 0, binding = 0) uniform sampler2D ShadowMap;
layout(set = 0, binding = 1) uniform sampler2DArray LightMap;
@ -7,20 +8,12 @@ layout(set = 0, binding = 4) uniform samplerCubeArray PrefilterMap;
#if defined(USE_RAYTRACE)
#if defined(SUPPORTS_RAYQUERY)
layout(set = 0, binding = 5) uniform accelerationStructureEXT acc;
#else
struct CollisionNode
{
vec3 center;
float padding1;
vec3 extents;
float padding2;
int left;
int right;
int element_index;
int padding3;
};
layout(std430, set = 0, binding = 5) buffer readonly NodeBuffer
layout(set = 0, binding = 5, std430) buffer readonly NodeBuffer
{
int nodesRoot;
int nodebufferPadding1;
@ -28,14 +21,12 @@ layout(std430, set = 0, binding = 5) buffer readonly NodeBuffer
int nodebufferPadding3;
CollisionNode nodes[];
};
struct SurfaceVertex // Note: this must always match the FFlatVertex struct
{
vec3 pos;
float lindex;
vec2 uv;
vec2 luv;
};
layout(std430, set = 0, binding = 6) buffer readonly VertexBuffer { SurfaceVertex vertices[]; };
layout(std430, set = 0, binding = 7) buffer readonly ElementBuffer { int elements[]; };
#endif
layout(set = 0, binding = 6, std430) buffer readonly VertexBuffer { SurfaceVertex vertices[]; };
layout(set = 0, binding = 7, std430) buffer readonly ElementBuffer { int elements[]; };
layout(set = 0, binding = 8, std430) buffer readonly SurfaceIndexBuffer { uint surfaceIndices[]; };
layout(set = 0, binding = 9, std430) buffer readonly SurfaceBuffer { SurfaceInfo surfaces[]; };
layout(set = 0, binding = 10, std430) buffer readonly PortalBuffer { PortalInfo portals[]; };
#endif

View file

@ -4,20 +4,48 @@
#if defined(USE_RAYTRACE)
#include <shaders/lightmap/polyfill_rayquery.glsl>
#include <shaders/lightmap/trace_levelmesh.glsl>
#include <shaders/lightmap/montecarlo.glsl>
vec2 getVogelDiskSample(int sampleIndex, int sampleCount, float phi)
float TraceDynLightRay(vec3 origin, float tmin, vec3 direction, float dist)
{
const float goldenAngle = radians(180.0) * (3.0 - sqrt(5.0));
float sampleIndexF = float(sampleIndex);
float sampleCountF = float(sampleCount);
float r = sqrt((sampleIndexF + 0.5) / sampleCountF); // Assuming index and count are positive
float theta = sampleIndexF * goldenAngle + phi;
float sine = sin(theta);
float cosine = cos(theta);
return vec2(cosine, sine) * r;
float alpha = 1.0;
for (int i = 0; i < 3; i++)
{
TraceResult result = TraceFirstHit(origin, tmin, direction, dist);
// Stop if we hit nothing - the point light is visible.
if (result.primitiveIndex == -1)
return alpha;
SurfaceInfo surface = GetSurface(result.primitiveIndex);
// Pass through surface texture
alpha = PassRayThroughSurfaceDynLight(surface, GetSurfaceUV(result.primitiveIndex, result.primitiveWeights), alpha);
// Stop if there is no light left
if (alpha <= 0.0)
return 0.0;
// Move to surface hit point
origin += direction * result.t;
dist -= result.t;
// Move through the portal, if any
TransformRay(surface.PortalIndex, origin, direction);
}
return 0.0;
}
float traceHit(vec3 origin, vec3 direction, float dist)
{
#if defined(USE_RAYTRACE_PRECISE)
return TraceDynLightRay(origin, 0.01f, direction, dist);
#else
return TraceAnyHit(origin, 0.01f, direction, dist) ? 0.0 : 1.0;
#endif
}
float traceShadow(vec4 lightpos, int quality, float softShadowRadius)
@ -30,7 +58,7 @@ float traceShadow(vec4 lightpos, int quality, float softShadowRadius)
if (quality == 0 || softShadowRadius == 0)
{
return traceHit(origin, direction, dist) ? 0.0 : 1.0;
return traceHit(origin, direction, dist);
}
else
{
@ -44,9 +72,9 @@ float traceShadow(vec4 lightpos, int quality, float softShadowRadius)
{
vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * softShadowRadius;
vec3 pos = target + xdir * gridoffset.x + ydir * gridoffset.y;
sum += traceHit(origin, normalize(pos - origin), dist) ? 0.0 : 1.0;
sum += traceHit(origin, normalize(pos - origin), dist);
}
return sum / step_count;
return (sum / step_count);
}
}