diff --git a/WickedEngine/offlineshadercompiler.cpp b/WickedEngine/offlineshadercompiler.cpp index 7384eda21..af45ddcc2 100644 --- a/WickedEngine/offlineshadercompiler.cpp +++ b/WickedEngine/offlineshadercompiler.cpp @@ -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", diff --git a/WickedEngine/shaders/ShaderInterop_SurfelGI.h b/WickedEngine/shaders/ShaderInterop_SurfelGI.h index 162334629..ff769c0f4 100644 --- a/WickedEngine/shaders/ShaderInterop_SurfelGI.h +++ b/WickedEngine/shaders/ShaderInterop_SurfelGI.h @@ -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 diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems b/WickedEngine/shaders/Shaders_SOURCE.vcxitems index 179eccd18..2cdbc092a 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems @@ -1018,6 +1018,10 @@ Compute 4.0 + + Compute + 4.0 + Compute 4.0 diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters index f9f2c6d1c..c9b613559 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters @@ -1022,6 +1022,9 @@ CS + + CS + diff --git a/WickedEngine/shaders/brdf.hlsli b/WickedEngine/shaders/brdf.hlsli index b5c29957e..f26beddd7 100644 --- a/WickedEngine/shaders/brdf.hlsli +++ b/WickedEngine/shaders/brdf.hlsli @@ -207,8 +207,6 @@ struct Surface in float4 specularMap = 1 ) { - init(); - if (material.options & SHADERMATERIAL_OPTION_BIT_TRANSPARENT || material.alphaTest > 0) { opacity = baseColor.a; diff --git a/WickedEngine/shaders/ddgi_raytraceCS.hlsl b/WickedEngine/shaders/ddgi_raytraceCS.hlsl index 3dff53472..a97b49576 100644 --- a/WickedEngine/shaders/ddgi_raytraceCS.hlsl +++ b/WickedEngine/shaders/ddgi_raytraceCS.hlsl @@ -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; diff --git a/WickedEngine/shaders/emittedparticlePS_soft.hlsl b/WickedEngine/shaders/emittedparticlePS_soft.hlsl index 24020628f..82a3f9eb2 100644 --- a/WickedEngine/shaders/emittedparticlePS_soft.hlsl +++ b/WickedEngine/shaders/emittedparticlePS_soft.hlsl @@ -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; diff --git a/WickedEngine/shaders/hairparticlePS.hlsl b/WickedEngine/shaders/hairparticlePS.hlsl index 26b64aebb..e8b88b869 100644 --- a/WickedEngine/shaders/hairparticlePS.hlsl +++ b/WickedEngine/shaders/hairparticlePS.hlsl @@ -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; diff --git a/WickedEngine/shaders/raytraceCS.hlsl b/WickedEngine/shaders/raytraceCS.hlsl index ea61c3f6a..6f3c3a093 100644 --- a/WickedEngine/shaders/raytraceCS.hlsl +++ b/WickedEngine/shaders/raytraceCS.hlsl @@ -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; diff --git a/WickedEngine/shaders/raytracingHF.hlsli b/WickedEngine/shaders/raytracingHF.hlsli index 8007b0473..603531858 100644 --- a/WickedEngine/shaders/raytracingHF.hlsli +++ b/WickedEngine/shaders/raytracingHF.hlsli @@ -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; diff --git a/WickedEngine/shaders/renderlightmapPS.hlsl b/WickedEngine/shaders/renderlightmapPS.hlsl index ecb8b03b4..223698b94 100644 --- a/WickedEngine/shaders/renderlightmapPS.hlsl +++ b/WickedEngine/shaders/renderlightmapPS.hlsl @@ -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; diff --git a/WickedEngine/shaders/rtaoCS.hlsl b/WickedEngine/shaders/rtaoCS.hlsl index f2852ffd6..2d83388da 100644 --- a/WickedEngine/shaders/rtaoCS.hlsl +++ b/WickedEngine/shaders/rtaoCS.hlsl @@ -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; diff --git a/WickedEngine/shaders/rtreflectionCS.hlsl b/WickedEngine/shaders/rtreflectionCS.hlsl index 358db255f..4892a1e36 100644 --- a/WickedEngine/shaders/rtreflectionCS.hlsl +++ b/WickedEngine/shaders/rtreflectionCS.hlsl @@ -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; diff --git a/WickedEngine/shaders/rtreflectionLIB.hlsl b/WickedEngine/shaders/rtreflectionLIB.hlsl index 1cedcb5f9..3a7f72cb6 100644 --- a/WickedEngine/shaders/rtreflectionLIB.hlsl +++ b/WickedEngine/shaders/rtreflectionLIB.hlsl @@ -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; diff --git a/WickedEngine/shaders/screenspaceshadowCS.hlsl b/WickedEngine/shaders/screenspaceshadowCS.hlsl index dd8b99066..ddfd184f9 100644 --- a/WickedEngine/shaders/screenspaceshadowCS.hlsl +++ b/WickedEngine/shaders/screenspaceshadowCS.hlsl @@ -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; diff --git a/WickedEngine/shaders/ssr_raytraceCS.hlsl b/WickedEngine/shaders/ssr_raytraceCS.hlsl index a8e5dec78..15db58d35 100644 --- a/WickedEngine/shaders/ssr_raytraceCS.hlsl +++ b/WickedEngine/shaders/ssr_raytraceCS.hlsl @@ -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; diff --git a/WickedEngine/shaders/ssr_resolveCS.hlsl b/WickedEngine/shaders/ssr_resolveCS.hlsl index 7e5f8e7c5..39e5aa590 100644 --- a/WickedEngine/shaders/ssr_resolveCS.hlsl +++ b/WickedEngine/shaders/ssr_resolveCS.hlsl @@ -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; diff --git a/WickedEngine/shaders/ssr_temporalCS.hlsl b/WickedEngine/shaders/ssr_temporalCS.hlsl index 4d35fad53..1a55190f6 100644 --- a/WickedEngine/shaders/ssr_temporalCS.hlsl +++ b/WickedEngine/shaders/ssr_temporalCS.hlsl @@ -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; diff --git a/WickedEngine/shaders/surfel_coverageCS.hlsl b/WickedEngine/shaders/surfel_coverageCS.hlsl index 4fd1b1884..93f89cff0 100644 --- a/WickedEngine/shaders/surfel_coverageCS.hlsl +++ b/WickedEngine/shaders/surfel_coverageCS.hlsl @@ -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... diff --git a/WickedEngine/shaders/surfel_indirectprepareCS.hlsl b/WickedEngine/shaders/surfel_indirectprepareCS.hlsl index be0f517a0..ab63aba7c 100644 --- a/WickedEngine/shaders/surfel_indirectprepareCS.hlsl +++ b/WickedEngine/shaders/surfel_indirectprepareCS.hlsl @@ -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)); } diff --git a/WickedEngine/shaders/surfel_integrateCS.hlsl b/WickedEngine/shaders/surfel_integrateCS.hlsl new file mode 100644 index 000000000..0e1357538 --- /dev/null +++ b/WickedEngine/shaders/surfel_integrateCS.hlsl @@ -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 surfelBuffer : register(t0); +ByteAddressBuffer surfelStatsBuffer : register(t1); +StructuredBuffer surfelGridBuffer : register(t2); +StructuredBuffer surfelCellBuffer : register(t3); +StructuredBuffer surfelAliveBuffer : register(t4); +Texture2D surfelMomentsTexturePrev : register(t5); +StructuredBuffer surfelRayBuffer : register(t6); + +RWStructuredBuffer surfelDataBuffer : register(u0); +RWTexture2D 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; +} diff --git a/WickedEngine/shaders/surfel_raytraceCS.hlsl b/WickedEngine/shaders/surfel_raytraceCS.hlsl index 738b461d0..6a1923b1b 100644 --- a/WickedEngine/shaders/surfel_raytraceCS.hlsl +++ b/WickedEngine/shaders/surfel_raytraceCS.hlsl @@ -12,38 +12,25 @@ StructuredBuffer surfelCellBuffer : register(t3); StructuredBuffer surfelAliveBuffer : register(t4); Texture2D surfelMomentsTexturePrev : register(t5); -RWStructuredBuffer surfelDataBuffer : register(u0); -RWTexture2D 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 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); } diff --git a/WickedEngine/shaders/surfel_updateCS.hlsl b/WickedEngine/shaders/surfel_updateCS.hlsl index dfee65e09..1c5297d22 100644 --- a/WickedEngine/shaders/surfel_updateCS.hlsl +++ b/WickedEngine/shaders/surfel_updateCS.hlsl @@ -4,14 +4,13 @@ StructuredBuffer surfelDataBuffer : register(t0); StructuredBuffer surfelAliveBuffer_CURRENT : register(t1); -Texture2D surfelMomentsTexturePrev : register(t2); RWStructuredBuffer surfelBuffer : register(u0); RWStructuredBuffer surfelGridBuffer : register(u1); RWStructuredBuffer surfelAliveBuffer_NEXT : register(u2); RWStructuredBuffer surfelDeadBuffer : register(u3); RWByteAddressBuffer surfelStatsBuffer : register(u4); -RWTexture2D surfelMomentsTexture : register(u5); +RWStructuredBuffer 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 diff --git a/WickedEngine/shaders/visibility_resolveCS.hlsl b/WickedEngine/shaders/visibility_resolveCS.hlsl index d6404174b..dcc5bb17c 100644 --- a/WickedEngine/shaders/visibility_resolveCS.hlsl +++ b/WickedEngine/shaders/visibility_resolveCS.hlsl @@ -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; diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index 0e382fbcd..6d7482201 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -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, diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index b825fa699..f952ae862 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -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[] = { diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index b4dd58cef..dce175dcf 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -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) { diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 9f097ba70..cd3bf983b 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -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: diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 7eed9fe8f..6ff0f138c 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -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); diff --git a/features.txt b/features.txt index dde7783cb..4267549cd 100644 --- a/features.txt +++ b/features.txt @@ -1,7 +1,6 @@ Feature list ------------ -DirectX 11 renderer DirectX 12 renderer Vulkan renderer Image rendering