diff --git a/WickedEngine/offlineshadercompiler.cpp b/WickedEngine/offlineshadercompiler.cpp index c9ba6fe02..bc2091a6b 100644 --- a/WickedEngine/offlineshadercompiler.cpp +++ b/WickedEngine/offlineshadercompiler.cpp @@ -196,7 +196,6 @@ wi::vector shaders = { {"rtao_denoise_filterCS", wi::graphics::ShaderStage::CS }, {"visibility_resolveCS", wi::graphics::ShaderStage::CS }, {"visibility_resolveCS_MSAA", wi::graphics::ShaderStage::CS }, - {"visibility_indirect_prepareCS", wi::graphics::ShaderStage::CS }, {"visibility_velocityCS", wi::graphics::ShaderStage::CS }, {"visibility_skyCS", wi::graphics::ShaderStage::CS }, {"surfel_coverageCS", wi::graphics::ShaderStage::CS }, diff --git a/WickedEngine/shaders/ShaderInterop_Renderer.h b/WickedEngine/shaders/ShaderInterop_Renderer.h index 141b08c94..b6f2d6552 100644 --- a/WickedEngine/shaders/ShaderInterop_Renderer.h +++ b/WickedEngine/shaders/ShaderInterop_Renderer.h @@ -409,21 +409,11 @@ struct ShaderMaterial // For binning shading based on shader types: struct ShaderTypeBin { - uint shaderType; - uint offset; - uint count; - uint padding; - uint dispatchX; uint dispatchY; uint dispatchZ; - uint padding1; - - uint4 padding2[14]; // force 256-byte alignment that's necessary for constant buffers :( + uint shaderType; }; -#ifdef __cplusplus -static_assert(sizeof(ShaderTypeBin) == 256); // 256 byte forced constant buffer alignment for DX12 -#endif // __cplusplus static const uint SHADERTYPE_BIN_COUNT = 10; struct VisibilityTile diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems b/WickedEngine/shaders/Shaders_SOURCE.vcxitems index f24bcac89..746d5f98f 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems @@ -39,6 +39,7 @@ + diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters index 9d4495375..264ed0236 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters @@ -150,6 +150,9 @@ HF + + HF + diff --git a/WickedEngine/shaders/objectHF.hlsli b/WickedEngine/shaders/objectHF.hlsli index 10fdbb51c..f1d4c2659 100644 --- a/WickedEngine/shaders/objectHF.hlsli +++ b/WickedEngine/shaders/objectHF.hlsli @@ -38,6 +38,7 @@ #include "fogHF.hlsli" #include "ShaderInterop_SurfelGI.h" #include "ShaderInterop_DDGI.h" +#include "shadingHF.hlsli" // DEFINITIONS ////////////////// @@ -299,666 +300,6 @@ struct PixelInput }; -// METHODS -//////////// - -inline void LightMapping(in int lightmap, in float2 ATLAS, inout Lighting lighting, inout Surface surface) -{ - [branch] - if (lightmap >= 0 && any(ATLAS)) - { - Texture2D texture_lightmap = bindless_textures[NonUniformResourceIndex(lightmap)]; -#ifdef LIGHTMAP_QUALITY_BICUBIC - lighting.indirect.diffuse = SampleTextureCatmullRom(texture_lightmap, sampler_linear_clamp, ATLAS).rgb; -#else - lighting.indirect.diffuse = texture_lightmap.SampleLevel(sampler_linear_clamp, ATLAS, 0).rgb; -#endif // LIGHTMAP_QUALITY_BICUBIC - - surface.flags |= SURFACE_FLAG_GI_APPLIED; - } -} - -inline float3 PlanarReflection(in Surface surface, in float2 bumpColor) -{ - [branch] - if (GetCamera().texture_reflection_index >= 0) - { - float4 reflectionUV = mul(GetCamera().reflection_view_projection, float4(surface.P, 1)); - reflectionUV.xy /= reflectionUV.w; - reflectionUV.xy = clipspace_to_uv(reflectionUV.xy); - return bindless_textures[GetCamera().texture_reflection_index].SampleLevel(sampler_linear_clamp, reflectionUV.xy + bumpColor, 0).rgb; - } - return 0; -} - -inline void ParallaxOcclusionMapping(inout float4 uvsets, in float3 V, in float3x3 TBN) -{ - [branch] - if (!GetMaterial().textures[DISPLACEMENTMAP].IsValid()) - return; - Texture2D tex = bindless_textures[GetMaterial().textures[DISPLACEMENTMAP].texture_descriptor]; - float2 uv = GetMaterial().textures[DISPLACEMENTMAP].GetUVSet() == 0 ? uvsets.xy : uvsets.zw; - float2 uv_dx = ddx_coarse(uv); - float2 uv_dy = ddy_coarse(uv); - - ParallaxOcclusionMapping_Impl( - uvsets, - V, - TBN, - GetMaterial(), - tex, - uv, - uv_dx, - uv_dy - ); -} - -inline void ForwardLighting(inout Surface surface, inout Lighting lighting) -{ -#ifndef DISABLE_ENVMAPS - // Apply environment maps: - float4 envmapAccumulation = 0; - -#ifndef ENVMAPRENDERING -#ifndef DISABLE_LOCALENVPMAPS - [branch] - if (xForwardEnvProbeMask != 0) - { - uint bucket_bits = xForwardEnvProbeMask; - - [loop] - while (bucket_bits != 0) - { - // Retrieve global entity index from local bucket, then remove bit from local bucket: - const uint bucket_bit_index = firstbitlow(bucket_bits); - const uint entity_index = bucket_bit_index; - bucket_bits ^= 1u << bucket_bit_index; - - [branch] - if (envmapAccumulation.a < 1) - { - ShaderEntity probe = load_entity(GetFrame().envprobearray_offset + entity_index); - if ((probe.layerMask & surface.layerMask) == 0) - continue; - - const float4x4 probeProjection = load_entitymatrix(probe.GetMatrixIndex()); - const float3 clipSpacePos = mul(probeProjection, float4(surface.P, 1)).xyz; - const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); - [branch] - if (is_saturated(uvw)) - { - const float4 envmapColor = EnvironmentReflection_Local(surface, probe, probeProjection, clipSpacePos); - // perform manual blending of probes: - // NOTE: they are sorted top-to-bottom, but blending is performed bottom-to-top - envmapAccumulation.rgb = mad(1 - envmapAccumulation.a, envmapColor.a * envmapColor.rgb, envmapAccumulation.rgb); - envmapAccumulation.a = mad(1 - envmapColor.a, envmapAccumulation.a, envmapColor.a); - [branch] - if (envmapAccumulation.a >= 1.0) - { - // force exit: - break; - } - } - } - else - { - // force exit: - break; - } - - } - } -#endif // DISABLE_LOCALENVPMAPS -#endif //ENVMAPRENDERING - - // Apply global envmap where there is no local envmap information: - [branch] - if (envmapAccumulation.a < 0.99) - { - envmapAccumulation.rgb = lerp(EnvironmentReflection_Global(surface), envmapAccumulation.rgb, envmapAccumulation.a); - } - lighting.indirect.specular += max(0, envmapAccumulation.rgb); -#endif // DISABLE_ENVMAPS - -#ifndef DISABLE_VOXELGI - VoxelGI(surface, lighting); -#endif //DISABLE_VOXELGI - - [branch] - if (any(xForwardLightMask)) - { - // Loop through light buckets for the draw call: - const uint first_item = 0; - const uint last_item = first_item + GetFrame().lightarray_count - 1; - const uint first_bucket = first_item / 32; - const uint last_bucket = min(last_item / 32, 1); // only 2 buckets max (uint2) for forward pass! - [loop] - for (uint bucket = first_bucket; bucket <= last_bucket; ++bucket) - { - uint bucket_bits = xForwardLightMask[bucket]; - - [loop] - while (bucket_bits != 0) - { - // Retrieve global entity index from local bucket, then remove bit from local bucket: - const uint bucket_bit_index = firstbitlow(bucket_bits); - const uint entity_index = bucket * 32 + bucket_bit_index; - bucket_bits ^= 1u << bucket_bit_index; - - ShaderEntity light = load_entity(GetFrame().lightarray_offset + entity_index); - if ((light.layerMask & surface.layerMask) == 0) - continue; - - if (light.GetFlags() & ENTITY_FLAG_LIGHT_STATIC) - { - continue; // static lights will be skipped (they are used in lightmap baking) - } - - switch (light.GetType()) - { - case ENTITY_TYPE_DIRECTIONALLIGHT: - { - light_directional(light, surface, lighting); - } - break; - case ENTITY_TYPE_POINTLIGHT: - { - light_point(light, surface, lighting); - } - break; - case ENTITY_TYPE_SPOTLIGHT: - { - light_spot(light, surface, lighting); - } - break; - } - } - } - } - - [branch] - if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetScene().ddgi.color_texture >= 0) - { - lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N); - surface.flags |= SURFACE_FLAG_GI_APPLIED; - } - -} - -inline void ForwardDecals(inout Surface surface, inout float4 surfaceMap) -{ -#ifndef DISABLE_DECALS - [branch] - if (xForwardDecalMask == 0) - return; - - // decals are enabled, loop through them first: - float4 decalAccumulation = 0; - float4 decalBumpAccumulation = 0; - float4 decalSurfaceAccumulation = 0; - float decalSurfaceAccumulationAlpha = 0; - const float3 P_dx = ddx_coarse(surface.P); - const float3 P_dy = ddy_coarse(surface.P); - - uint bucket_bits = xForwardDecalMask; - - [loop] - while (bucket_bits != 0 && decalAccumulation.a < 1 && decalBumpAccumulation.a < 1 && decalSurfaceAccumulationAlpha < 1) - { - // Retrieve global entity index from local bucket, then remove bit from local bucket: - const uint bucket_bit_index = firstbitlow(bucket_bits); - const uint entity_index = bucket_bit_index; - bucket_bits ^= 1u << bucket_bit_index; - - ShaderEntity decal = load_entity(GetFrame().decalarray_offset + entity_index); - if ((decal.layerMask & surface.layerMask) == 0) - continue; - - float4x4 decalProjection = load_entitymatrix(decal.GetMatrixIndex()); - int decalTexture = asint(decalProjection[3][0]); - int decalNormal = asint(decalProjection[3][1]); - float decalNormalStrength = decalProjection[3][2]; - int decalSurfacemap = asint(decalProjection[3][3]); - decalProjection[3] = float4(0, 0, 0, 1); - const float3 clipSpacePos = mul(decalProjection, float4(surface.P, 1)).xyz; - float3 uvw = clipspace_to_uv(clipSpacePos.xyz); - [branch] - if (is_saturated(uvw)) - { - uvw.xy = mad(uvw.xy, decal.shadowAtlasMulAdd.xy, decal.shadowAtlasMulAdd.zw); - // mipmapping needs to be performed by hand: - const float2 decalDX = mul(P_dx, (float3x3)decalProjection).xy; - const float2 decalDY = mul(P_dy, (float3x3)decalProjection).xy; - float4 decalColor = decal.GetColor(); - // blend out if close to cube Z: - const float edgeBlend = 1 - pow(saturate(abs(clipSpacePos.z)), 8); - const float slopeBlend = decal.GetConeAngleCos() > 0 ? pow(saturate(dot(surface.N, decal.GetDirection())), decal.GetConeAngleCos()) : 1; - decalColor.a *= edgeBlend * slopeBlend; - [branch] - if (decalTexture >= 0) - { - decalColor *= bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sampler_objectshader, uvw.xy, decalDX, decalDY); - if ((decal.GetFlags() & ENTITY_FLAG_DECAL_BASECOLOR_ONLY_ALPHA) == 0) - { - // perform manual blending of decals: - // NOTE: they are sorted top-to-bottom, but blending is performed bottom-to-top - decalAccumulation.rgb = mad(1 - decalAccumulation.a, decalColor.a * decalColor.rgb, decalAccumulation.rgb); - decalAccumulation.a = mad(1 - decalColor.a, decalAccumulation.a, decalColor.a); - } - } - [branch] - if (decalNormal >= 0) - { - float3 decalBumpColor = float3(bindless_textures[NonUniformResourceIndex(decalNormal)].SampleGrad(sampler_objectshader, uvw.xy, decalDX, decalDY).rg, 1); - decalBumpColor = decalBumpColor * 2 - 1; - decalBumpColor.rg *= decalNormalStrength; - decalBumpAccumulation.rgb = mad(1 - decalBumpAccumulation.a, decalColor.a * decalBumpColor.rgb, decalBumpAccumulation.rgb); - decalBumpAccumulation.a = mad(1 - decalColor.a, decalBumpAccumulation.a, decalColor.a); - } - [branch] - if (decalSurfacemap >= 0) - { - float4 decalSurfaceColor = bindless_textures[NonUniformResourceIndex(decalSurfacemap)].SampleGrad(sampler_objectshader, uvw.xy, decalDX, decalDY); - decalSurfaceAccumulation = mad(1 - decalSurfaceAccumulationAlpha, decalColor.a * decalSurfaceColor, decalSurfaceAccumulation); - decalSurfaceAccumulationAlpha = mad(1 - decalColor.a, decalSurfaceAccumulationAlpha, decalColor.a); - } - } - } - - surface.baseColor.rgb = mad(surface.baseColor.rgb, 1 - decalAccumulation.a, decalAccumulation.rgb); - surface.bumpColor.rgb = mad(surface.bumpColor.rgb, 1 - decalBumpAccumulation.a, decalBumpAccumulation.rgb); - surfaceMap = mad(surfaceMap, 1 - decalSurfaceAccumulationAlpha, decalSurfaceAccumulation); -#endif // DISABLE_DECALS -} - -inline uint GetFlatTileIndex(uint2 pixel) -{ - const uint2 tileIndex = uint2(floor(pixel / TILED_CULLING_BLOCKSIZE)); - return flatten2D(tileIndex, GetCamera().entity_culling_tilecount.xy) * SHADER_ENTITY_TILE_BUCKET_COUNT; -} - -inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint flatTileIndex) -{ -#ifndef DISABLE_ENVMAPS - // Apply environment maps: - float4 envmapAccumulation = 0; - -#ifndef DISABLE_LOCALENVPMAPS - [branch] - if (GetFrame().envprobearray_count > 0) - { - // Loop through envmap buckets in the tile: - const uint first_item = GetFrame().envprobearray_offset; - const uint last_item = first_item + GetFrame().envprobearray_count - 1; - const uint first_bucket = first_item / 32; - const uint last_bucket = min(last_item / 32, max(0, SHADER_ENTITY_TILE_BUCKET_COUNT - 1)); - [loop] - for (uint bucket = first_bucket; bucket <= last_bucket; ++bucket) - { - uint bucket_bits = load_entitytile(flatTileIndex + bucket); - -#ifndef ENTITY_TILE_UNIFORM - // Bucket scalarizer - Siggraph 2017 - Improved Culling [Michal Drobot]: - bucket_bits = WaveReadLaneFirst(WaveActiveBitOr(bucket_bits)); -#endif // ENTITY_TILE_UNIFORM - - [loop] - while (bucket_bits != 0) - { - // Retrieve global entity index from local bucket, then remove bit from local bucket: - const uint bucket_bit_index = firstbitlow(bucket_bits); - const uint entity_index = bucket * 32 + bucket_bit_index; - bucket_bits ^= 1u << bucket_bit_index; - - [branch] - if (entity_index >= first_item && entity_index <= last_item && envmapAccumulation.a < 1) - { - ShaderEntity probe = load_entity(entity_index); - if ((probe.layerMask & surface.layerMask) == 0) - continue; - - const float4x4 probeProjection = load_entitymatrix(probe.GetMatrixIndex()); - const float3 clipSpacePos = mul(probeProjection, float4(surface.P, 1)).xyz; - const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); - [branch] - if (is_saturated(uvw)) - { - const float4 envmapColor = EnvironmentReflection_Local(surface, probe, probeProjection, clipSpacePos); - // perform manual blending of probes: - // NOTE: they are sorted top-to-bottom, but blending is performed bottom-to-top - envmapAccumulation.rgb = mad(1 - envmapAccumulation.a, envmapColor.a * envmapColor.rgb, envmapAccumulation.rgb); - envmapAccumulation.a = mad(1 - envmapColor.a, envmapAccumulation.a, envmapColor.a); - [branch] - if (envmapAccumulation.a >= 1.0) - { - // force exit: - bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; - break; - } - } - } - else if (entity_index > last_item) - { - // force exit: - bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; - break; - } - - } - } - } -#endif // DISABLE_LOCALENVPMAPS - - // Apply global envmap where there is no local envmap information: - [branch] - if (envmapAccumulation.a < 0.99) - { - envmapAccumulation.rgb = lerp(EnvironmentReflection_Global(surface), envmapAccumulation.rgb, envmapAccumulation.a); - } - lighting.indirect.specular += max(0, envmapAccumulation.rgb); -#endif // DISABLE_ENVMAPS - -#ifndef DISABLE_VOXELGI -#ifdef TRANSPARENT // opaque tiled forward: voxel GI was rendered in separate pass - VoxelGI(surface, lighting); -#endif // TRANSPARENT -#endif //DISABLE_VOXELGI - - [branch] - if (GetFrame().lightarray_count > 0) - { - // Loop through light buckets in the tile: - const uint first_item = GetFrame().lightarray_offset; - const uint last_item = first_item + GetFrame().lightarray_count - 1; - const uint first_bucket = first_item / 32; - const uint last_bucket = min(last_item / 32, max(0, SHADER_ENTITY_TILE_BUCKET_COUNT - 1)); - [loop] - for (uint bucket = first_bucket; bucket <= last_bucket; ++bucket) - { - uint bucket_bits = load_entitytile(flatTileIndex + bucket); - -#ifndef ENTITY_TILE_UNIFORM - // Bucket scalarizer - Siggraph 2017 - Improved Culling [Michal Drobot]: - bucket_bits = WaveReadLaneFirst(WaveActiveBitOr(bucket_bits)); -#endif // ENTITY_TILE_UNIFORM - - [loop] - while (bucket_bits != 0) - { - // Retrieve global entity index from local bucket, then remove bit from local bucket: - const uint bucket_bit_index = firstbitlow(bucket_bits); - const uint entity_index = bucket * 32 + bucket_bit_index; - bucket_bits ^= 1u << bucket_bit_index; - - // Check if it is a light and process: - [branch] - if (entity_index >= first_item && entity_index <= last_item) - { - ShaderEntity light = load_entity(entity_index); - if ((light.layerMask & surface.layerMask) == 0) - continue; - - if (light.GetFlags() & ENTITY_FLAG_LIGHT_STATIC) - { - continue; // static lights will be skipped (they are used in lightmap baking) - } - -#if defined(SHADOW_MASK_ENABLED) && !defined(TRANSPARENT) - const bool shadow_mask_enabled = (GetFrame().options & OPTION_BIT_SHADOW_MASK) && GetCamera().texture_rtshadow_index >= 0; - float shadow_mask = 1; - [branch] - if (shadow_mask_enabled && light.IsCastingShadow()) - { - uint shadow_index = entity_index - GetFrame().lightarray_offset; - if (shadow_index < 16) - { - uint mask_shift = (shadow_index % 4) * 8; - uint mask_bucket = shadow_index / 4; - uint mask = (bindless_textures_uint4[GetCamera().texture_rtshadow_index][surface.pixel][mask_bucket] >> mask_shift) & 0xFF; - if (mask == 0) - { - continue; - } - shadow_mask = mask / 255.0; - } - } -#else - const float shadow_mask = 1; -#endif // SHADOW_MASK_ENABLED - - switch (light.GetType()) - { - case ENTITY_TYPE_DIRECTIONALLIGHT: - { - light_directional(light, surface, lighting, shadow_mask); - } - break; - case ENTITY_TYPE_POINTLIGHT: - { - light_point(light, surface, lighting, shadow_mask); - } - break; - case ENTITY_TYPE_SPOTLIGHT: - { - light_spot(light, surface, lighting, shadow_mask); - } - break; - } - } - else if (entity_index > last_item) - { - // force exit: - bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; - break; - } - - } - } - } - -#ifndef TRANSPARENT - [branch] - if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetCamera().texture_rtdiffuse_index >= 0) - { - lighting.indirect.diffuse = bindless_textures[GetCamera().texture_rtdiffuse_index][surface.pixel].rgb; - surface.flags |= SURFACE_FLAG_GI_APPLIED; - } - - [branch] - if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetFrame().options & OPTION_BIT_SURFELGI_ENABLED && GetCamera().texture_surfelgi_index >= 0 && surfel_cellvalid(surfel_cell(surface.P))) - { - lighting.indirect.diffuse = bindless_textures[GetCamera().texture_surfelgi_index][surface.pixel].rgb; - surface.flags |= SURFACE_FLAG_GI_APPLIED; - } - - [branch] - if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetCamera().texture_vxgi_diffuse_index >= 0) - { - lighting.indirect.diffuse = bindless_textures[GetCamera().texture_vxgi_diffuse_index][surface.pixel].rgb; - surface.flags |= SURFACE_FLAG_GI_APPLIED; - } - [branch] - if (GetCamera().texture_vxgi_specular_index >= 0) - { - float4 vxgi_specular = bindless_textures[GetCamera().texture_vxgi_specular_index][surface.pixel]; - lighting.indirect.specular = vxgi_specular.rgb * surface.F + lighting.indirect.specular * (1 - vxgi_specular.a); - } -#endif // TRANSPARENT - - [branch] - if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetScene().ddgi.color_texture >= 0) - { - lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N); - surface.flags |= SURFACE_FLAG_GI_APPLIED; - } - -} - -inline void TiledDecals(inout Surface surface, uint flatTileIndex, inout float4 surfaceMap) -{ -#ifndef DISABLE_DECALS - [branch] - if (GetFrame().decalarray_count == 0) - return; - - // decals are enabled, loop through them first: - float4 decalAccumulation = 0; - float4 decalBumpAccumulation = 0; - float4 decalSurfaceAccumulation = 0; - float decalSurfaceAccumulationAlpha = 0; - -#ifdef SURFACE_LOAD_QUAD_DERIVATIVES - const float3 P_dx = surface.P_dx; - const float3 P_dy = surface.P_dy; -#else - const float3 P_dx = ddx_coarse(surface.P); - const float3 P_dy = ddy_coarse(surface.P); -#endif // SURFACE_LOAD_QUAD_DERIVATIVES - - // Loop through decal buckets in the tile: - const uint first_item = GetFrame().decalarray_offset; - const uint last_item = first_item + GetFrame().decalarray_count - 1; - const uint first_bucket = first_item / 32; - const uint last_bucket = min(last_item / 32, max(0, SHADER_ENTITY_TILE_BUCKET_COUNT - 1)); - [loop] - for (uint bucket = first_bucket; bucket <= last_bucket; ++bucket) - { - uint bucket_bits = load_entitytile(flatTileIndex + bucket); - -#ifndef ENTITY_TILE_UNIFORM - // This is the wave scalarizer from Improved Culling - Siggraph 2017 [Drobot]: - bucket_bits = WaveReadLaneFirst(WaveActiveBitOr(bucket_bits)); -#endif // ENTITY_TILE_UNIFORM - - [loop] - while (bucket_bits != 0 && decalAccumulation.a < 1 && decalBumpAccumulation.a < 1 && decalSurfaceAccumulationAlpha < 1) - { - // Retrieve global entity index from local bucket, then remove bit from local bucket: - const uint bucket_bit_index = firstbitlow(bucket_bits); - const uint entity_index = bucket * 32 + bucket_bit_index; - bucket_bits ^= 1u << bucket_bit_index; - - [branch] - if (entity_index >= first_item && entity_index <= last_item) - { - ShaderEntity decal = load_entity(entity_index); - if ((decal.layerMask & surface.layerMask) == 0) - continue; - - float4x4 decalProjection = load_entitymatrix(decal.GetMatrixIndex()); - int decalTexture = asint(decalProjection[3][0]); - int decalNormal = asint(decalProjection[3][1]); - float decalNormalStrength = decalProjection[3][2]; - int decalSurfacemap = asint(decalProjection[3][3]); - decalProjection[3] = float4(0, 0, 0, 1); - const float3 clipSpacePos = mul(decalProjection, float4(surface.P, 1)).xyz; - float3 uvw = clipspace_to_uv(clipSpacePos.xyz); - [branch] - if (is_saturated(uvw)) - { - uvw.xy = mad(uvw.xy, decal.shadowAtlasMulAdd.xy, decal.shadowAtlasMulAdd.zw); - // mipmapping needs to be performed by hand: - const float2 decalDX = mul(P_dx, (float3x3)decalProjection).xy; - const float2 decalDY = mul(P_dy, (float3x3)decalProjection).xy; - float4 decalColor = decal.GetColor(); - // blend out if close to cube Z: - const float edgeBlend = 1 - pow(saturate(abs(clipSpacePos.z)), 8); - const float slopeBlend = decal.GetConeAngleCos() > 0 ? pow(saturate(dot(surface.N, decal.GetDirection())), decal.GetConeAngleCos()) : 1; - decalColor.a *= edgeBlend * slopeBlend; - [branch] - if (decalTexture >= 0) - { - decalColor *= bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sampler_objectshader, uvw.xy, decalDX, decalDY); - if ((decal.GetFlags() & ENTITY_FLAG_DECAL_BASECOLOR_ONLY_ALPHA) == 0) - { - // perform manual blending of decals: - // NOTE: they are sorted top-to-bottom, but blending is performed bottom-to-top - decalAccumulation.rgb = mad(1 - decalAccumulation.a, decalColor.a * decalColor.rgb, decalAccumulation.rgb); - decalAccumulation.a = mad(1 - decalColor.a, decalAccumulation.a, decalColor.a); - } - } - [branch] - if (decalNormal >= 0) - { - float3 decalBumpColor = float3(bindless_textures[NonUniformResourceIndex(decalNormal)].SampleGrad(sampler_objectshader, uvw.xy, decalDX, decalDY).rg, 1); - decalBumpColor = decalBumpColor * 2 - 1; - decalBumpColor.rg *= decalNormalStrength; - decalBumpAccumulation.rgb = mad(1 - decalBumpAccumulation.a, decalColor.a * decalBumpColor.rgb, decalBumpAccumulation.rgb); - decalBumpAccumulation.a = mad(1 - decalColor.a, decalBumpAccumulation.a, decalColor.a); - } - [branch] - if (decalSurfacemap >= 0) - { - float4 decalSurfaceColor = bindless_textures[NonUniformResourceIndex(decalSurfacemap)].SampleGrad(sampler_objectshader, uvw.xy, decalDX, decalDY); - decalSurfaceAccumulation = mad(1 - decalSurfaceAccumulationAlpha, decalColor.a * decalSurfaceColor, decalSurfaceAccumulation); - decalSurfaceAccumulationAlpha = mad(1 - decalColor.a, decalSurfaceAccumulationAlpha, decalColor.a); - } - } - } - else if (entity_index > last_item) - { - // force exit: - bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; - break; - } - - } - } - - surface.baseColor.rgb = mad(surface.baseColor.rgb, 1 - decalAccumulation.a, decalAccumulation.rgb); - surface.bumpColor.rgb = mad(surface.bumpColor.rgb, 1 - decalBumpAccumulation.a, decalBumpAccumulation.rgb); - surfaceMap = mad(surfaceMap, 1 - decalSurfaceAccumulationAlpha, decalSurfaceAccumulation); -#endif // DISABLE_DECALS -} - -inline void ApplyFog(in float distance, float3 V, inout float4 color) -{ - const float4 fog = GetFog(distance, GetCamera().position, -V); - //color.rgb = (1.0 - fog.a) * color.rgb + fog.rgb; // premultiplied fog - color.rgb = lerp(color.rgb, fog.rgb, fog.a); // non-premultiplied fog -} - -inline void ApplyAerialPerspective(float2 uv, float3 P, inout float4 color) -{ - if (GetFrame().options & OPTION_BIT_REALISTIC_SKY_AERIAL_PERSPECTIVE) - { - const float4 AP = GetAerialPerspectiveTransmittance(uv, P, GetCamera().position, texture_cameravolumelut); - color.rgb = color.rgb * (1.0 - AP.a) + AP.rgb; - } -} - -inline uint AlphaToCoverage(float alpha, float alphaTest, float4 svposition) -{ - if (alphaTest == 0) - { - // No alpha test, force full coverage: - return ~0u; - } - - if (GetFrame().options & OPTION_BIT_TEMPORALAA_ENABLED) - { - // When Temporal AA is enabled, dither the alpha mask with animated blue noise: - alpha -= blue_noise(svposition.xy, svposition.w).x / GetCamera().sample_count; - } - else if (GetCamera().sample_count > 1) - { - // Without Temporal AA, use static dithering: - alpha -= dither(svposition.xy) / GetCamera().sample_count; - } - else - { - // Without Temporal AA and MSAA, regular alpha test behaviour will be used: - alpha -= alphaTest; - } - - if (alpha > 0) - { - return ~0u >> (31u - uint(alpha * GetCamera().sample_count)); - } - return 0; -} - - // OBJECT SHADER PROTOTYPE /////////////////////////// @@ -1116,7 +457,25 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target #endif #ifdef PARALLAXOCCLUSIONMAPPING - ParallaxOcclusionMapping(input.uvsets, surface.V, TBN); + [branch] + if (GetMaterial().textures[DISPLACEMENTMAP].IsValid()) + { + Texture2D tex = bindless_textures[GetMaterial().textures[DISPLACEMENTMAP].texture_descriptor]; + float2 uv = GetMaterial().textures[DISPLACEMENTMAP].GetUVSet() == 0 ? input.uvsets.xy : input.uvsets.zw; + float2 uv_dx = ddx_coarse(uv); + float2 uv_dy = ddy_coarse(uv); + + ParallaxOcclusionMapping_Impl( + input.uvsets, + surface.V, + TBN, + GetMaterial(), + tex, + uv, + uv_dx, + uv_dy + ); + } #endif // PARALLAXOCCLUSIONMAPPING #endif // OBJECTSHADER_USE_TANGENT @@ -1192,11 +551,11 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target #ifndef PREPASS #ifndef WATER #ifdef FORWARD - ForwardDecals(surface, surfaceMap); + ForwardDecals(surface, surfaceMap, sampler_objectshader); #endif // FORWARD #ifdef TILEDFORWARD - TiledDecals(surface, flat_tile_index, surfaceMap); + TiledDecals(surface, flat_tile_index, surfaceMap, sampler_objectshader); #endif // TILEDFORWARD #endif // WATER #endif // PREPASS diff --git a/WickedEngine/shaders/shadingHF.hlsli b/WickedEngine/shaders/shadingHF.hlsli new file mode 100644 index 000000000..42211d8be --- /dev/null +++ b/WickedEngine/shaders/shadingHF.hlsli @@ -0,0 +1,644 @@ +#ifndef WI_SHADING_HF +#define WI_SHADING_HF +#include "globals.hlsli" +#include "surfaceHF.hlsli" +#include "lightingHF.hlsli" +#include "brdf.hlsli" +#include "ShaderInterop_SurfelGI.h" +#include "ShaderInterop_DDGI.h" + +inline void LightMapping(in int lightmap, in float2 ATLAS, inout Lighting lighting, inout Surface surface) +{ + [branch] + if (lightmap >= 0 && any(ATLAS)) + { + Texture2D texture_lightmap = bindless_textures[NonUniformResourceIndex(lightmap)]; +#ifdef LIGHTMAP_QUALITY_BICUBIC + lighting.indirect.diffuse = SampleTextureCatmullRom(texture_lightmap, sampler_linear_clamp, ATLAS).rgb; +#else + lighting.indirect.diffuse = texture_lightmap.SampleLevel(sampler_linear_clamp, ATLAS, 0).rgb; +#endif // LIGHTMAP_QUALITY_BICUBIC + + surface.flags |= SURFACE_FLAG_GI_APPLIED; + } +} + +inline float3 PlanarReflection(in Surface surface, in float2 bumpColor) +{ + [branch] + if (GetCamera().texture_reflection_index >= 0) + { + float4 reflectionUV = mul(GetCamera().reflection_view_projection, float4(surface.P, 1)); + reflectionUV.xy /= reflectionUV.w; + reflectionUV.xy = clipspace_to_uv(reflectionUV.xy); + return bindless_textures[GetCamera().texture_reflection_index].SampleLevel(sampler_linear_clamp, reflectionUV.xy + bumpColor, 0).rgb; + } + return 0; +} + +inline void ForwardLighting(inout Surface surface, inout Lighting lighting) +{ +#ifndef DISABLE_ENVMAPS + // Apply environment maps: + float4 envmapAccumulation = 0; + +#ifndef ENVMAPRENDERING +#ifndef DISABLE_LOCALENVPMAPS + [branch] + if (xForwardEnvProbeMask != 0) + { + uint bucket_bits = xForwardEnvProbeMask; + + [loop] + while (bucket_bits != 0) + { + // Retrieve global entity index from local bucket, then remove bit from local bucket: + const uint bucket_bit_index = firstbitlow(bucket_bits); + const uint entity_index = bucket_bit_index; + bucket_bits ^= 1u << bucket_bit_index; + + [branch] + if (envmapAccumulation.a < 1) + { + ShaderEntity probe = load_entity(GetFrame().envprobearray_offset + entity_index); + if ((probe.layerMask & surface.layerMask) == 0) + continue; + + const float4x4 probeProjection = load_entitymatrix(probe.GetMatrixIndex()); + const float3 clipSpacePos = mul(probeProjection, float4(surface.P, 1)).xyz; + const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); + [branch] + if (is_saturated(uvw)) + { + const float4 envmapColor = EnvironmentReflection_Local(surface, probe, probeProjection, clipSpacePos); + // perform manual blending of probes: + // NOTE: they are sorted top-to-bottom, but blending is performed bottom-to-top + envmapAccumulation.rgb = mad(1 - envmapAccumulation.a, envmapColor.a * envmapColor.rgb, envmapAccumulation.rgb); + envmapAccumulation.a = mad(1 - envmapColor.a, envmapAccumulation.a, envmapColor.a); + [branch] + if (envmapAccumulation.a >= 1.0) + { + // force exit: + break; + } + } + } + else + { + // force exit: + break; + } + + } + } +#endif // DISABLE_LOCALENVPMAPS +#endif //ENVMAPRENDERING + + // Apply global envmap where there is no local envmap information: + [branch] + if (envmapAccumulation.a < 0.99) + { + envmapAccumulation.rgb = lerp(EnvironmentReflection_Global(surface), envmapAccumulation.rgb, envmapAccumulation.a); + } + lighting.indirect.specular += max(0, envmapAccumulation.rgb); +#endif // DISABLE_ENVMAPS + +#ifndef DISABLE_VOXELGI + VoxelGI(surface, lighting); +#endif //DISABLE_VOXELGI + + [branch] + if (any(xForwardLightMask)) + { + // Loop through light buckets for the draw call: + const uint first_item = 0; + const uint last_item = first_item + GetFrame().lightarray_count - 1; + const uint first_bucket = first_item / 32; + const uint last_bucket = min(last_item / 32, 1); // only 2 buckets max (uint2) for forward pass! + [loop] + for (uint bucket = first_bucket; bucket <= last_bucket; ++bucket) + { + uint bucket_bits = xForwardLightMask[bucket]; + + [loop] + while (bucket_bits != 0) + { + // Retrieve global entity index from local bucket, then remove bit from local bucket: + const uint bucket_bit_index = firstbitlow(bucket_bits); + const uint entity_index = bucket * 32 + bucket_bit_index; + bucket_bits ^= 1u << bucket_bit_index; + + ShaderEntity light = load_entity(GetFrame().lightarray_offset + entity_index); + if ((light.layerMask & surface.layerMask) == 0) + continue; + + if (light.GetFlags() & ENTITY_FLAG_LIGHT_STATIC) + { + continue; // static lights will be skipped (they are used in lightmap baking) + } + + switch (light.GetType()) + { + case ENTITY_TYPE_DIRECTIONALLIGHT: + { + light_directional(light, surface, lighting); + } + break; + case ENTITY_TYPE_POINTLIGHT: + { + light_point(light, surface, lighting); + } + break; + case ENTITY_TYPE_SPOTLIGHT: + { + light_spot(light, surface, lighting); + } + break; + } + } + } + } + + [branch] + if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetScene().ddgi.color_texture >= 0) + { + lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N); + surface.flags |= SURFACE_FLAG_GI_APPLIED; + } + +} + +inline void ForwardDecals(inout Surface surface, inout float4 surfaceMap, SamplerState sam) +{ +#ifndef DISABLE_DECALS + [branch] + if (xForwardDecalMask == 0) + return; + + // decals are enabled, loop through them first: + float4 decalAccumulation = 0; + float4 decalBumpAccumulation = 0; + float4 decalSurfaceAccumulation = 0; + float decalSurfaceAccumulationAlpha = 0; + const float3 P_dx = ddx_coarse(surface.P); + const float3 P_dy = ddy_coarse(surface.P); + + uint bucket_bits = xForwardDecalMask; + + [loop] + while (bucket_bits != 0 && decalAccumulation.a < 1 && decalBumpAccumulation.a < 1 && decalSurfaceAccumulationAlpha < 1) + { + // Retrieve global entity index from local bucket, then remove bit from local bucket: + const uint bucket_bit_index = firstbitlow(bucket_bits); + const uint entity_index = bucket_bit_index; + bucket_bits ^= 1u << bucket_bit_index; + + ShaderEntity decal = load_entity(GetFrame().decalarray_offset + entity_index); + if ((decal.layerMask & surface.layerMask) == 0) + continue; + + float4x4 decalProjection = load_entitymatrix(decal.GetMatrixIndex()); + int decalTexture = asint(decalProjection[3][0]); + int decalNormal = asint(decalProjection[3][1]); + float decalNormalStrength = decalProjection[3][2]; + int decalSurfacemap = asint(decalProjection[3][3]); + decalProjection[3] = float4(0, 0, 0, 1); + const float3 clipSpacePos = mul(decalProjection, float4(surface.P, 1)).xyz; + float3 uvw = clipspace_to_uv(clipSpacePos.xyz); + [branch] + if (is_saturated(uvw)) + { + uvw.xy = mad(uvw.xy, decal.shadowAtlasMulAdd.xy, decal.shadowAtlasMulAdd.zw); + // mipmapping needs to be performed by hand: + const float2 decalDX = mul(P_dx, (float3x3)decalProjection).xy; + const float2 decalDY = mul(P_dy, (float3x3)decalProjection).xy; + float4 decalColor = decal.GetColor(); + // blend out if close to cube Z: + const float edgeBlend = 1 - pow(saturate(abs(clipSpacePos.z)), 8); + const float slopeBlend = decal.GetConeAngleCos() > 0 ? pow(saturate(dot(surface.N, decal.GetDirection())), decal.GetConeAngleCos()) : 1; + decalColor.a *= edgeBlend * slopeBlend; + [branch] + if (decalTexture >= 0) + { + decalColor *= bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sam, uvw.xy, decalDX, decalDY); + if ((decal.GetFlags() & ENTITY_FLAG_DECAL_BASECOLOR_ONLY_ALPHA) == 0) + { + // perform manual blending of decals: + // NOTE: they are sorted top-to-bottom, but blending is performed bottom-to-top + decalAccumulation.rgb = mad(1 - decalAccumulation.a, decalColor.a * decalColor.rgb, decalAccumulation.rgb); + decalAccumulation.a = mad(1 - decalColor.a, decalAccumulation.a, decalColor.a); + } + } + [branch] + if (decalNormal >= 0) + { + float3 decalBumpColor = float3(bindless_textures[NonUniformResourceIndex(decalNormal)].SampleGrad(sam, uvw.xy, decalDX, decalDY).rg, 1); + decalBumpColor = decalBumpColor * 2 - 1; + decalBumpColor.rg *= decalNormalStrength; + decalBumpAccumulation.rgb = mad(1 - decalBumpAccumulation.a, decalColor.a * decalBumpColor.rgb, decalBumpAccumulation.rgb); + decalBumpAccumulation.a = mad(1 - decalColor.a, decalBumpAccumulation.a, decalColor.a); + } + [branch] + if (decalSurfacemap >= 0) + { + float4 decalSurfaceColor = bindless_textures[NonUniformResourceIndex(decalSurfacemap)].SampleGrad(sam, uvw.xy, decalDX, decalDY); + decalSurfaceAccumulation = mad(1 - decalSurfaceAccumulationAlpha, decalColor.a * decalSurfaceColor, decalSurfaceAccumulation); + decalSurfaceAccumulationAlpha = mad(1 - decalColor.a, decalSurfaceAccumulationAlpha, decalColor.a); + } + } + } + + surface.baseColor.rgb = mad(surface.baseColor.rgb, 1 - decalAccumulation.a, decalAccumulation.rgb); + surface.bumpColor.rgb = mad(surface.bumpColor.rgb, 1 - decalBumpAccumulation.a, decalBumpAccumulation.rgb); + surfaceMap = mad(surfaceMap, 1 - decalSurfaceAccumulationAlpha, decalSurfaceAccumulation); +#endif // DISABLE_DECALS +} + +inline uint GetFlatTileIndex(uint2 pixel) +{ + const uint2 tileIndex = uint2(floor(pixel / TILED_CULLING_BLOCKSIZE)); + return flatten2D(tileIndex, GetCamera().entity_culling_tilecount.xy) * SHADER_ENTITY_TILE_BUCKET_COUNT; +} + +inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint flatTileIndex) +{ +#ifndef DISABLE_ENVMAPS + // Apply environment maps: + float4 envmapAccumulation = 0; + +#ifndef DISABLE_LOCALENVPMAPS + [branch] + if (GetFrame().envprobearray_count > 0) + { + // Loop through envmap buckets in the tile: + const uint first_item = GetFrame().envprobearray_offset; + const uint last_item = first_item + GetFrame().envprobearray_count - 1; + const uint first_bucket = first_item / 32; + const uint last_bucket = min(last_item / 32, max(0, SHADER_ENTITY_TILE_BUCKET_COUNT - 1)); + [loop] + for (uint bucket = first_bucket; bucket <= last_bucket; ++bucket) + { + uint bucket_bits = load_entitytile(flatTileIndex + bucket); + +#ifndef ENTITY_TILE_UNIFORM + // Bucket scalarizer - Siggraph 2017 - Improved Culling [Michal Drobot]: + bucket_bits = WaveReadLaneFirst(WaveActiveBitOr(bucket_bits)); +#endif // ENTITY_TILE_UNIFORM + + [loop] + while (bucket_bits != 0) + { + // Retrieve global entity index from local bucket, then remove bit from local bucket: + const uint bucket_bit_index = firstbitlow(bucket_bits); + const uint entity_index = bucket * 32 + bucket_bit_index; + bucket_bits ^= 1u << bucket_bit_index; + + [branch] + if (entity_index >= first_item && entity_index <= last_item && envmapAccumulation.a < 1) + { + ShaderEntity probe = load_entity(entity_index); + if ((probe.layerMask & surface.layerMask) == 0) + continue; + + const float4x4 probeProjection = load_entitymatrix(probe.GetMatrixIndex()); + const float3 clipSpacePos = mul(probeProjection, float4(surface.P, 1)).xyz; + const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); + [branch] + if (is_saturated(uvw)) + { + const float4 envmapColor = EnvironmentReflection_Local(surface, probe, probeProjection, clipSpacePos); + // perform manual blending of probes: + // NOTE: they are sorted top-to-bottom, but blending is performed bottom-to-top + envmapAccumulation.rgb = mad(1 - envmapAccumulation.a, envmapColor.a * envmapColor.rgb, envmapAccumulation.rgb); + envmapAccumulation.a = mad(1 - envmapColor.a, envmapAccumulation.a, envmapColor.a); + [branch] + if (envmapAccumulation.a >= 1.0) + { + // force exit: + bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; + break; + } + } + } + else if (entity_index > last_item) + { + // force exit: + bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; + break; + } + + } + } + } +#endif // DISABLE_LOCALENVPMAPS + + // Apply global envmap where there is no local envmap information: + [branch] + if (envmapAccumulation.a < 0.99) + { + envmapAccumulation.rgb = lerp(EnvironmentReflection_Global(surface), envmapAccumulation.rgb, envmapAccumulation.a); + } + lighting.indirect.specular += max(0, envmapAccumulation.rgb); +#endif // DISABLE_ENVMAPS + +#ifndef DISABLE_VOXELGI +#ifdef TRANSPARENT // opaque tiled forward: voxel GI was rendered in separate pass + VoxelGI(surface, lighting); +#endif // TRANSPARENT +#endif //DISABLE_VOXELGI + + [branch] + if (GetFrame().lightarray_count > 0) + { + // Loop through light buckets in the tile: + const uint first_item = GetFrame().lightarray_offset; + const uint last_item = first_item + GetFrame().lightarray_count - 1; + const uint first_bucket = first_item / 32; + const uint last_bucket = min(last_item / 32, max(0, SHADER_ENTITY_TILE_BUCKET_COUNT - 1)); + [loop] + for (uint bucket = first_bucket; bucket <= last_bucket; ++bucket) + { + uint bucket_bits = load_entitytile(flatTileIndex + bucket); + +#ifndef ENTITY_TILE_UNIFORM + // Bucket scalarizer - Siggraph 2017 - Improved Culling [Michal Drobot]: + bucket_bits = WaveReadLaneFirst(WaveActiveBitOr(bucket_bits)); +#endif // ENTITY_TILE_UNIFORM + + [loop] + while (bucket_bits != 0) + { + // Retrieve global entity index from local bucket, then remove bit from local bucket: + const uint bucket_bit_index = firstbitlow(bucket_bits); + const uint entity_index = bucket * 32 + bucket_bit_index; + bucket_bits ^= 1u << bucket_bit_index; + + // Check if it is a light and process: + [branch] + if (entity_index >= first_item && entity_index <= last_item) + { + ShaderEntity light = load_entity(entity_index); + if ((light.layerMask & surface.layerMask) == 0) + continue; + + if (light.GetFlags() & ENTITY_FLAG_LIGHT_STATIC) + { + continue; // static lights will be skipped (they are used in lightmap baking) + } + +#if defined(SHADOW_MASK_ENABLED) && !defined(TRANSPARENT) + const bool shadow_mask_enabled = (GetFrame().options & OPTION_BIT_SHADOW_MASK) && GetCamera().texture_rtshadow_index >= 0; + float shadow_mask = 1; + [branch] + if (shadow_mask_enabled && light.IsCastingShadow()) + { + uint shadow_index = entity_index - GetFrame().lightarray_offset; + if (shadow_index < 16) + { + uint mask_shift = (shadow_index % 4) * 8; + uint mask_bucket = shadow_index / 4; + uint mask = (bindless_textures_uint4[GetCamera().texture_rtshadow_index][surface.pixel][mask_bucket] >> mask_shift) & 0xFF; + if (mask == 0) + { + continue; + } + shadow_mask = mask / 255.0; + } + } +#else + const float shadow_mask = 1; +#endif // SHADOW_MASK_ENABLED + + switch (light.GetType()) + { + case ENTITY_TYPE_DIRECTIONALLIGHT: + { + light_directional(light, surface, lighting, shadow_mask); + } + break; + case ENTITY_TYPE_POINTLIGHT: + { + light_point(light, surface, lighting, shadow_mask); + } + break; + case ENTITY_TYPE_SPOTLIGHT: + { + light_spot(light, surface, lighting, shadow_mask); + } + break; + } + } + else if (entity_index > last_item) + { + // force exit: + bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; + break; + } + + } + } + } + +#ifndef TRANSPARENT + [branch] + if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetCamera().texture_rtdiffuse_index >= 0) + { + lighting.indirect.diffuse = bindless_textures[GetCamera().texture_rtdiffuse_index][surface.pixel].rgb; + surface.flags |= SURFACE_FLAG_GI_APPLIED; + } + + [branch] + if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetFrame().options & OPTION_BIT_SURFELGI_ENABLED && GetCamera().texture_surfelgi_index >= 0 && surfel_cellvalid(surfel_cell(surface.P))) + { + lighting.indirect.diffuse = bindless_textures[GetCamera().texture_surfelgi_index][surface.pixel].rgb; + surface.flags |= SURFACE_FLAG_GI_APPLIED; + } + + [branch] + if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetCamera().texture_vxgi_diffuse_index >= 0) + { + lighting.indirect.diffuse = bindless_textures[GetCamera().texture_vxgi_diffuse_index][surface.pixel].rgb; + surface.flags |= SURFACE_FLAG_GI_APPLIED; + } + [branch] + if (GetCamera().texture_vxgi_specular_index >= 0) + { + float4 vxgi_specular = bindless_textures[GetCamera().texture_vxgi_specular_index][surface.pixel]; + lighting.indirect.specular = vxgi_specular.rgb * surface.F + lighting.indirect.specular * (1 - vxgi_specular.a); + } +#endif // TRANSPARENT + + [branch] + if ((surface.flags & SURFACE_FLAG_GI_APPLIED) == 0 && GetScene().ddgi.color_texture >= 0) + { + lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N); + surface.flags |= SURFACE_FLAG_GI_APPLIED; + } + +} + +inline void TiledDecals(inout Surface surface, uint flatTileIndex, inout float4 surfaceMap, SamplerState sam) +{ +#ifndef DISABLE_DECALS + [branch] + if (GetFrame().decalarray_count == 0) + return; + + // decals are enabled, loop through them first: + float4 decalAccumulation = 0; + float4 decalBumpAccumulation = 0; + float4 decalSurfaceAccumulation = 0; + float decalSurfaceAccumulationAlpha = 0; + +#ifdef SURFACE_LOAD_QUAD_DERIVATIVES + const float3 P_dx = surface.P_dx; + const float3 P_dy = surface.P_dy; +#else + const float3 P_dx = ddx_coarse(surface.P); + const float3 P_dy = ddy_coarse(surface.P); +#endif // SURFACE_LOAD_QUAD_DERIVATIVES + + // Loop through decal buckets in the tile: + const uint first_item = GetFrame().decalarray_offset; + const uint last_item = first_item + GetFrame().decalarray_count - 1; + const uint first_bucket = first_item / 32; + const uint last_bucket = min(last_item / 32, max(0, SHADER_ENTITY_TILE_BUCKET_COUNT - 1)); + [loop] + for (uint bucket = first_bucket; bucket <= last_bucket; ++bucket) + { + uint bucket_bits = load_entitytile(flatTileIndex + bucket); + +#ifndef ENTITY_TILE_UNIFORM + // This is the wave scalarizer from Improved Culling - Siggraph 2017 [Drobot]: + bucket_bits = WaveReadLaneFirst(WaveActiveBitOr(bucket_bits)); +#endif // ENTITY_TILE_UNIFORM + + [loop] + while (bucket_bits != 0 && decalAccumulation.a < 1 && decalBumpAccumulation.a < 1 && decalSurfaceAccumulationAlpha < 1) + { + // Retrieve global entity index from local bucket, then remove bit from local bucket: + const uint bucket_bit_index = firstbitlow(bucket_bits); + const uint entity_index = bucket * 32 + bucket_bit_index; + bucket_bits ^= 1u << bucket_bit_index; + + [branch] + if (entity_index >= first_item && entity_index <= last_item) + { + ShaderEntity decal = load_entity(entity_index); + if ((decal.layerMask & surface.layerMask) == 0) + continue; + + float4x4 decalProjection = load_entitymatrix(decal.GetMatrixIndex()); + int decalTexture = asint(decalProjection[3][0]); + int decalNormal = asint(decalProjection[3][1]); + float decalNormalStrength = decalProjection[3][2]; + int decalSurfacemap = asint(decalProjection[3][3]); + decalProjection[3] = float4(0, 0, 0, 1); + const float3 clipSpacePos = mul(decalProjection, float4(surface.P, 1)).xyz; + float3 uvw = clipspace_to_uv(clipSpacePos.xyz); + [branch] + if (is_saturated(uvw)) + { + uvw.xy = mad(uvw.xy, decal.shadowAtlasMulAdd.xy, decal.shadowAtlasMulAdd.zw); + // mipmapping needs to be performed by hand: + const float2 decalDX = mul(P_dx, (float3x3)decalProjection).xy; + const float2 decalDY = mul(P_dy, (float3x3)decalProjection).xy; + float4 decalColor = decal.GetColor(); + // blend out if close to cube Z: + const float edgeBlend = 1 - pow(saturate(abs(clipSpacePos.z)), 8); + const float slopeBlend = decal.GetConeAngleCos() > 0 ? pow(saturate(dot(surface.N, decal.GetDirection())), decal.GetConeAngleCos()) : 1; + decalColor.a *= edgeBlend * slopeBlend; + [branch] + if (decalTexture >= 0) + { + decalColor *= bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sam, uvw.xy, decalDX, decalDY); + if ((decal.GetFlags() & ENTITY_FLAG_DECAL_BASECOLOR_ONLY_ALPHA) == 0) + { + // perform manual blending of decals: + // NOTE: they are sorted top-to-bottom, but blending is performed bottom-to-top + decalAccumulation.rgb = mad(1 - decalAccumulation.a, decalColor.a * decalColor.rgb, decalAccumulation.rgb); + decalAccumulation.a = mad(1 - decalColor.a, decalAccumulation.a, decalColor.a); + } + } + [branch] + if (decalNormal >= 0) + { + float3 decalBumpColor = float3(bindless_textures[NonUniformResourceIndex(decalNormal)].SampleGrad(sam, uvw.xy, decalDX, decalDY).rg, 1); + decalBumpColor = decalBumpColor * 2 - 1; + decalBumpColor.rg *= decalNormalStrength; + decalBumpAccumulation.rgb = mad(1 - decalBumpAccumulation.a, decalColor.a * decalBumpColor.rgb, decalBumpAccumulation.rgb); + decalBumpAccumulation.a = mad(1 - decalColor.a, decalBumpAccumulation.a, decalColor.a); + } + [branch] + if (decalSurfacemap >= 0) + { + float4 decalSurfaceColor = bindless_textures[NonUniformResourceIndex(decalSurfacemap)].SampleGrad(sam, uvw.xy, decalDX, decalDY); + decalSurfaceAccumulation = mad(1 - decalSurfaceAccumulationAlpha, decalColor.a * decalSurfaceColor, decalSurfaceAccumulation); + decalSurfaceAccumulationAlpha = mad(1 - decalColor.a, decalSurfaceAccumulationAlpha, decalColor.a); + } + } + } + else if (entity_index > last_item) + { + // force exit: + bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; + break; + } + + } + } + + surface.baseColor.rgb = mad(surface.baseColor.rgb, 1 - decalAccumulation.a, decalAccumulation.rgb); + surface.bumpColor.rgb = mad(surface.bumpColor.rgb, 1 - decalBumpAccumulation.a, decalBumpAccumulation.rgb); + surfaceMap = mad(surfaceMap, 1 - decalSurfaceAccumulationAlpha, decalSurfaceAccumulation); +#endif // DISABLE_DECALS +} + +inline void ApplyFog(in float distance, float3 V, inout float4 color) +{ + const float4 fog = GetFog(distance, GetCamera().position, -V); + //color.rgb = (1.0 - fog.a) * color.rgb + fog.rgb; // premultiplied fog + color.rgb = lerp(color.rgb, fog.rgb, fog.a); // non-premultiplied fog +} + +inline void ApplyAerialPerspective(float2 uv, float3 P, inout float4 color) +{ + if (GetFrame().options & OPTION_BIT_REALISTIC_SKY_AERIAL_PERSPECTIVE) + { + const float4 AP = GetAerialPerspectiveTransmittance(uv, P, GetCamera().position, texture_cameravolumelut); + color.rgb = color.rgb * (1.0 - AP.a) + AP.rgb; + } +} + +inline uint AlphaToCoverage(float alpha, float alphaTest, float4 svposition) +{ + if (alphaTest == 0) + { + // No alpha test, force full coverage: + return ~0u; + } + + if (GetFrame().options & OPTION_BIT_TEMPORALAA_ENABLED) + { + // When Temporal AA is enabled, dither the alpha mask with animated blue noise: + alpha -= blue_noise(svposition.xy, svposition.w).x / GetCamera().sample_count; + } + else if (GetCamera().sample_count > 1) + { + // Without Temporal AA, use static dithering: + alpha -= dither(svposition.xy) / GetCamera().sample_count; + } + else + { + // Without Temporal AA and MSAA, regular alpha test behaviour will be used: + alpha -= alphaTest; + } + + if (alpha > 0) + { + return ~0u >> (31u - uint(alpha * GetCamera().sample_count)); + } + return 0; +} + +#endif // WI_SHADING_HF diff --git a/WickedEngine/shaders/visibility_resolveCS.hlsl b/WickedEngine/shaders/visibility_resolveCS.hlsl index 9fac81cce..26e5dfd31 100644 --- a/WickedEngine/shaders/visibility_resolveCS.hlsl +++ b/WickedEngine/shaders/visibility_resolveCS.hlsl @@ -112,7 +112,7 @@ void main(uint2 Gid : SV_GroupID, uint groupIndex : SV_GroupIndex) { uint bin_tile_list_offset = groupIndex * GetCamera().visibility_tilecount_flat; uint tile_offset = 0; - InterlockedAdd(output_bins[groupIndex].count, 1, tile_offset); + InterlockedAdd(output_bins[groupIndex].dispatchX, 1, tile_offset); VisibilityTile tile; tile.visibility_tile_id = pack_pixel(Gid.xy); diff --git a/WickedEngine/shaders/visibility_shadeCS.hlsl b/WickedEngine/shaders/visibility_shadeCS.hlsl index 737b90ee5..353b23434 100644 --- a/WickedEngine/shaders/visibility_shadeCS.hlsl +++ b/WickedEngine/shaders/visibility_shadeCS.hlsl @@ -9,9 +9,14 @@ #include "ShaderInterop_Renderer.h" #include "raytracingHF.hlsli" #include "brdf.hlsli" -#include "objectHF.hlsli" +#include "shadingHF.hlsli" + +struct VisibilityPushConstants +{ + uint global_tile_offset; +}; +PUSHCONSTANT(push, VisibilityPushConstants); -ConstantBuffer bin : register(b10); StructuredBuffer binned_tiles : register(t0); Texture2D input_payload_0 : register(t2); Texture2D input_payload_1 : register(t3); @@ -21,7 +26,7 @@ RWTexture2D output : register(u0); [numthreads(VISIBILITY_BLOCKSIZE, VISIBILITY_BLOCKSIZE, 1)] void main(uint Gid : SV_GroupID, uint groupIndex : SV_GroupIndex) { - const uint tile_offset = bin.offset + Gid.x; + const uint tile_offset = push.global_tile_offset + Gid.x; VisibilityTile tile = binned_tiles[tile_offset]; [branch] if (!tile.check_thread_valid(groupIndex)) return; const uint2 GTid = remap_lane_8x8(groupIndex); diff --git a/WickedEngine/shaders/visibility_skyCS.hlsl b/WickedEngine/shaders/visibility_skyCS.hlsl index 4b3da7299..dd10fd12d 100644 --- a/WickedEngine/shaders/visibility_skyCS.hlsl +++ b/WickedEngine/shaders/visibility_skyCS.hlsl @@ -3,7 +3,12 @@ #include "skyHF.hlsli" #include "fogHF.hlsli" -ConstantBuffer bin : register(b10); +struct VisibilityPushConstants +{ + uint global_tile_offset; +}; +PUSHCONSTANT(push, VisibilityPushConstants); + StructuredBuffer binned_tiles : register(t0); RWTexture2D output : register(u0); @@ -11,7 +16,7 @@ RWTexture2D output : register(u0); [numthreads(VISIBILITY_BLOCKSIZE, VISIBILITY_BLOCKSIZE, 1)] void main(uint Gid : SV_GroupID, uint groupIndex : SV_GroupIndex) { - const uint tile_offset = bin.offset + Gid.x; + const uint tile_offset = push.global_tile_offset + Gid.x; VisibilityTile tile = binned_tiles[tile_offset]; [branch] if (!tile.check_thread_valid(groupIndex)) diff --git a/WickedEngine/shaders/visibility_surfaceCS.hlsl b/WickedEngine/shaders/visibility_surfaceCS.hlsl index b91a5f62e..00bffc304 100644 --- a/WickedEngine/shaders/visibility_surfaceCS.hlsl +++ b/WickedEngine/shaders/visibility_surfaceCS.hlsl @@ -9,9 +9,14 @@ #include "ShaderInterop_Renderer.h" #include "raytracingHF.hlsli" #include "surfaceHF.hlsli" -#include "objectHF.hlsli" +#include "shadingHF.hlsli" + +struct VisibilityPushConstants +{ + uint global_tile_offset; +}; +PUSHCONSTANT(push, VisibilityPushConstants); -ConstantBuffer bin : register(b10); StructuredBuffer binned_tiles : register(t0); RWTexture2D output : register(u0); @@ -23,7 +28,7 @@ RWTexture2D output_payload_1 : register(u4); [numthreads(VISIBILITY_BLOCKSIZE, VISIBILITY_BLOCKSIZE, 1)] void main(uint Gid : SV_GroupID, uint groupIndex : SV_GroupIndex) { - const uint tile_offset = bin.offset + Gid.x; + const uint tile_offset = push.global_tile_offset + Gid.x; VisibilityTile tile = binned_tiles[tile_offset]; const uint2 GTid = remap_lane_8x8(groupIndex); const uint2 pixel = unpack_pixel(tile.visibility_tile_id) * VISIBILITY_BLOCKSIZE + GTid; diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index 76d3521b7..9f8080f35 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -372,7 +372,6 @@ namespace wi::enums CSTYPE_SURFEL_INTEGRATE, CSTYPE_VISIBILITY_RESOLVE, CSTYPE_VISIBILITY_RESOLVE_MSAA, - CSTYPE_VISIBILITY_INDIRECT_PREPARE, CSTYPE_VISIBILITY_SKY, CSTYPE_VISIBILITY_VELOCITY, CSTYPE_VISIBILITY_SURFACE_REDUCED_PERMUTATION_BEGIN, diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 4d59dab3a..5c830f235 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -1044,7 +1044,6 @@ void LoadShaders() wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_VISIBILITY_RESOLVE], "visibility_resolveCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_VISIBILITY_RESOLVE_MSAA], "visibility_resolveCS_MSAA.cso"); }); - wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_VISIBILITY_INDIRECT_PREPARE], "visibility_indirect_prepareCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_VISIBILITY_SKY], "visibility_skyCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_VISIBILITY_VELOCITY], "visibility_velocityCS.cso"); }); @@ -9221,7 +9220,7 @@ void CreateVisibilityResources(VisibilityResources& res, XMUINT2 resolution) GPUBufferDesc desc; desc.stride = sizeof(ShaderTypeBin); desc.size = desc.stride * (MaterialComponent::SHADERTYPE_COUNT + 1); // +1 for sky - desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS | BindFlag::CONSTANT_BUFFER; + desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS; desc.misc_flags = ResourceMiscFlag::BUFFER_STRUCTURED | ResourceMiscFlag::INDIRECT_ARGS; bool success = device->CreateBuffer(&desc, nullptr, &res.bins); assert(success); @@ -9270,11 +9269,18 @@ void Visibility_Prepare( // Beginning barriers, clears: { - barrier_stack.push_back(GPUBarrier::Buffer(&res.bins, ResourceState::CONSTANT_BUFFER | ResourceState::INDIRECT_ARGUMENT, ResourceState::UNORDERED_ACCESS)); - barrier_stack.push_back(GPUBarrier::Buffer(&res.binned_tiles, ResourceState::SHADER_RESOURCE, ResourceState::UNORDERED_ACCESS)); - barrier_stack_flush(cmd); - device->ClearUAV(&res.bins, 0, cmd); - barrier_stack.push_back(GPUBarrier::Memory(&res.bins)); + ShaderTypeBin bins[SHADERTYPE_BIN_COUNT + 1]; + for (uint i = 0; i < arraysize(bins); ++i) + { + ShaderTypeBin& bin = bins[i]; + bin.dispatchX = 0; // will be used for atomic add in shader + bin.dispatchY = 1; + bin.dispatchZ = 1; + bin.shaderType = i; + } + device->UpdateBuffer(&res.bins, bins, cmd); + barrier_stack.push_back(GPUBarrier::Buffer(&res.bins, ResourceState::COPY_DST, ResourceState::UNORDERED_ACCESS)); + barrier_stack.push_back(GPUBarrier::Buffer(&res.binned_tiles, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS)); barrier_stack_flush(cmd); } @@ -9357,25 +9363,13 @@ void Visibility_Prepare( { barrier_stack.push_back(GPUBarrier::Image(res.primitiveID_resolved, ResourceState::UNORDERED_ACCESS, res.primitiveID_resolved->desc.layout)); } - barrier_stack.push_back(GPUBarrier::Memory(&res.bins)); + barrier_stack.push_back(GPUBarrier::Buffer(&res.bins, ResourceState::UNORDERED_ACCESS, ResourceState::INDIRECT_ARGUMENT)); + barrier_stack.push_back(GPUBarrier::Buffer(&res.binned_tiles, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE)); barrier_stack_flush(cmd); device->EventEnd(cmd); } - // Indirect prepare: - { - device->EventBegin("Indirect Prepare", cmd); - device->BindComputeShader(&shaders[CSTYPE_VISIBILITY_INDIRECT_PREPARE], cmd); - device->BindUAV(&res.bins, 0, cmd); - device->Dispatch(1, 1, 1, cmd); - device->EventEnd(cmd); - } - - barrier_stack.push_back(GPUBarrier::Buffer(&res.bins, ResourceState::UNORDERED_ACCESS, ResourceState::CONSTANT_BUFFER | ResourceState::INDIRECT_ARGUMENT)); - barrier_stack.push_back(GPUBarrier::Buffer(&res.binned_tiles, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE)); - barrier_stack_flush(cmd); - wi::profiler::EndRange(range); device->EventEnd(cmd); } @@ -9405,20 +9399,24 @@ void Visibility_Surface( device->BindUAV(&res.texture_payload_0, 3, cmd); device->BindUAV(&res.texture_payload_1, 4, cmd); + const uint visibility_tilecount_flat = res.tile_count.x * res.tile_count.y; + uint visibility_tile_offset = 0; + // surface dispatches per material type: device->EventBegin("Surface parameters", cmd); for (uint i = 0; i < MaterialComponent::SHADERTYPE_COUNT; ++i) { device->BindComputeShader(&shaders[CSTYPE_VISIBILITY_SURFACE_PERMUTATION_BEGIN + i], cmd); - device->BindConstantBuffer(&res.bins, 10, cmd, i * sizeof(ShaderTypeBin)); + device->PushConstants(&visibility_tile_offset, sizeof(visibility_tile_offset), cmd); device->DispatchIndirect(&res.bins, i * sizeof(ShaderTypeBin) + offsetof(ShaderTypeBin, dispatchX), cmd); + visibility_tile_offset += visibility_tilecount_flat; } device->EventEnd(cmd); // sky dispatch: device->EventBegin("Sky", cmd); device->BindComputeShader(&shaders[CSTYPE_VISIBILITY_SKY], cmd); - device->BindConstantBuffer(&res.bins, 10, cmd, MaterialComponent::SHADERTYPE_COUNT * sizeof(ShaderTypeBin)); + device->PushConstants(&visibility_tile_offset, sizeof(visibility_tile_offset), cmd); device->DispatchIndirect(&res.bins, MaterialComponent::SHADERTYPE_COUNT * sizeof(ShaderTypeBin) + offsetof(ShaderTypeBin, dispatchX), cmd); device->EventEnd(cmd); @@ -9449,15 +9447,20 @@ void Visibility_Surface_Reduced( device->BindUAV(&res.texture_normals, 1, cmd); device->BindUAV(&res.texture_roughness, 2, cmd); + const uint visibility_tilecount_flat = res.tile_count.x * res.tile_count.y; + uint visibility_tile_offset = 0; + // surface dispatches per material type: device->EventBegin("Surface parameters", cmd); for (uint i = 0; i < MaterialComponent::SHADERTYPE_COUNT; ++i) { - if (i == MaterialComponent::SHADERTYPE_UNLIT) - continue; // this won't need surface parameter write out - device->BindComputeShader(&shaders[CSTYPE_VISIBILITY_SURFACE_REDUCED_PERMUTATION_BEGIN + i], cmd); - device->BindConstantBuffer(&res.bins, 10, cmd, i * sizeof(ShaderTypeBin)); - device->DispatchIndirect(&res.bins, i * sizeof(ShaderTypeBin) + offsetof(ShaderTypeBin, dispatchX), cmd); + if (i != MaterialComponent::SHADERTYPE_UNLIT) // this won't need surface parameter write out + { + device->BindComputeShader(&shaders[CSTYPE_VISIBILITY_SURFACE_REDUCED_PERMUTATION_BEGIN + i], cmd); + device->PushConstants(&visibility_tile_offset, sizeof(visibility_tile_offset), cmd); + device->DispatchIndirect(&res.bins, i * sizeof(ShaderTypeBin) + offsetof(ShaderTypeBin, dispatchX), cmd); + } + visibility_tile_offset += visibility_tilecount_flat; } device->EventEnd(cmd); @@ -9490,14 +9493,19 @@ void Visibility_Shade( device->BindResource(&res.texture_payload_1, 3, cmd); device->BindUAV(&output, 0, cmd); + const uint visibility_tilecount_flat = res.tile_count.x * res.tile_count.y; + uint visibility_tile_offset = 0; + // shading dispatches per material type: for (uint i = 0; i < MaterialComponent::SHADERTYPE_COUNT; ++i) { - if (i == MaterialComponent::SHADERTYPE_UNLIT) - continue; // the unlit shader is special, it had already written out its final color in the surface shader - device->BindComputeShader(&shaders[CSTYPE_VISIBILITY_SHADE_PERMUTATION_BEGIN + i], cmd); - device->BindConstantBuffer(&res.bins, 10, cmd, i * sizeof(ShaderTypeBin)); - device->DispatchIndirect(&res.bins, i * sizeof(ShaderTypeBin) + offsetof(ShaderTypeBin, dispatchX), cmd); + if (i != MaterialComponent::SHADERTYPE_UNLIT) // the unlit shader is special, it had already written out its final color in the surface shader + { + device->BindComputeShader(&shaders[CSTYPE_VISIBILITY_SHADE_PERMUTATION_BEGIN + i], cmd); + device->PushConstants(&visibility_tile_offset, sizeof(visibility_tile_offset), cmd); + device->DispatchIndirect(&res.bins, i * sizeof(ShaderTypeBin) + offsetof(ShaderTypeBin, dispatchX), cmd); + } + visibility_tile_offset += visibility_tilecount_flat; } barrier_stack.push_back(GPUBarrier::Image(&output, ResourceState::UNORDERED_ACCESS, output.desc.layout)); diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 83ccadd38..ba5584b76 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 = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 203; + const int revision = 204; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);