Surfel GI updates (#388)

* surfel gi updates; raytracing backface lighting fixes;

* renderer updates
This commit is contained in:
Turánszki János
2022-01-22 17:14:30 +01:00
committed by GitHub
parent 5cb4baa1ff
commit e350dc3716
30 changed files with 475 additions and 229 deletions
+1
View File
@@ -234,6 +234,7 @@ int main(int argc, char* argv[])
"surfel_binningCS.hlsl",
"surfel_raytraceCS_rtapi.hlsl",
"surfel_raytraceCS.hlsl",
"surfel_integrateCS.hlsl",
"ddgi_raytraceCS.hlsl",
"ddgi_raytraceCS_rtapi.hlsl",
"ddgi_updateCS.hlsl",
+116 -37
View File
@@ -3,18 +3,54 @@
#include "ShaderInterop.h"
#include "ShaderInterop_Renderer.h"
static const uint SURFEL_CAPACITY = 100000;
static const uint SQRT_SURFEL_CAPACITY = (uint)ceil(sqrt((float)SURFEL_CAPACITY));
static const uint SURFEL_MOMENT_RESOLUTION = 4;
static const uint SURFEL_MOMENT_TEXELS = 1 + SURFEL_MOMENT_RESOLUTION + 1; // with border padding
static const uint SURFEL_MOMENT_ATLAS_TEXELS = SQRT_SURFEL_CAPACITY * SURFEL_MOMENT_TEXELS;
static const uint3 SURFEL_GRID_DIMENSIONS = uint3(128, 64, 128);
static const uint SURFEL_TABLE_SIZE = SURFEL_GRID_DIMENSIONS.x * SURFEL_GRID_DIMENSIONS.y * SURFEL_GRID_DIMENSIONS.z;
static const float SURFEL_MAX_RADIUS = 2;
static const float SURFEL_RECYCLE_DISTANCE = 0; // if surfel is behind camera and farther than this distance, it starts preparing for recycling
static const uint SURFEL_RECYCLE_TIME = 60; // if surfel is preparing for recycling, this is how many frames it takes to recycle it
static const uint SURFEL_STATS_OFFSET_COUNT = 0;
static const uint SURFEL_STATS_OFFSET_NEXTCOUNT = SURFEL_STATS_OFFSET_COUNT + 4;
static const uint SURFEL_STATS_OFFSET_DEADCOUNT = SURFEL_STATS_OFFSET_NEXTCOUNT + 4;
static const uint SURFEL_STATS_OFFSET_CELLALLOCATOR = SURFEL_STATS_OFFSET_DEADCOUNT + 4;
static const uint SURFEL_STATS_OFFSET_RAYCOUNT = SURFEL_STATS_OFFSET_CELLALLOCATOR + 4;
static const uint SURFEL_STATS_OFFSET_SHORTAGE = SURFEL_STATS_OFFSET_RAYCOUNT + 4;
static const uint SURFEL_STATS_SIZE = SURFEL_STATS_OFFSET_SHORTAGE + 4;
static const uint SURFEL_INDIRECT_OFFSET_ITERATE = 0;
static const uint SURFEL_INDIRECT_OFFSET_RAYTRACE = SURFEL_INDIRECT_OFFSET_ITERATE + 4 * 3;
static const uint SURFEL_INDIRECT_OFFSET_INTEGRATE = SURFEL_INDIRECT_OFFSET_RAYTRACE + 4 * 3;
static const uint SURFEL_INDIRECT_SIZE = SURFEL_INDIRECT_OFFSET_INTEGRATE + 4 * 3;
static const uint SURFEL_INDIRECT_NUMTHREADS = 32;
static const float SURFEL_TARGET_COVERAGE = 0.5f; // how many surfels should affect a pixel fully, higher values will increase quality and cost
static const uint SURFEL_CELL_LIMIT = ~0; // limit the amount of allocated surfels in a cell
static const uint SURFEL_RAY_BUDGET = 200000; // max number of rays per frame
static const uint SURFEL_RAY_BOOST_MAX = 32; // max amount of rays per surfel
#define SURFEL_COVERAGE_HALFRES // runs the coverage shader in half resolution for improved performance
#define SURFEL_GRID_CULLING // if defined, surfels will not be added to grid cells that they do not intersect
#define SURFEL_USE_HASHING // if defined, hashing will be used to retrieve surfels, hashing is good because it supports infinite world trivially, but slower due to hash collisions
#define SURFEL_ENABLE_INFINITE_BOUNCES // if defined, previous frame's surfel data will be sampled at ray tracing hit points
//#define SURFEL_ENABLE_IRRADIANCE_SHARING // if defined, surfels will pull color from nearby surfels, this can smooth out the GI a bit
// This per-surfel surfel structure will be accessed rapidly on GI lookup, so keep it as small as possible
// But also ensure that it is 16-byte aligned for structured buffer access performance
struct Surfel
{
float3 position;
uint normal;
float3 color;
uint data; // 16bit radius (half float), 16bit rayCount
uint data; // 24bit rayOffset, 8bit rayCount
#ifndef __cplusplus
float GetRadius() { return f16tof32(data & 0xFFFF); }
uint GetRayCount() { return (data >> 16u) & 0xFFFF; }
inline float GetRadius() { return SURFEL_MAX_RADIUS; }
inline uint GetRayOffset() { return data & 0xFFFFFF; }
inline uint GetRayCount() { return (data >> 24u) & 0xFF; }
#endif // __cplusplus
};
// This per-surfel structure will store all additional persistent data per surfel that isn't needed at GI lookup
struct SurfelData
{
uint2 primitiveID;
@@ -33,42 +69,45 @@ struct SurfelData
uint GetLife() { return life_recycle & 0xFFFF; }
uint GetRecycle() { return (life_recycle >> 16u) & 0xFFFF; }
};
struct PushConstantsSurfelRaytrace
struct SurfelRayData
{
uint instanceInclusionMask;
float3 direction;
float depth;
float3 radiance;
uint surfelIndex;
};
struct SurfelRayDataPacked
{
uint4 data;
#ifndef __cplusplus
inline void store(SurfelRayData rayData)
{
data.xy = pack_half4(float4(rayData.direction, rayData.depth));
data.z = Pack_R11G11B10_FLOAT(rayData.radiance);
data.w = rayData.surfelIndex;
}
inline SurfelRayData load()
{
SurfelRayData rayData;
float4 unpk = unpack_half4(data.xy);
rayData.direction = unpk.xyz;
rayData.depth = unpk.w;
rayData.radiance = Unpack_R11G11B10_FLOAT(data.z);
rayData.surfelIndex = data.w;
return rayData;
}
#endif // __cplusplus
};
static const uint SURFEL_CAPACITY = 100000;
static const uint SQRT_SURFEL_CAPACITY = (uint)ceil(sqrt((float)SURFEL_CAPACITY));
static const uint SURFEL_MOMENT_TEXELS = 4 + 2;
static const uint SURFEL_MOMENT_ATLAS_TEXELS = SQRT_SURFEL_CAPACITY * SURFEL_MOMENT_TEXELS;
static const uint3 SURFEL_GRID_DIMENSIONS = uint3(128, 64, 128);
static const uint SURFEL_TABLE_SIZE = SURFEL_GRID_DIMENSIONS.x * SURFEL_GRID_DIMENSIONS.y * SURFEL_GRID_DIMENSIONS.z;
static const float SURFEL_MAX_RADIUS = 2;
static const float SURFEL_RECYCLE_DISTANCE = 0; // if surfel is behind camera and farther than this distance, it starts preparing for recycling
static const uint SURFEL_RECYCLE_TIME = 60; // if surfel is preparing for recycling, this is how many frames it takes to recycle it
struct SurfelGridCell
{
uint count;
uint offset;
};
static const uint SURFEL_STATS_OFFSET_COUNT = 0;
static const uint SURFEL_STATS_OFFSET_NEXTCOUNT = SURFEL_STATS_OFFSET_COUNT + 4;
static const uint SURFEL_STATS_OFFSET_DEADCOUNT = SURFEL_STATS_OFFSET_NEXTCOUNT + 4;
static const uint SURFEL_STATS_OFFSET_CELLALLOCATOR = SURFEL_STATS_OFFSET_DEADCOUNT + 4;
static const uint SURFEL_STATS_OFFSET_INDIRECT = SURFEL_STATS_OFFSET_CELLALLOCATOR + 4;
static const uint SURFEL_STATS_OFFSET_RAYCOUNT = SURFEL_STATS_OFFSET_INDIRECT + 4 * 3;
static const uint SURFEL_STATS_OFFSET_SHORTAGE = SURFEL_STATS_OFFSET_RAYCOUNT + 4;
static const uint SURFEL_INDIRECT_NUMTHREADS = 32;
static const float SURFEL_TARGET_COVERAGE = 0.5f; // how many surfels should affect a pixel fully, higher values will increase quality and cost
static const uint SURFEL_CELL_LIMIT = ~0; // limit the amount of allocated surfels in a cell
static const uint SURFEL_RAY_BUDGET = 200000; // max number of rays per frame
static const uint SURFEL_RAY_BOOST_MAX = 32; // max amount of rays per surfel
#define SURFEL_COVERAGE_HALFRES // runs the coverage shader in half resolution for improved performance
#define SURFEL_GRID_CULLING // if defined, surfels will not be added to grid cells that they do not intersect
#define SURFEL_USE_HASHING // if defined, hashing will be used to retrieve surfels, hashing is good because it supports infinite world trivially, but slower due to hash collisions
#define SURFEL_ENABLE_INFINITE_BOUNCES // if defined, previous frame's surfel data will be sampled at ray tracing hit points
#define SURFEL_ENABLE_IRRADIANCE_SHARING // if defined, surfels will pull color from nearby surfels, this can smooth out the GI a bit
struct PushConstantsSurfelRaytrace
{
uint instanceInclusionMask;
};
enum SURFEL_DEBUG
{
SURFEL_DEBUG_NONE,
@@ -187,16 +226,15 @@ static const int3 surfel_neighbor_offsets[27] = {
float2 surfel_moment_pixel(uint surfel_index, float3 normal, float3 direction)
{
uint2 moments_pixel = unflatten2D(surfel_index, SQRT_SURFEL_CAPACITY) * SURFEL_MOMENT_TEXELS;
float3 hemi = mul(direction, transpose(get_tangentspace(normal)));
hemi.z = abs(hemi.z);
float3 hemi = mul(get_tangentspace(normal), direction);
hemi = normalize(hemi);
hemi.z = abs(hemi.z);
float2 moments_uv = encode_hemioct(hemi) * 0.5 + 0.5;
//float2 moments_uv = hemi.xy * 0.5 + 0.5;
return moments_pixel + 1 + moments_uv * (SURFEL_MOMENT_TEXELS - 2);
return moments_pixel + 1 + moments_uv * SURFEL_MOMENT_RESOLUTION;
}
float2 surfel_moment_uv(uint surfel_index, float3 normal, float3 direction)
{
return surfel_moment_pixel(surfel_index, normal, direction) / SURFEL_MOMENT_ATLAS_TEXELS;
return (surfel_moment_pixel(surfel_index, normal, direction) + 0.5) / SURFEL_MOMENT_ATLAS_TEXELS;
}
float surfel_moment_weight(float2 moments, float dist)
{
@@ -265,6 +303,47 @@ void MultiscaleMeanEstimator(
data.variance = variance;
data.inconsistency = inconsistency;
}
// Border offsets from: https://github.com/diharaw/hybrid-rendering/blob/master/src/shaders/gi/gi_border_update.glsl
static const uint4 SURFEL_MOMENT_BORDER_OFFSETS[36] = {
uint4(8, 1, 1, 0),
uint4(7, 1, 2, 0),
uint4(6, 1, 3, 0),
uint4(5, 1, 4, 0),
uint4(4, 1, 5, 0),
uint4(3, 1, 6, 0),
uint4(2, 1, 7, 0),
uint4(1, 1, 8, 0),
uint4(8, 8, 1, 9),
uint4(7, 8, 2, 9),
uint4(6, 8, 3, 9),
uint4(5, 8, 4, 9),
uint4(4, 8, 5, 9),
uint4(3, 8, 6, 9),
uint4(2, 8, 7, 9),
uint4(1, 8, 8, 9),
uint4(1, 8, 0, 1),
uint4(1, 7, 0, 2),
uint4(1, 6, 0, 3),
uint4(1, 5, 0, 4),
uint4(1, 4, 0, 5),
uint4(1, 3, 0, 6),
uint4(1, 2, 0, 7),
uint4(1, 1, 0, 8),
uint4(8, 8, 9, 1),
uint4(8, 7, 9, 2),
uint4(8, 6, 9, 3),
uint4(8, 5, 9, 4),
uint4(8, 4, 9, 5),
uint4(8, 3, 9, 6),
uint4(8, 2, 9, 7),
uint4(8, 1, 9, 8),
uint4(8, 8, 0, 0),
uint4(1, 8, 9, 0),
uint4(8, 1, 0, 9),
uint4(1, 1, 9, 9)
};
#endif // __cplusplus
#endif // WI_SHADERINTEROP_SURFEL_GI_H
@@ -1018,6 +1018,10 @@
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)surfel_integrateCS.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)surfel_raytraceCS.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
@@ -1022,6 +1022,9 @@
<FxCompile Include="$(MSBuildThisFileDirectory)ddgi_updateCS_depth.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)surfel_integrateCS.hlsl">
<Filter>CS</Filter>
</FxCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop.h">
-2
View File
@@ -207,8 +207,6 @@ struct Surface
in float4 specularMap = 1
)
{
init();
if (material.options & SHADERMATERIAL_OPTION_BIT_TRANSPARENT || material.alphaTest > 0)
{
opacity = baseColor.a;
+2 -1
View File
@@ -31,7 +31,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn
const float3 probePos = ddgi_probe_position(probeCoord);
float seed = 0.123456;
float2 uv = float2(frac(GetFrame().frame_count.x / 4096.0), DTid.x);
float2 uv = float2(frac(GetFrame().frame_count.x / 4096.0), DTid.x / float(DDGI_PROBE_COUNT * push.rayCount));
const float3x3 random_orientation = (float3x3)g_xTransform;
@@ -85,6 +85,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn
{
Surface surface;
surface.init();
float hit_depth = 0;
float3 hit_result = 0;
@@ -63,6 +63,7 @@ float4 main(VertextoPixel input) : SV_TARGET
lighting.create(0, 0, GetAmbient(N), 0);
Surface surface;
surface.init();
surface.create(material, color, 0);
surface.P = input.P;
surface.N = N;
+1
View File
@@ -29,6 +29,7 @@ float4 main(VertexToPixel input) : SV_Target
const float2 ScreenCoord = pixel * GetCamera().internal_resolution_rcp;
Surface surface;
surface.init();
surface.create(material, color, 0);
surface.P = input.pos3D;
surface.N = input.nor;
+3
View File
@@ -68,6 +68,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
prim.subsetIndex = q.CandidateGeometryIndex();
Surface surface;
surface.init();
if (!surface.load(prim, q.CandidateTriangleBarycentrics()))
break;
@@ -104,6 +105,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
}
Surface surface;
surface.init();
#ifdef RTAPI
// ray origin updated for next bounce:
@@ -264,6 +266,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
prim.subsetIndex = q.CandidateGeometryIndex();
Surface surface;
surface.init();
if (!surface.load(prim, q.CandidateTriangleBarycentrics()))
break;
+2
View File
@@ -106,6 +106,7 @@ inline void IntersectTriangle(
if (prim.flags & BVH_PRIMITIVE_FLAG_TRANSPARENT)
{
Surface surface;
surface.init();
if (surface.load(hit.primitiveID, hit.bary))
{
if (surface.opacity - rand(seed, uv) >= 0)
@@ -160,6 +161,7 @@ inline bool IntersectTriangleANY(
hit.bary = float2(u, v);
Surface surface;
surface.init();
if (surface.load(prim.primitiveID(), float2(u, v)))
{
return surface.opacity - rand(seed, uv) >= 0;
@@ -169,6 +169,7 @@ float4 main(Input input) : SV_TARGET
prim.subsetIndex = q.CandidateGeometryIndex();
Surface surface;
surface.init();
if (!surface.load(prim, q.CandidateTriangleBarycentrics()))
break;
+2
View File
@@ -39,6 +39,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid :
prim.unpack(texture_gbuffer0[DTid.xy * 2]);
Surface surface;
surface.init();
if (!surface.load(prim, P))
{
return;
@@ -74,6 +75,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid :
prim.subsetIndex = q.CandidateGeometryIndex();
Surface surface;
surface.init();
if (!surface.load(prim, q.CandidateTriangleBarycentrics()))
break;
+3
View File
@@ -37,6 +37,7 @@ void main(uint2 DTid : SV_DispatchThreadID)
//return;
Surface surface;
surface.init();
if (!surface.load(prim, P))
{
return;
@@ -112,6 +113,7 @@ void main(uint2 DTid : SV_DispatchThreadID)
prim.subsetIndex = q.CandidateGeometryIndex();
Surface surface;
surface.init();
if (!surface.load(prim, q.CandidateTriangleBarycentrics()))
break;
@@ -144,6 +146,7 @@ void main(uint2 DTid : SV_DispatchThreadID)
prim.subsetIndex = q.CommittedGeometryIndex();
Surface surface;
surface.init();
if (!q.CommittedTriangleFrontFace())
{
surface.flags |= SURFACE_FLAG_BACKFACE;
@@ -44,6 +44,7 @@ void RTReflection_Raygen()
//return;
Surface surface;
surface.init();
if (!surface.load(prim, P))
{
return;
@@ -124,6 +125,7 @@ void RTReflection_ClosestHit(inout RayPayload payload, in BuiltInTriangleInterse
prim.subsetIndex = GeometryIndex();
Surface surface;
surface.init();
if (HitKind() != HIT_KIND_TRIANGLE_FRONT_FACE)
{
surface.flags |= SURFACE_FLAG_BACKFACE;
@@ -197,6 +199,7 @@ void RTReflection_AnyHit(inout RayPayload payload, in BuiltInTriangleIntersectio
prim.subsetIndex = GeometryIndex();
Surface surface;
surface.init();
if (!surface.load(prim, attr.barycentrics))
return;
@@ -54,6 +54,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid :
prim.unpack(texture_gbuffer0[DTid.xy * 2]);
Surface surface;
surface.init();
if (!surface.load(prim, P))
{
return;
@@ -234,6 +235,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid :
prim.subsetIndex = q.CandidateGeometryIndex();
Surface surface;
surface.init();
if (!surface.load(prim, q.CandidateTriangleBarycentrics()))
break;
+1
View File
@@ -232,6 +232,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
prim.unpack(texture_gbuffer0[DTid.xy * 2]);
Surface surface;
surface.init();
if (!surface.load(prim, reconstruct_position(uv, depth)))
{
return;
+2
View File
@@ -74,6 +74,7 @@ void GetSampleInfo(float2 velocity, float2 neighborUV, float2 uv, float3 P, floa
float NdotL = saturate(dot(N, L));
Surface surface;
surface.init();
surface.roughnessBRDF = roughness * roughness;
surface.NdotV = NdotV;
@@ -105,6 +106,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
prim.unpack(texture_gbuffer0[DTid.xy * 2]);
Surface surface;
surface.init();
if (!surface.load(prim, P))
{
return;
+1
View File
@@ -121,6 +121,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint3
prim.unpack(texture_gbuffer0[DTid.xy * 2]);
Surface surface;
surface.init();
if (!surface.load(prim, P))
return;
+3 -2
View File
@@ -95,6 +95,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, uin
prim.unpack(primitiveID);
Surface surface;
surface.init();
if (!surface.load(prim, P))
{
return;
@@ -118,7 +119,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, uin
uint surfel_index = surfelCellBuffer[cell.offset + i];
Surfel surfel = surfelBuffer[surfel_index];
float3 L = surfel.position - P;
float3 L = P - surfel.position;
float dist2 = dot(L, L);
if (dist2 < sqr(surfel.GetRadius()))
{
@@ -134,7 +135,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, uin
contribution = smoothstep(0, 1, contribution);
coverage += contribution;
float2 moments = surfelMomentsTexture.SampleLevel(sampler_linear_clamp, surfel_moment_uv(surfel_index, normal, -L / dist), 0);
float2 moments = surfelMomentsTexture.SampleLevel(sampler_linear_clamp, surfel_moment_uv(surfel_index, normal, L / dist), 0);
contribution *= surfel_moment_weight(moments, dist);
// contribution based on life can eliminate black popping surfels, but the surfel_data must be accessed...
@@ -2,6 +2,7 @@
#include "ShaderInterop_SurfelGI.h"
RWByteAddressBuffer surfelStatsBuffer : register(u0);
RWByteAddressBuffer surfelIndirectBuffer : register(u1);
[numthreads(1, 1, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
@@ -13,12 +14,16 @@ void main(uint3 DTid : SV_DispatchThreadID)
int shortage = max(0, -dead_count); // if deadcount was negative, there was shortage
dead_count = clamp(dead_count, 0, SURFEL_CAPACITY);
uint ray_count = surfelStatsBuffer.Load(SURFEL_STATS_OFFSET_RAYCOUNT);
surfelStatsBuffer.Store(SURFEL_STATS_OFFSET_COUNT, surfel_count);
surfelStatsBuffer.Store(SURFEL_STATS_OFFSET_NEXTCOUNT, 0);
surfelStatsBuffer.Store(SURFEL_STATS_OFFSET_DEADCOUNT, dead_count);
surfelStatsBuffer.Store(SURFEL_STATS_OFFSET_CELLALLOCATOR, 0);
surfelStatsBuffer.Store(SURFEL_STATS_OFFSET_RAYCOUNT, SURFEL_RAY_BUDGET);
surfelStatsBuffer.Store(SURFEL_STATS_OFFSET_RAYCOUNT, 0);
surfelStatsBuffer.Store(SURFEL_STATS_OFFSET_SHORTAGE, shortage);
surfelStatsBuffer.Store3(SURFEL_STATS_OFFSET_INDIRECT, uint3((surfel_count + SURFEL_INDIRECT_NUMTHREADS - 1) / SURFEL_INDIRECT_NUMTHREADS, 1, 1));
surfelIndirectBuffer.Store3(SURFEL_INDIRECT_OFFSET_ITERATE, uint3((surfel_count + SURFEL_INDIRECT_NUMTHREADS - 1) / SURFEL_INDIRECT_NUMTHREADS, 1, 1));
surfelIndirectBuffer.Store3(SURFEL_INDIRECT_OFFSET_RAYTRACE, uint3((ray_count + SURFEL_INDIRECT_NUMTHREADS - 1) / SURFEL_INDIRECT_NUMTHREADS, 1, 1));
surfelIndirectBuffer.Store3(SURFEL_INDIRECT_OFFSET_INTEGRATE, uint3(surfel_count, 1, 1));
}
@@ -0,0 +1,201 @@
#include "globals.hlsli"
#include "raytracingHF.hlsli"
#include "lightingHF.hlsli"
#include "ShaderInterop_SurfelGI.h"
static const float WEIGHT_EPSILON = 0.0001;
StructuredBuffer<Surfel> surfelBuffer : register(t0);
ByteAddressBuffer surfelStatsBuffer : register(t1);
StructuredBuffer<SurfelGridCell> surfelGridBuffer : register(t2);
StructuredBuffer<uint> surfelCellBuffer : register(t3);
StructuredBuffer<uint> surfelAliveBuffer : register(t4);
Texture2D<float2> surfelMomentsTexturePrev : register(t5);
StructuredBuffer<SurfelRayDataPacked> surfelRayBuffer : register(t6);
RWStructuredBuffer<SurfelData> surfelDataBuffer : register(u0);
RWTexture2D<float2> surfelMomentsTexture : register(u1);
static const uint THREADCOUNT = 8;
static const uint CACHE_SIZE = THREADCOUNT * THREADCOUNT;
groupshared SurfelRayData ray_cache[CACHE_SIZE];
groupshared float4 result_cache[CACHE_SIZE];
[numthreads(THREADCOUNT, THREADCOUNT, 1)]
void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID, uint groupIndex : SV_GroupIndex)
{
uint surfel_index = Gid.x;
Surfel surfel = surfelBuffer[surfel_index];
SurfelData surfel_data = surfelDataBuffer[surfel_index];
uint life = surfel_data.GetLife();
uint recycle = surfel_data.GetRecycle();
float maxDistance = surfel.GetRadius();
const float3 P = surfel.position;
const float3 N = normalize(unpack_unitvector(surfel.normal));
float3 texel_direction = decode_hemioct(((GTid.xy + 0.5) / (float2)SURFEL_MOMENT_RESOLUTION) * 2 - 1);
texel_direction = mul(texel_direction, get_tangentspace(N));
texel_direction = normalize(texel_direction);
float4 result = 0;
float2 result_depth = 0;
float total_weight = 0;
uint remaining_rays = surfel.GetRayCount();
uint offset = surfel.GetRayOffset();
while (remaining_rays > 0)
{
uint num_rays = min(CACHE_SIZE, remaining_rays);
if (groupIndex < num_rays)
{
ray_cache[groupIndex] = surfelRayBuffer[offset + groupIndex].load();
}
GroupMemoryBarrierWithGroupSync();
for (uint r = 0; r < num_rays; ++r)
{
SurfelRayData ray = ray_cache[r];
result += float4(ray.radiance, 1);
float depth;
if (ray.depth > 0)
{
depth = clamp(ray.depth, 0, maxDistance);
}
else
{
depth = maxDistance;
}
const float3 radiance = ray.radiance.rgb;
float weight = saturate(dot(texel_direction, ray.direction) + 0.01);
weight = pow(weight, 32);
if (weight > WEIGHT_EPSILON)
{
result_depth += float2(depth, sqr(depth)) * weight;
total_weight += weight;
}
}
GroupMemoryBarrierWithGroupSync();
remaining_rays -= num_rays;
offset += num_rays;
}
uint2 moments_topleft = unflatten2D(surfel_index, SQRT_SURFEL_CAPACITY) * SURFEL_MOMENT_TEXELS;
if (total_weight > WEIGHT_EPSILON && GTid.x < SURFEL_MOMENT_RESOLUTION && GTid.y < SURFEL_MOMENT_RESOLUTION)
{
result_depth /= total_weight;
uint2 moments_pixel = moments_topleft + 1 + GTid.xy;
if (life > 0)
{
const float2 prev_moment = surfelMomentsTexturePrev[moments_pixel];
result_depth = lerp(prev_moment, result_depth, 0.02);
}
surfelMomentsTexture[moments_pixel] = result_depth;
}
#ifdef SURFEL_ENABLE_IRRADIANCE_SHARING
// Surfel irradiance sharing:
{
uint cellindex = surfel_cellindex(surfel_cell(P));
SurfelGridCell cell = surfelGridBuffer[cellindex];
for (uint i = 0; i < cell.count; i += THREADCOUNT * THREADCOUNT)
{
uint surfel_index = surfelCellBuffer[cell.offset + i];
Surfel surfel = surfelBuffer[surfel_index];
const float combined_radius = surfel.GetRadius() + maxDistance;
float3 L = P - surfel.position;
float dist2 = dot(L, L);
if (dist2 < sqr(combined_radius))
{
float3 normal = normalize(unpack_unitvector(surfel.normal));
float dotN = dot(N, normal);
if (dotN > 0)
{
float dist = sqrt(dist2);
float contribution = 1;
contribution *= saturate(dotN);
contribution *= saturate(1 - dist / combined_radius);
contribution = smoothstep(0, 1, contribution);
float2 moments = surfelMomentsTexturePrev.SampleLevel(sampler_linear_clamp, surfel_moment_uv(surfel_index, normal, L / dist), 0);
contribution *= surfel_moment_weight(moments, dist);
result += float4(surfel.color, 1) * contribution;
}
}
}
}
result_cache[groupIndex] = result;
#endif // SURFEL_ENABLE_IRRADIANCE_SHARING
AllMemoryBarrierWithGroupSync();
// Copy moment borders:
for (uint i = GTid.x; i < SURFEL_MOMENT_TEXELS; i += THREADCOUNT)
{
for (uint j = GTid.y; j < SURFEL_MOMENT_TEXELS; j += THREADCOUNT)
{
uint2 pixel_write = moments_topleft + uint2(i, j);
uint2 pixel_read = clamp(pixel_write, moments_topleft + 1, moments_topleft + 1 + SURFEL_MOMENT_RESOLUTION - 1);
surfelMomentsTexture[pixel_write] = surfelMomentsTexture[pixel_read];
}
}
if (groupIndex > 0)
return;
#ifdef SURFEL_ENABLE_IRRADIANCE_SHARING
result = 0;
for (uint c = 0; c < CACHE_SIZE; ++c)
{
result += result_cache[c];
}
#endif // SURFEL_ENABLE_IRRADIANCE_SHARING
if (result.a > 0)
{
result /= result.a;
MultiscaleMeanEstimator(result.rgb, surfel_data, 0.08);
}
life++;
float3 cam_to_surfel = surfel.position - GetCamera().position;
if (length(cam_to_surfel) > SURFEL_RECYCLE_DISTANCE)
{
ShaderSphere sphere;
sphere.center = surfel.position;
sphere.radius = surfel.GetRadius();
if (GetCamera().frustum.intersects(sphere))
{
recycle = 0;
}
else
{
recycle++;
}
}
else
{
recycle = 0;
}
surfel_data.life_recycle = 0;
surfel_data.life_recycle |= life & 0xFFFF;
surfel_data.life_recycle |= (recycle & 0xFFFF) << 16u;
surfelDataBuffer[surfel_index] = surfel_data;
}
+18 -125
View File
@@ -12,38 +12,25 @@ StructuredBuffer<uint> surfelCellBuffer : register(t3);
StructuredBuffer<uint> surfelAliveBuffer : register(t4);
Texture2D<float2> surfelMomentsTexturePrev : register(t5);
RWStructuredBuffer<SurfelData> surfelDataBuffer : register(u0);
RWTexture2D<float2> surfelMomentsTexture : register(u1);
void surfel_moments_write(uint2 moments_pixel, float dist)
{
float2 prev = surfelMomentsTexture[moments_pixel];
float2 blend = prev.x < dist ? 0.005 : 0.5;
surfelMomentsTexture[moments_pixel] = lerp(prev, float2(dist, sqr(dist)), blend);
}
RWStructuredBuffer<SurfelRayDataPacked> surfelRayBuffer : register(u0);
[numthreads(SURFEL_INDIRECT_NUMTHREADS, 1, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
{
uint surfel_count = surfelStatsBuffer.Load(SURFEL_STATS_OFFSET_COUNT);
if (DTid.x >= surfel_count)
uint global_ray_count = surfelStatsBuffer.Load(SURFEL_STATS_OFFSET_RAYCOUNT);
if (DTid.x >= global_ray_count)
return;
float4 result = 0;
SurfelRayData rayData = surfelRayBuffer[DTid.x].load();
uint surfel_index = surfelAliveBuffer[DTid.x];
uint surfel_index = rayData.surfelIndex;
Surfel surfel = surfelBuffer[surfel_index];
SurfelData surfel_data = surfelDataBuffer[surfel_index];
uint life = surfel_data.GetLife();
uint recycle = surfel_data.GetRecycle();
const float3 N = normalize(unpack_unitvector(surfel.normal));
float seed = 0.123456;
float2 uv = float2(frac(GetFrame().frame_count.x / 4096.0), (float)surfel_index / SURFEL_CAPACITY);
float2 uv = float2(frac(GetFrame().frame_count.x / 4096.0), (float)DTid.x / (float)global_ray_count);
uint rayCount = surfel.GetRayCount();
for (uint rayIndex = 0; rayIndex < rayCount; ++rayIndex)
{
RayDesc ray;
ray.Origin = surfel.position;
@@ -51,8 +38,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
ray.TMax = FLT_MAX;
ray.Direction = normalize(sample_hemisphere_cos(N, seed, uv));
uint2 moments_pixel = surfel_moment_pixel(surfel_index, N, ray.Direction);
rayData.direction = ray.Direction;
#ifdef RTAPI
RayQuery<
@@ -74,8 +60,6 @@ void main(uint3 DTid : SV_DispatchThreadID)
#endif // RTAPI
{
surfel_moments_write(moments_pixel, surfel.GetRadius());
float3 envColor;
[branch]
if (IsStaticSky())
@@ -87,12 +71,14 @@ void main(uint3 DTid : SV_DispatchThreadID)
{
envColor = GetDynamicSkyColor(ray.Direction, true, true, false, true);
}
result += float4(max(0, envColor), 1);
rayData.radiance = max(0, envColor);
rayData.depth = -1;
}
else
{
Surface surface;
surface.init();
float hit_depth = 0;
float3 hit_result = 0;
@@ -113,7 +99,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
surface.flags |= SURFACE_FLAG_BACKFACE;
}
if(!surface.load(prim, q.CommittedTriangleBarycentrics()))
break;
return;
#else
@@ -122,17 +108,10 @@ void main(uint3 DTid : SV_DispatchThreadID)
hit_depth = hit.distance;
if (!surface.load(hit.primitiveID, hit.bary))
break;
return;
#endif // RTAPI
if (hit_depth < surfel.GetRadius())
{
hit_depth *= 0.8; // bias
}
hit_depth = clamp(hit_depth, 0, surfel.GetRadius());
surfel_moments_write(moments_pixel, hit_depth);
surface.P = ray.Origin;
surface.V = -ray.Direction;
surface.update();
@@ -289,7 +268,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
uint surfel_index = surfelCellBuffer[cell.offset + i];
Surfel surfel = surfelBuffer[surfel_index];
float3 L = surfel.position - surface.P;
float3 L = surface.P - surfel.position;
float dist2 = dot(L, L);
if (dist2 < sqr(surfel.GetRadius()))
{
@@ -304,7 +283,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
contribution *= saturate(1 - dist / surfel.GetRadius());
contribution = smoothstep(0, 1, contribution);
float2 moments = surfelMomentsTexturePrev.SampleLevel(sampler_linear_clamp, surfel_moment_uv(surfel_index, normal, -L / dist), 0);
float2 moments = surfelMomentsTexturePrev.SampleLevel(sampler_linear_clamp, surfel_moment_uv(surfel_index, normal, L / dist), 0);
contribution *= surfel_moment_weight(moments, dist);
surfel_gi += float4(surfel.color, 1) * contribution;
@@ -323,99 +302,13 @@ void main(uint3 DTid : SV_DispatchThreadID)
hit_result *= surface.albedo;
hit_result += max(0, surface.emissiveColor);
result += float4(hit_result, 1);
rayData.radiance = hit_result;
rayData.depth = hit_depth;
}
}
#ifdef SURFEL_ENABLE_IRRADIANCE_SHARING
// Surfel irradiance sharing:
{
Surface surface;
surface.P = surfel.position;
surface.N = normalize(unpack_unitvector(surfel.normal));
const float surface_radius = surfel.GetRadius();
uint cellindex = surfel_cellindex(surfel_cell(surface.P));
SurfelGridCell cell = surfelGridBuffer[cellindex];
for (uint i = 0; i < cell.count; ++i)
{
uint surfel_index = surfelCellBuffer[cell.offset + i];
Surfel surfel = surfelBuffer[surfel_index];
const float combined_radius = surfel.GetRadius() + surface_radius;
float3 L = surfel.position - surface.P;
float dist2 = dot(L, L);
if (dist2 < sqr(combined_radius))
{
float3 normal = normalize(unpack_unitvector(surfel.normal));
float dotN = dot(surface.N, normal);
if (dotN > 0)
{
float dist = sqrt(dist2);
float contribution = 1;
contribution *= saturate(dotN);
contribution *= saturate(1 - dist / combined_radius);
contribution = smoothstep(0, 1, contribution);
float2 moments = surfelMomentsTexturePrev.SampleLevel(sampler_linear_clamp, surfel_moment_uv(surfel_index, normal, -L / dist), 0);
contribution *= surfel_moment_weight(moments, dist);
result += float4(surfel.color, 1) * contribution;
}
}
}
}
#endif // SURFEL_ENABLE_IRRADIANCE_SHARING
if (result.a > 0)
{
result /= result.a;
MultiscaleMeanEstimator(result.rgb, surfel_data, 0.08);
}
// Copy moment borders:
uint2 moments_topleft = unflatten2D(surfel_index, SQRT_SURFEL_CAPACITY) * SURFEL_MOMENT_TEXELS;
for (uint i = 0; i < SURFEL_MOMENT_TEXELS; ++i)
{
for (uint j = 0; j < SURFEL_MOMENT_TEXELS; ++j)
{
uint2 pixel_write = moments_topleft + uint2(i, j);
uint2 pixel_read = clamp(pixel_write, moments_topleft + 1, moments_topleft + SURFEL_MOMENT_TEXELS - 2);
surfelMomentsTexture[pixel_write] = surfelMomentsTexture[pixel_read];
}
}
life++;
float3 cam_to_surfel = surfel.position - GetCamera().position;
if (length(cam_to_surfel) > SURFEL_RECYCLE_DISTANCE)
{
ShaderSphere sphere;
sphere.center = surfel.position;
sphere.radius = surfel.GetRadius();
if (GetCamera().frustum.intersects(sphere))
{
recycle = 0;
}
else
{
recycle++;
}
}
else
{
recycle = 0;
}
surfel_data.life_recycle = 0;
surfel_data.life_recycle |= life & 0xFFFF;
surfel_data.life_recycle |= (recycle & 0xFFFF) << 16u;
surfelDataBuffer[surfel_index] = surfel_data;
surfelRayBuffer[DTid.x].store(rayData);
}
+17 -32
View File
@@ -4,14 +4,13 @@
StructuredBuffer<SurfelData> surfelDataBuffer : register(t0);
StructuredBuffer<uint> surfelAliveBuffer_CURRENT : register(t1);
Texture2D<float2> surfelMomentsTexturePrev : register(t2);
RWStructuredBuffer<Surfel> surfelBuffer : register(u0);
RWStructuredBuffer<SurfelGridCell> surfelGridBuffer : register(u1);
RWStructuredBuffer<uint> surfelAliveBuffer_NEXT : register(u2);
RWStructuredBuffer<uint> surfelDeadBuffer : register(u3);
RWByteAddressBuffer surfelStatsBuffer : register(u4);
RWTexture2D<float2> surfelMomentsTexture : register(u5);
RWStructuredBuffer<SurfelRayDataPacked> surfelRayBuffer : register(u5);
[numthreads(SURFEL_INDIRECT_NUMTHREADS, 1, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
@@ -30,6 +29,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
prim.unpack(surfel_data.primitiveID);
Surface surface;
surface.init();
if (surface.load(prim, unpack_half2(surfel_data.bary), surfel_data.uid))
{
surfel.normal = pack_unitvector(surface.facenormal);
@@ -66,9 +66,6 @@ void main(uint3 DTid : SV_DispatchThreadID)
surfelStatsBuffer.InterlockedAdd(SURFEL_STATS_OFFSET_NEXTCOUNT, 1, aliveCount);
surfelAliveBuffer_NEXT[aliveCount] = surfel_index;
surfel.data = 0;
surfel.data |= f32tof16(radius) & 0xFFFF;
// Determine ray count for surfel:
uint rayCountRequest = saturate(surfel_data.inconsistency) * SURFEL_RAY_BOOST_MAX;
const uint recycle = surfel_data.GetRecycle();
@@ -80,40 +77,28 @@ void main(uint3 DTid : SV_DispatchThreadID)
{
rayCountRequest = 0;
}
int rayCountGlobal = 0;
uint rayOffset = 0;
if (rayCountRequest > 0)
{
surfelStatsBuffer.InterlockedAdd(SURFEL_STATS_OFFSET_RAYCOUNT, -rayCountRequest, rayCountGlobal);
surfelStatsBuffer.InterlockedAdd(SURFEL_STATS_OFFSET_RAYCOUNT, rayCountRequest, rayOffset);
}
uint rayCount = clamp(rayCountRequest, 0, rayCountGlobal);
surfel.data |= (rayCount & 0xFFFF) << 16u;
uint rayCount = (rayOffset < SURFEL_RAY_BUDGET) ? rayCountRequest : 0;
rayCount = clamp(rayCount, 0, SURFEL_RAY_BUDGET - rayOffset);
rayCount &= 0xFF;
surfel.data = 0;
surfel.data |= rayOffset & 0xFFFFFF;
surfel.data |= rayCount << 24u;
surfelBuffer[surfel_index] = surfel;
uint2 moments_pixel = unflatten2D(surfel_index, SQRT_SURFEL_CAPACITY) * SURFEL_MOMENT_TEXELS;
if (surfel_data.GetLife() == 0)
SurfelRayData initialRayData = (SurfelRayData)0;
initialRayData.surfelIndex = surfel_index;
SurfelRayDataPacked initialRayDataPacked;
initialRayDataPacked.store(initialRayData);
for (uint rayIndex = 0; rayIndex < rayCount; ++rayIndex)
{
// initialize surfel moments:
for (int i = 0; i < SURFEL_MOMENT_TEXELS; ++i)
{
for (int j = 0; j < SURFEL_MOMENT_TEXELS; ++j)
{
uint2 pixel_write = moments_pixel + uint2(i, j);
surfelMomentsTexture[pixel_write] = float2(radius, sqr(radius));
}
}
}
else
{
// copy surfel moments:
for (int i = 0; i < SURFEL_MOMENT_TEXELS; ++i)
{
for (int j = 0; j < SURFEL_MOMENT_TEXELS; ++j)
{
uint2 pixel_write = moments_pixel + uint2(i, j);
surfelMomentsTexture[pixel_write] = surfelMomentsTexturePrev[pixel_write];
}
}
surfelRayBuffer[rayOffset + rayIndex] = initialRayDataPacked;
}
}
else
@@ -48,6 +48,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, uin
prim.unpack(primitiveID);
Surface surface;
surface.init();
if (surface.load(prim, P))
{
pre = surface.pre;
+1
View File
@@ -344,6 +344,7 @@ namespace wi::enums
CSTYPE_SURFEL_GRIDRESET,
CSTYPE_SURFEL_GRIDOFFSETS,
CSTYPE_SURFEL_BINNING,
CSTYPE_SURFEL_INTEGRATE,
CSTYPE_VISIBILITY_RESOLVE,
CSTYPE_VISIBILITY_RESOLVE_MSAA,
CSTYPE_DDGI_RAYTRACE,
+58 -23
View File
@@ -993,6 +993,7 @@ void LoadShaders()
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_SURFEL_GRIDRESET], "surfel_gridresetCS.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_SURFEL_GRIDOFFSETS], "surfel_gridoffsetsCS.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_SURFEL_BINNING], "surfel_binningCS.cso"); });
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_SURFEL_INTEGRATE], "surfel_integrateCS.cso"); });
if (device->CheckCapability(GraphicsDeviceCapability::RAYTRACING))
{
wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_SURFEL_RAYTRACE], "surfel_raytraceCS_rtapi.cso", ShaderModel::SM_6_5); });
@@ -2278,7 +2279,7 @@ inline void CreateDirLightShadowCams(const LightComponent& light, CameraComponen
// Extrude bounds to avoid early shadow clipping:
float ext = abs(_center.z - _min.z);
ext = std::max(ext, farPlane * 0.5f);
ext = std::max(ext, std::min(1500.0f, farPlane) * 0.5f);
_min.z = _center.z - ext;
_max.z = _center.z + ext;
@@ -4871,26 +4872,9 @@ void DrawScene(
vis.scene->ocean.Render(*vis.camera, vis.scene->weather.oceanParameters, cmd);
}
if (hairparticle)
{
if (!transparent)
{
for (uint32_t hairIndex : vis.visibleHairs)
{
const wi::HairParticleSystem& hair = vis.scene->hairs[hairIndex];
Entity entity = vis.scene->hairs.GetEntity(hairIndex);
const MaterialComponent& material = *vis.scene->materials.GetComponent(entity);
hair.Draw(material, renderPass, cmd);
}
}
}
if (IsWireRender() && !transparent)
return;
RenderImpostors(vis, renderPass, cmd);
uint32_t renderTypeFlags = 0;
if (opaque)
{
@@ -4933,6 +4917,23 @@ void DrawScene(
RenderMeshes(vis, renderQueue, renderPass, renderTypeFlags, cmd, tessellation);
}
if (hairparticle)
{
if (!transparent)
{
for (uint32_t hairIndex : vis.visibleHairs)
{
const wi::HairParticleSystem& hair = vis.scene->hairs[hairIndex];
Entity entity = vis.scene->hairs.GetEntity(hairIndex);
const MaterialComponent& material = *vis.scene->materials.GetComponent(entity);
hair.Draw(material, renderPass, cmd);
}
}
}
RenderImpostors(vis, renderPass, cmd);
device->BindShadingRate(ShadingRate::RATE_1X1, cmd);
device->EventEnd(cmd);
@@ -7776,6 +7777,7 @@ void SurfelGI_Coverage(
device->EventBegin("Indirect args", cmd);
const GPUResource* uavs[] = {
&scene.surfelStatsBuffer,
&scene.surfelIndirectBuffer,
};
device->BindUAVs(uavs, 0, arraysize(uavs), cmd);
@@ -7839,7 +7841,6 @@ void SurfelGI(
device->BindResource(&scene.surfelDataBuffer, 0, cmd);
device->BindResource(&scene.surfelAliveBuffer[0], 1, cmd);
device->BindResource(&scene.surfelMomentsTexture[0], 2, cmd);
const GPUResource* uavs[] = {
&scene.surfelBuffer,
@@ -7847,7 +7848,7 @@ void SurfelGI(
&scene.surfelAliveBuffer[1],
&scene.surfelDeadBuffer,
&scene.surfelStatsBuffer,
&scene.surfelMomentsTexture[1],
&scene.surfelRayBuffer,
};
device->BindUAVs(uavs, 0, arraysize(uavs), cmd);
@@ -7858,7 +7859,7 @@ void SurfelGI(
device->Barrier(barriers, arraysize(barriers), cmd);
}
device->DispatchIndirect(&scene.surfelStatsBuffer, SURFEL_STATS_OFFSET_INDIRECT, cmd);
device->DispatchIndirect(&scene.surfelIndirectBuffer, SURFEL_INDIRECT_OFFSET_ITERATE, cmd);
{
GPUBarrier barriers[] = {
@@ -7924,7 +7925,7 @@ void SurfelGI(
};
device->BindUAVs(uavs, 0, arraysize(uavs), cmd);
device->DispatchIndirect(&scene.surfelStatsBuffer, SURFEL_STATS_OFFSET_INDIRECT, cmd);
device->DispatchIndirect(&scene.surfelIndirectBuffer, SURFEL_INDIRECT_OFFSET_ITERATE, cmd);
{
GPUBarrier barriers[] = {
@@ -7957,6 +7958,40 @@ void SurfelGI(
device->BindResource(&scene.surfelAliveBuffer[0], 4, cmd);
device->BindResource(&scene.surfelMomentsTexture[0], 5, cmd);
const GPUResource* uavs[] = {
&scene.surfelRayBuffer,
};
device->BindUAVs(uavs, 0, arraysize(uavs), cmd);
device->DispatchIndirect(&scene.surfelIndirectBuffer, SURFEL_INDIRECT_OFFSET_RAYTRACE, cmd);
{
GPUBarrier barriers[] = {
GPUBarrier::Memory(),
GPUBarrier::Buffer(&scene.surfelRayBuffer, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE_COMPUTE),
};
device->Barrier(barriers, arraysize(barriers), cmd);
}
device->EventEnd(cmd);
}
// Integrate rays:
{
device->EventBegin("Integrate", cmd);
device->BindComputeShader(&shaders[CSTYPE_SURFEL_INTEGRATE], cmd);
device->BindResource(&scene.surfelBuffer, 0, cmd);
device->BindResource(&scene.surfelStatsBuffer, 1, cmd);
device->BindResource(&scene.surfelGridBuffer, 2, cmd);
device->BindResource(&scene.surfelCellBuffer, 3, cmd);
device->BindResource(&scene.surfelAliveBuffer[0], 4, cmd);
device->BindResource(&scene.surfelMomentsTexture[0], 5, cmd);
device->BindResource(&scene.surfelRayBuffer, 6, cmd);
const GPUResource* uavs[] = {
&scene.surfelDataBuffer,
&scene.surfelMomentsTexture[1],
@@ -7971,7 +8006,7 @@ void SurfelGI(
device->Barrier(barriers, arraysize(barriers), cmd);
}
device->DispatchIndirect(&scene.surfelStatsBuffer, SURFEL_STATS_OFFSET_INDIRECT, cmd);
device->DispatchIndirect(&scene.surfelIndirectBuffer, SURFEL_INDIRECT_OFFSET_INTEGRATE, cmd);
{
GPUBarrier barriers[] = {
+18 -3
View File
@@ -1730,12 +1730,19 @@ namespace wi::scene
device->SetName(&surfelDeadBuffer, "surfelDeadBuffer");
desc.stride = sizeof(uint);
desc.size = desc.stride * 9; // count (1 uint), nextCount (1 uint), deadCount (1 uint), cellAllocator (1 uint), IndirectDispatchArgs (3 uints), raycount (1 uint), shortage (1 uint)
desc.misc_flags = ResourceMiscFlag::BUFFER_RAW | ResourceMiscFlag::INDIRECT_ARGS;
uint stats_data[] = { 0,0,SURFEL_CAPACITY,0,0,0,0,0,0 };
desc.size = SURFEL_STATS_SIZE;
desc.misc_flags = ResourceMiscFlag::BUFFER_RAW;
uint stats_data[] = { 0,0,SURFEL_CAPACITY,0,0,0 };
device->CreateBuffer(&desc, &stats_data, &surfelStatsBuffer);
device->SetName(&surfelStatsBuffer, "surfelStatsBuffer");
desc.stride = sizeof(uint);
desc.size = SURFEL_INDIRECT_SIZE;
desc.misc_flags = ResourceMiscFlag::BUFFER_RAW | ResourceMiscFlag::INDIRECT_ARGS;
uint indirect_data[] = { 0,0,0, 0,0,0, 0,0,0 };
device->CreateBuffer(&desc, &indirect_data, &surfelIndirectBuffer);
device->SetName(&surfelIndirectBuffer, "surfelIndirectBuffer");
desc.stride = sizeof(SurfelGridCell);
desc.size = desc.stride * SURFEL_TABLE_SIZE;
desc.misc_flags = ResourceMiscFlag::BUFFER_STRUCTURED;
@@ -1748,6 +1755,12 @@ namespace wi::scene
device->CreateBuffer(&desc, nullptr, &surfelCellBuffer);
device->SetName(&surfelCellBuffer, "surfelCellBuffer");
desc.stride = sizeof(SurfelRayDataPacked);
desc.size = desc.stride * SURFEL_RAY_BUDGET;
desc.misc_flags = ResourceMiscFlag::BUFFER_STRUCTURED;
device->CreateBuffer(&desc, nullptr, &surfelRayBuffer);
device->SetName(&surfelRayBuffer, "surfelRayBuffer");
TextureDesc tex;
tex.width = SURFEL_MOMENT_ATLAS_TEXELS;
tex.height = SURFEL_MOMENT_ATLAS_TEXELS;
@@ -2967,6 +2980,8 @@ namespace wi::scene
std::swap(mesh.streamoutBuffer_POS, mesh.vertexBuffer_PRE);
}
mesh._flags &= ~MeshComponent::TLAS_FORCE_DOUBLE_SIDED;
uint32_t subsetIndex = 0;
for (auto& subset : mesh.subsets)
{
+2
View File
@@ -1329,8 +1329,10 @@ namespace wi::scene
wi::graphics::GPUBuffer surfelAliveBuffer[2];
wi::graphics::GPUBuffer surfelDeadBuffer;
wi::graphics::GPUBuffer surfelStatsBuffer;
wi::graphics::GPUBuffer surfelIndirectBuffer;
wi::graphics::GPUBuffer surfelGridBuffer;
wi::graphics::GPUBuffer surfelCellBuffer;
wi::graphics::GPUBuffer surfelRayBuffer;
wi::graphics::Texture surfelMomentsTexture[2];
// DDGI resources:
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 60;
// minor bug fixes, alterations, refactors, updates
const int revision = 20;
const int revision = 21;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);
-1
View File
@@ -1,7 +1,6 @@
Feature list
------------
DirectX 11 renderer
DirectX 12 renderer
Vulkan renderer
Image rendering