From a4ac42543309bdc62673d4bc33141bfce6a7caf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Mon, 12 Feb 2024 18:00:37 +0100 Subject: [PATCH] Shader nonuniform indexing changes to uniform (#801) --- WickedEngine/shaders/lightingHF.hlsli | 7 +- WickedEngine/shaders/shadingHF.hlsli | 216 ++++++++++++++------------ WickedEngine/shaders/surfaceHF.hlsli | 78 +++++----- 3 files changed, 162 insertions(+), 139 deletions(-) diff --git a/WickedEngine/shaders/lightingHF.hlsli b/WickedEngine/shaders/lightingHF.hlsli index 675db4dd7..af0e4e817 100644 --- a/WickedEngine/shaders/lightingHF.hlsli +++ b/WickedEngine/shaders/lightingHF.hlsli @@ -426,12 +426,8 @@ inline float3 EnvironmentReflection_Global(in Surface surface) // clipSpacePos: world space pixel position transformed into OBB space by probeProjection matrix // MIP: mip level to sample // return: color of the environment map (rgb), blend factor of the environment map (a) -inline float4 EnvironmentReflection_Local(int textureIndex, in Surface surface, in ShaderEntity probe, in float4x4 probeProjection, in float3 clipSpacePos) +inline float4 EnvironmentReflection_Local(in TextureCube cubemap, in Surface surface, in ShaderEntity probe, in float4x4 probeProjection, in float3 clipSpacePos) { - [branch] - if (GetScene().globalprobe < 0) - return 0; - // Perform parallax correction of reflection ray (R) into OBB: float3 RayLS = mul((float3x3)probeProjection, surface.R); float3 FirstPlaneIntersect = (float3(1, 1, 1) - clipSpacePos) / RayLS; @@ -441,7 +437,6 @@ inline float4 EnvironmentReflection_Local(int textureIndex, in Surface surface, float3 IntersectPositionWS = surface.P + surface.R * Distance; float3 R_parallaxCorrected = IntersectPositionWS - probe.position; - TextureCube cubemap = bindless_cubemaps[NonUniformResourceIndex(textureIndex)]; uint2 dim; uint mips; cubemap.GetDimensions(0, dim.x, dim.y, mips); diff --git a/WickedEngine/shaders/shadingHF.hlsli b/WickedEngine/shaders/shadingHF.hlsli index 078a5286a..bea418b88 100644 --- a/WickedEngine/shaders/shadingHF.hlsli +++ b/WickedEngine/shaders/shadingHF.hlsli @@ -57,22 +57,25 @@ inline void ForwardLighting(inout Surface surface, inout Lighting lighting) const uint entity_index = bucket_bit_index; bucket_bits ^= 1u << bucket_bit_index; + ShaderEntity probe = load_entity(GetFrame().envprobearray_offset + entity_index); + if ((probe.layerMask & surface.layerMask) == 0) + continue; + + float4x4 probeProjection = load_entitymatrix(probe.GetMatrixIndex()); + const int probeTexture = asint(probeProjection[3][0]); + probeProjection[3] = float4(0, 0, 0, 1); + TextureCube cubemap = bindless_cubemaps[probeTexture]; + + // under here will be VGPR! [branch] if (envmapAccumulation.a < 1) { - ShaderEntity probe = load_entity(GetFrame().envprobearray_offset + entity_index); - if ((probe.layerMask & surface.layerMask) == 0) - continue; - - float4x4 probeProjection = load_entitymatrix(probe.GetMatrixIndex()); - const int probeTexture = asint(probeProjection[3][0]); - probeProjection[3] = float4(0, 0, 0, 1); 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(probeTexture, surface, probe, probeProjection, clipSpacePos); + const float4 envmapColor = EnvironmentReflection_Local(cubemap, 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); @@ -183,7 +186,7 @@ inline void ForwardDecals(inout Surface surface, inout float4 surfaceMap, Sample uint bucket_bits = xForwardDecalMask; [loop] - while (bucket_bits != 0 && decalAccumulation.a < 1 && decalBumpAccumulation.a < 1 && decalSurfaceAccumulationAlpha < 1) + 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); @@ -200,47 +203,53 @@ inline void ForwardDecals(inout Surface surface, inout float4 surfaceMap, Sample 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); + + // under here will be VGPR! [branch] - if (is_saturated(uvw)) + if(decalAccumulation.a < 1 && decalBumpAccumulation.a < 1 && decalSurfaceAccumulationAlpha < 1) { - 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; + const float3 clipSpacePos = mul(decalProjection, float4(surface.P, 1)).xyz; + float3 uvw = clipspace_to_uv(clipSpacePos.xyz); [branch] - if (decalTexture >= 0) + if (is_saturated(uvw)) { - decalColor *= bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sam, uvw.xy, decalDX, decalDY); - if ((decal.GetFlags() & ENTITY_FLAG_DECAL_BASECOLOR_ONLY_ALPHA) == 0) + 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) { - // 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); + decalColor *= bindless_textures[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[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[decalSurfacemap].SampleGrad(sam, uvw.xy, decalDX, decalDY); + decalSurfaceAccumulation = mad(1 - decalSurfaceAccumulationAlpha, decalColor.a * decalSurfaceColor, decalSurfaceAccumulation); + decalSurfaceAccumulationAlpha = mad(1 - decalColor.a, decalSurfaceAccumulationAlpha, 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); } } } @@ -270,8 +279,8 @@ inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint f // 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)); + const uint first_bucket = first_item / 32u; + const uint last_bucket = min(last_item / 32u, max(0, SHADER_ENTITY_TILE_BUCKET_COUNT - 1)); [loop] for (uint bucket = first_bucket; bucket <= last_bucket; ++bucket) { @@ -291,7 +300,7 @@ inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint f bucket_bits ^= 1u << bucket_bit_index; [branch] - if (entity_index >= first_item && entity_index <= last_item && envmapAccumulation.a < 1) + if (entity_index >= first_item && entity_index <= last_item) { ShaderEntity probe = load_entity(entity_index); if ((probe.layerMask & surface.layerMask) == 0) @@ -300,22 +309,29 @@ inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint f float4x4 probeProjection = load_entitymatrix(probe.GetMatrixIndex()); const int probeTexture = asint(probeProjection[3][0]); probeProjection[3] = float4(0, 0, 0, 1); - const float3 clipSpacePos = mul(probeProjection, float4(surface.P, 1)).xyz; - const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); + TextureCube cubemap = bindless_cubemaps[probeTexture]; + + // under here will be VGPR! [branch] - if (is_saturated(uvw)) + if(envmapAccumulation.a < 1) { - const float4 envmapColor = EnvironmentReflection_Local(probeTexture, 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); + const float3 clipSpacePos = mul(probeProjection, float4(surface.P, 1)).xyz; + const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); [branch] - if (envmapAccumulation.a >= 1.0) + if (is_saturated(uvw)) { - // force exit: - bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; - break; + const float4 envmapColor = EnvironmentReflection_Local(cubemap, 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; + } } } } @@ -362,8 +378,8 @@ inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint f // 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)); + const uint first_bucket = first_item / 32u; + const uint last_bucket = min(last_item / 32u, max(0, SHADER_ENTITY_TILE_BUCKET_COUNT - 1)); [loop] for (uint bucket = first_bucket; bucket <= last_bucket; ++bucket) { @@ -516,7 +532,7 @@ inline void TiledDecals(inout Surface surface, uint flatTileIndex, inout float4 #endif // ENTITY_TILE_UNIFORM [loop] - while (bucket_bits != 0 && decalAccumulation.a < 1 && decalBumpAccumulation.a < 1 && decalSurfaceAccumulationAlpha < 1) + 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); @@ -536,47 +552,53 @@ inline void TiledDecals(inout Surface surface, uint flatTileIndex, inout float4 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); + + // under here will be VGPR! [branch] - if (is_saturated(uvw)) + if(decalAccumulation.a < 1 && decalBumpAccumulation.a < 1 && decalSurfaceAccumulationAlpha < 1) { - 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; + const float3 clipSpacePos = mul(decalProjection, float4(surface.P, 1)).xyz; + float3 uvw = clipspace_to_uv(clipSpacePos.xyz); [branch] - if (decalTexture >= 0) + if (is_saturated(uvw)) { - decalColor *= bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sam, uvw.xy, decalDX, decalDY); - if ((decal.GetFlags() & ENTITY_FLAG_DECAL_BASECOLOR_ONLY_ALPHA) == 0) + 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) { - // 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); + decalColor *= bindless_textures[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[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[decalSurfacemap].SampleGrad(sam, uvw.xy, decalDX, decalDY); + decalSurfaceAccumulation = mad(1 - decalSurfaceAccumulationAlpha, decalColor.a * decalSurfaceColor, decalSurfaceAccumulation); + decalSurfaceAccumulationAlpha = mad(1 - decalColor.a, decalSurfaceAccumulationAlpha, 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); } } } diff --git a/WickedEngine/shaders/surfaceHF.hlsli b/WickedEngine/shaders/surfaceHF.hlsli index a451752a3..6fd388043 100644 --- a/WickedEngine/shaders/surfaceHF.hlsli +++ b/WickedEngine/shaders/surfaceHF.hlsli @@ -623,7 +623,7 @@ struct Surface #endif // ENTITY_TILE_UNIFORM [loop] - while (bucket_bits != 0 && decalAccumulation.a < 1 && decalBumpAccumulation.a < 1 && decalSurfaceAccumulationAlpha < 1) + 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); @@ -643,47 +643,53 @@ struct Surface float decalNormalStrength = decalProjection[3][2]; int decalSurfacemap = asint(decalProjection[3][3]); decalProjection[3] = float4(0, 0, 0, 1); - const float3 clipSpacePos = mul(decalProjection, float4(P, 1)).xyz; - float3 uvw = clipspace_to_uv(clipSpacePos.xyz); + + // under here will be VGPR! [branch] - if (is_saturated(uvw)) + if(decalAccumulation.a < 1 && decalBumpAccumulation.a < 1 && decalSurfaceAccumulationAlpha < 1) { - 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(N, decal.GetDirection())), decal.GetConeAngleCos()) : 1; - decalColor.a *= edgeBlend * slopeBlend; + const float3 clipSpacePos = mul(decalProjection, float4(P, 1)).xyz; + float3 uvw = clipspace_to_uv(clipSpacePos.xyz); [branch] - if (decalTexture >= 0) + if (is_saturated(uvw)) { - decalColor *= bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sam, uvw.xy, decalDX, decalDY); - if ((decal.GetFlags() & ENTITY_FLAG_DECAL_BASECOLOR_ONLY_ALPHA) == 0) + 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(N, decal.GetDirection())), decal.GetConeAngleCos()) : 1; + decalColor.a *= edgeBlend * slopeBlend; + [branch] + if (decalTexture >= 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); + decalColor *= bindless_textures[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[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[decalSurfacemap].SampleGrad(sam, uvw.xy, decalDX, decalDY); + decalSurfaceAccumulation = mad(1 - decalSurfaceAccumulationAlpha, decalColor.a * decalSurfaceColor, decalSurfaceAccumulation); + decalSurfaceAccumulationAlpha = mad(1 - decalColor.a, decalSurfaceAccumulationAlpha, 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); } } }