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