diff --git a/Editor/OptionsWindow.cpp b/Editor/OptionsWindow.cpp index 0089f6f41..64fdeca9b 100644 --- a/Editor/OptionsWindow.cpp +++ b/Editor/OptionsWindow.cpp @@ -77,7 +77,12 @@ void OptionsWindow::Create(EditorComponent* _editor) pick.entity = scene.Entity_CreateForce("force"); break; case 7: - pick.entity = scene.Entity_CreateDecal("decal", "images/logo_small.png"); + pick.entity = scene.Entity_CreateDecal("decal", ""); + if (scene.materials.Contains(pick.entity)) + { + MaterialComponent* decal_material = scene.materials.GetComponent(pick.entity); + decal_material->textures[MaterialComponent::BASECOLORMAP].resource.SetTexture(*wi::texturehelper::getLogo()); + } scene.transforms.GetComponent(pick.entity)->RotateRollPitchYaw(XMFLOAT3(XM_PIDIV2, 0, 0)); break; case 8: diff --git a/WickedEngine/shaders/captureImpostorPS.hlsl b/WickedEngine/shaders/captureImpostorPS.hlsl index 6883801ab..7df221e90 100644 --- a/WickedEngine/shaders/captureImpostorPS.hlsl +++ b/WickedEngine/shaders/captureImpostorPS.hlsl @@ -31,8 +31,13 @@ ImpostorOutput main(PixelInput input) [branch] if (GetMaterial().textures[NORMALMAP].IsValid()) { - float3 bumpColor; - NormalMapping(input.uvsets, N, TBN, bumpColor); + [branch] + if (GetMaterial().normalMapStrength > 0 && GetMaterial().textures[NORMALMAP].IsValid()) + { + float3 normalMap = float3(GetMaterial().textures[NORMALMAP].Sample(sampler_objectshader, input.uvsets).rg, 1); + float3 bumpColor = normalMap.rgb * 2 - 1; + N = normalize(lerp(N, mul(bumpColor, TBN), GetMaterial().normalMapStrength)); + } } float4 surfaceMap = 1; diff --git a/WickedEngine/shaders/emittedparticlePS_soft.hlsl b/WickedEngine/shaders/emittedparticlePS_soft.hlsl index bc050e049..cb4ac053b 100644 --- a/WickedEngine/shaders/emittedparticlePS_soft.hlsl +++ b/WickedEngine/shaders/emittedparticlePS_soft.hlsl @@ -24,7 +24,7 @@ float4 main(VertextoPixel input) : SV_TARGET } } - float2 pixel = input.pos.xy; + uint2 pixel = input.pos.xy; float2 ScreenCoord = pixel * GetCamera().internal_resolution_rcp; float4 depthScene = texture_lineardepth.GatherRed(sampler_linear_clamp, ScreenCoord) * GetCamera().z_far; float depthFragment = input.pos.w; @@ -74,7 +74,7 @@ float4 main(VertextoPixel input) : SV_TARGET surface.sss_inv = material.subsurfaceScattering_inv; surface.update(); - TiledLighting(surface, lighting); + TiledLighting(surface, lighting, GetFlatTileIndex(pixel)); color.rgb *= lighting.direct.diffuse + lighting.indirect.diffuse; diff --git a/WickedEngine/shaders/globals.hlsli b/WickedEngine/shaders/globals.hlsli index c023a3042..ceb909d00 100644 --- a/WickedEngine/shaders/globals.hlsli +++ b/WickedEngine/shaders/globals.hlsli @@ -126,6 +126,14 @@ inline ShaderMaterial load_material(uint materialIndex) { return bindless_buffers[GetScene().materialbuffer].Load(materialIndex * sizeof(ShaderMaterial)); } +uint load_entitytile(uint tileIndex) +{ +#ifdef TRANSPARENT + return bindless_buffers[GetCamera().buffer_entitytiles_transparent_index].Load(tileIndex * sizeof(uint)); +#else + return bindless_buffers[GetCamera().buffer_entitytiles_opaque_index].Load(tileIndex * sizeof(uint)); +#endif // TRANSPARENT +} inline ShaderEntity load_entity(uint entityIndex) { return bindless_buffers[GetFrame().buffer_entityarray_index].Load(entityIndex * sizeof(ShaderEntity)); diff --git a/WickedEngine/shaders/hairparticlePS.hlsl b/WickedEngine/shaders/hairparticlePS.hlsl index 6e564a5fa..27c32ed86 100644 --- a/WickedEngine/shaders/hairparticlePS.hlsl +++ b/WickedEngine/shaders/hairparticlePS.hlsl @@ -57,7 +57,7 @@ float4 main(VertexToPixel input) : SV_Target float depth = input.pos.z; float3 reflection = 0; - TiledLighting(surface, lighting); + TiledLighting(surface, lighting, GetFlatTileIndex(pixel)); ApplyLighting(surface, lighting, color); diff --git a/WickedEngine/shaders/impostorPS.hlsl b/WickedEngine/shaders/impostorPS.hlsl index 5ace32ccd..8a39e3be1 100644 --- a/WickedEngine/shaders/impostorPS.hlsl +++ b/WickedEngine/shaders/impostorPS.hlsl @@ -54,7 +54,7 @@ float4 main(VSOut input) : SV_Target Lighting lighting; lighting.create(0, 0, GetAmbient(surface.N), 0); - TiledLighting(surface, lighting); + TiledLighting(surface, lighting, GetFlatTileIndex(pixel)); float4 color = 0; diff --git a/WickedEngine/shaders/objectHF.hlsli b/WickedEngine/shaders/objectHF.hlsli index e014b995b..6f6ee71f9 100644 --- a/WickedEngine/shaders/objectHF.hlsli +++ b/WickedEngine/shaders/objectHF.hlsli @@ -3,6 +3,12 @@ #ifdef TRANSPARENT #define DISABLE_TRANSPARENT_SHADOWMAP +#else +#define SHADOW_MASK_ENABLED +#endif + +#if !defined(TRANSPARENT) && !defined(PREPASS) +#define DISABLE_ALPHATEST #endif #ifdef PLANARREFLECTION @@ -49,15 +55,6 @@ inline ShaderMaterial GetMaterial() #define sampler_objectshader bindless_samplers[GetMaterial().sampler_descriptor] -uint load_entitytile(uint tileIndex) -{ -#ifdef TRANSPARENT - return bindless_buffers[GetCamera().buffer_entitytiles_transparent_index].Load(tileIndex * sizeof(uint)); -#else - return bindless_buffers[GetCamera().buffer_entitytiles_opaque_index].Load(tileIndex * sizeof(uint)); -#endif // TRANSPARENT -} - // Use these to compile this file as shader prototype: //#define OBJECTSHADER_COMPILE_VS - compile vertex shader prototype //#define OBJECTSHADER_COMPILE_PS - compile pixel shader prototype @@ -321,22 +318,6 @@ inline void LightMapping(in int lightmap, in float2 ATLAS, inout Lighting lighti } } -inline void NormalMapping(in float4 uvsets, inout float3 N, in float3x3 TBN, out float3 bumpColor) -{ - [branch] - if (GetMaterial().normalMapStrength > 0 && GetMaterial().textures[NORMALMAP].IsValid()) - { - float3 normalMap = float3(GetMaterial().textures[NORMALMAP].Sample(sampler_objectshader, uvsets).rg, 1); - bumpColor = normalMap.rgb * 2 - 1; - N = normalize(lerp(N, mul(bumpColor, TBN), GetMaterial().normalMapStrength)); - bumpColor *= GetMaterial().normalMapStrength; - } - else - { - bumpColor = 0; - } -} - inline float3 PlanarReflection(in Surface surface, in float2 bumpColor) { [branch] @@ -374,79 +355,6 @@ inline void ParallaxOcclusionMapping(inout float4 uvsets, in float3 V, in float3 inline void ForwardLighting(inout Surface surface, inout Lighting lighting) { -#ifndef DISABLE_DECALS - [branch] - if (xForwardDecalMask != 0) - { - // decals are enabled, loop through them first: - float4 decalAccumulation = 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) - { - // 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 (decalAccumulation.a < 1) - { - 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]); - decalProjection[3] = float4(0, 0, 0, 1); - const float3 clipSpacePos = mul(decalProjection, float4(surface.P, 1)).xyz; - const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); - [branch] - if (is_saturated(uvw)) - { - float4 decalColor = 1; - [branch] - if (decalTexture >= 0) - { - // 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; - decalColor = bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sampler_objectshader, uvw.xy, decalDX, decalDY); - } - // blend out if close to cube Z: - float edgeBlend = 1 - pow(saturate(abs(clipSpacePos.z)), 8); - decalColor.a *= edgeBlend; - decalColor *= decal.GetColor(); - // 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 (decalAccumulation.a >= 1.0) - { - // force exit: - break; - } - } - } - else - { - // force exit: - break; - } - - } - - surface.albedo.rgb = lerp(surface.albedo.rgb, decalAccumulation.rgb, decalAccumulation.a); - } -#endif // DISABLE_DECALS - - #ifndef DISABLE_ENVMAPS // Apply environment maps: float4 envmapAccumulation = 0; @@ -577,107 +485,84 @@ inline void ForwardLighting(inout Surface surface, inout Lighting lighting) } - -inline void TiledDecals(inout Surface surface, uint flatTileIndex) +inline void ForwardDecals(inout Surface surface) { +#ifndef DISABLE_DECALS [branch] - if (GetFrame().decalarray_count > 0) + if (xForwardDecalMask == 0) + return; + + // decals are enabled, loop through them first: + float4 decalAccumulation = 0; + float4 decalBumpAccumulation = 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) { - // decals are enabled, loop through them first: - float4 decalAccumulation = 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 + // 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; - // 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) + 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 = asint(decalProjection[3][2]); + decalProjection[3] = float4(0, 0, 0, 1); + const float3 clipSpacePos = mul(decalProjection, float4(surface.P, 1)).xyz; + const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); + [branch] + if (is_saturated(uvw)) { - 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) + // 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); + decalColor.a *= edgeBlend; + [branch] + if (decalTexture >= 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 && decalAccumulation.a < 1) - { - 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]); - decalProjection[3] = float4(0, 0, 0, 1); - const float3 clipSpacePos = mul(decalProjection, float4(surface.P, 1)).xyz; - const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); - [branch] - if (is_saturated(uvw)) - { - // mipmapping needs to be performed by hand: - float4 decalColor = 1; - [branch] - if (decalTexture >= 0) - { - const float2 decalDX = mul(P_dx, (float3x3)decalProjection).xy; - const float2 decalDY = mul(P_dy, (float3x3)decalProjection).xy; - decalColor = bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sampler_objectshader, uvw.xy, decalDX, decalDY); - } - // blend out if close to cube Z: - float edgeBlend = 1 - pow(saturate(abs(clipSpacePos.z)), 8); - decalColor.a *= edgeBlend; - decalColor *= decal.GetColor(); - // 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 (decalAccumulation.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; - } - + decalColor *= bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sampler_objectshader, uvw.xy, decalDX, decalDY); + // 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); } } - - surface.albedo.rgb = lerp(surface.albedo.rgb, decalAccumulation.rgb, decalAccumulation.a); } + + surface.baseColor.rgb = lerp(surface.baseColor.rgb, decalAccumulation.rgb, decalAccumulation.a); + surface.bumpColor.rgb = lerp(surface.bumpColor.rgb, decalBumpAccumulation.rgb, decalBumpAccumulation.a); +#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_DECALS - TiledDecals(surface, flatTileIndex); -#endif // DISABLE_DECALS - #ifndef DISABLE_ENVMAPS // Apply environment maps: float4 envmapAccumulation = 0; @@ -892,15 +777,106 @@ inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint f } } -inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint2 tileIndex) + +inline void TiledDecals(inout Surface surface, uint flatTileIndex) { - const uint flatTileIndex = flatten2D(tileIndex, GetCamera().entity_culling_tilecount.xy) * SHADER_ENTITY_TILE_BUCKET_COUNT; - TiledLighting(surface, lighting, flatTileIndex); -} -inline void TiledLighting(inout Surface surface, inout Lighting lighting) -{ - const uint2 tileIndex = uint2(floor(surface.pixel / TILED_CULLING_BLOCKSIZE)); - TiledLighting(surface, lighting, tileIndex); +#ifndef DISABLE_DECALS + [branch] + if (GetFrame().decalarray_count == 0) + return; + + // decals are enabled, loop through them first: + float4 decalAccumulation = 0; + float4 decalBumpAccumulation = 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) + { + // 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]; + decalProjection[3] = float4(0, 0, 0, 1); + const float3 clipSpacePos = mul(decalProjection, float4(surface.P, 1)).xyz; + const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); + [branch] + if (is_saturated(uvw)) + { + // 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); + decalColor.a *= edgeBlend; + [branch] + if (decalTexture >= 0) + { + decalColor *= bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sampler_objectshader, uvw.xy, decalDX, decalDY); + // 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); + } + } + } + else if (entity_index > last_item) + { + // force exit: + bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; + break; + } + + } + } + + surface.baseColor.rgb = lerp(surface.baseColor.rgb, decalAccumulation.rgb, decalAccumulation.a); + surface.bumpColor.rgb = lerp(surface.bumpColor.rgb, decalBumpAccumulation.rgb, decalBumpAccumulation.a); +#endif // DISABLE_DECALS } inline void ApplyFog(in float distance, float3 V, inout float4 color) @@ -1059,9 +1035,8 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target { const float depth = input.pos.z; const float lineardepth = input.pos.w; - const float2 pixel = input.pos.xy; + const uint2 pixel = input.pos.xy; const float2 ScreenCoord = pixel * GetCamera().internal_resolution_rcp; - float3 bumpColor = 0; #ifndef DISABLE_ALPHATEST #ifndef TRANSPARENT @@ -1116,8 +1091,6 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target - float4 color = 1; - #ifdef OBJECTSHADER_USE_UVSETS [branch] #ifdef PREPASS @@ -1126,14 +1099,13 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target if (GetMaterial().textures[BASECOLORMAP].IsValid() && (GetFrame().options & OPTION_BIT_DISABLE_ALBEDO_MAPS) == 0) #endif // PREPASS { - float4 baseColorMap = GetMaterial().textures[BASECOLORMAP].Sample(sampler_objectshader, input.uvsets); - color *= baseColorMap; + surface.baseColor *= GetMaterial().textures[BASECOLORMAP].Sample(sampler_objectshader, input.uvsets); } #endif // OBJECTSHADER_USE_UVSETS #ifdef OBJECTSHADER_USE_COLOR - color *= input.color; + surface.baseColor *= input.color; #endif // OBJECTSHADER_USE_COLOR @@ -1142,15 +1114,41 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target // Alpha test is only done for transparents // - Prepass will write alpha coverage mask // - Opaque will use [earlydepthstencil] and COMPARISON_EQUAL depth test on top of depth prepass - clip(color.a - GetMaterial().alphaTest); + clip(surface.baseColor.a - GetMaterial().alphaTest); #endif // DISABLE_ALPHATEST #endif // TRANSPARENT +#ifndef WATER +#ifdef OBJECTSHADER_USE_TANGENT + [branch] + if (GetMaterial().normalMapStrength > 0 && GetMaterial().textures[NORMALMAP].IsValid()) + { + surface.bumpColor = float3(GetMaterial().textures[NORMALMAP].Sample(sampler_objectshader, input.uvsets).rg, 1); + surface.bumpColor = surface.bumpColor * 2 - 1; + surface.bumpColor.rg *= GetMaterial().normalMapStrength; + } +#endif // OBJECTSHADER_USE_TANGENT +#endif // WATER + + +#ifdef FORWARD + ForwardDecals(surface); +#endif // FORWARD + +#ifdef TILEDFORWARD + const uint flat_tile_index = GetFlatTileIndex(pixel); + TiledDecals(surface, flat_tile_index); +#endif // TILEDFORWARD + #ifndef WATER #ifdef OBJECTSHADER_USE_TANGENT - NormalMapping(input.uvsets, surface.N, TBN, bumpColor); + [branch] + if (any(surface.bumpColor)) + { + surface.N = normalize(lerp(surface.N, mul(surface.bumpColor, TBN), length(surface.bumpColor))); + } #endif // OBJECTSHADER_USE_TANGENT #endif // WATER @@ -1178,7 +1176,7 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target - surface.create(GetMaterial(), color, surfaceMap, specularMap); + surface.create(GetMaterial(), surface.baseColor, surfaceMap, specularMap); // Emissive map: @@ -1318,9 +1316,9 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target { bumpColor2 = bindless_textures_float2[GetCamera().texture_waterriples_index].SampleLevel(sampler_linear_clamp, ScreenCoord, 0).rg; } - bumpColor = float3(bumpColor0 + bumpColor1 + bumpColor2, 1) * GetMaterial().refraction; - surface.N = normalize(lerp(surface.N, mul(normalize(bumpColor), TBN), GetMaterial().normalMapStrength)); - bumpColor *= GetMaterial().normalMapStrength; + surface.bumpColor = float3(bumpColor0 + bumpColor1 + bumpColor2, 1) * GetMaterial().refraction; + surface.N = normalize(lerp(surface.N, mul(normalize(surface.bumpColor), TBN), GetMaterial().normalMapStrength)); + surface.bumpColor *= GetMaterial().normalMapStrength; [branch] if (GetCamera().texture_reflection_index >= 0) @@ -1329,7 +1327,7 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target float4 reflectionUV = mul(GetCamera().reflection_view_projection, float4(surface.P, 1)); reflectionUV.xy /= reflectionUV.w; reflectionUV.xy = clipspace_to_uv(reflectionUV.xy); - lighting.indirect.specular += bindless_textures[GetCamera().texture_reflection_index].SampleLevel(sampler_linear_mirror, reflectionUV.xy + bumpColor.rg, 0).rgb * surface.F; + lighting.indirect.specular += bindless_textures[GetCamera().texture_reflection_index].SampleLevel(sampler_linear_mirror, reflectionUV.xy + surface.bumpColor.rg, 0).rgb * surface.F; } #endif // WATER @@ -1373,7 +1371,7 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target #ifdef PLANARREFLECTION - lighting.indirect.specular += PlanarReflection(surface, bumpColor.rg) * surface.F; + lighting.indirect.specular += PlanarReflection(surface, surface.bumpColor.rg) * surface.F; #endif @@ -1383,7 +1381,7 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target #ifdef TILEDFORWARD - TiledLighting(surface, lighting); + TiledLighting(surface, lighting, flat_tile_index); #endif // TILEDFORWARD @@ -1403,15 +1401,17 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target #endif // WATER + float4 color = surface.baseColor; + #ifdef WATER [branch] if (GetCamera().texture_refraction_index >= 0) { // WATER REFRACTION Texture2D texture_refraction = bindless_textures[GetCamera().texture_refraction_index]; - float sampled_lineardepth = texture_lineardepth.SampleLevel(sampler_point_clamp, ScreenCoord.xy + bumpColor.rg, 0) * GetCamera().z_far; + float sampled_lineardepth = texture_lineardepth.SampleLevel(sampler_point_clamp, ScreenCoord.xy + surface.bumpColor.rg, 0) * GetCamera().z_far; float depth_difference = sampled_lineardepth - lineardepth; - surface.refraction.rgb = texture_refraction.SampleLevel(sampler_linear_mirror, ScreenCoord.xy + bumpColor.rg * saturate(0.5 * depth_difference), 0).rgb; + surface.refraction.rgb = texture_refraction.SampleLevel(sampler_linear_mirror, ScreenCoord.xy + surface.bumpColor.rg * saturate(0.5 * depth_difference), 0).rgb; if (depth_difference < 0) { // Fix cutoff by taking unperturbed depth diff to fill the holes with fog: @@ -1424,7 +1424,6 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target } #endif // WATER - ApplyLighting(surface, lighting, color); diff --git a/WickedEngine/shaders/objectPS.hlsl b/WickedEngine/shaders/objectPS.hlsl index a29ee8d3b..052600fea 100644 --- a/WickedEngine/shaders/objectPS.hlsl +++ b/WickedEngine/shaders/objectPS.hlsl @@ -1,7 +1,5 @@ #define OBJECTSHADER_COMPILE_PS #define OBJECTSHADER_LAYOUT_COMMON -#define SHADOW_MASK_ENABLED #define TILEDFORWARD -#define DISABLE_ALPHATEST #include "objectHF.hlsli" diff --git a/WickedEngine/shaders/oceanSurfacePS.hlsl b/WickedEngine/shaders/oceanSurfacePS.hlsl index 01f5681ba..32bb5ef61 100644 --- a/WickedEngine/shaders/oceanSurfacePS.hlsl +++ b/WickedEngine/shaders/oceanSurfacePS.hlsl @@ -19,6 +19,7 @@ float4 main(PSIn input) : SV_TARGET float dist = length(V); V /= dist; float emissive = 0; + uint2 pixel = input.pos.xy; float ocean_level_at_camera_pos = xOceanWaterHeight; ocean_level_at_camera_pos += texture_ocean_displacementmap.SampleLevel(sampler_linear_wrap, GetCamera().position.xz * xOceanPatchSizeRecip, 0).z; // texture contains xzy! @@ -33,7 +34,7 @@ float4 main(PSIn input) : SV_TARGET Surface surface; surface.init(); surface.flags |= SURFACE_FLAG_RECEIVE_SHADOW; - surface.pixel = input.pos.xy; + surface.pixel = pixel; float depth = input.pos.z; surface.albedo = color.rgb; surface.f0 = camera_above_water ? 0.02 : 0.1; @@ -48,7 +49,7 @@ float4 main(PSIn input) : SV_TARGET Lighting lighting; lighting.create(0, 0, GetAmbient(surface.N), 0); - TiledLighting(surface, lighting); + TiledLighting(surface, lighting, GetFlatTileIndex(pixel)); float2 ScreenCoord = surface.pixel * GetCamera().internal_resolution_rcp; const float bump_strength = camera_above_water ? 0.04 : 0.1; diff --git a/WickedEngine/shaders/screenspaceshadowCS.hlsl b/WickedEngine/shaders/screenspaceshadowCS.hlsl index f4718f35a..9dfecab46 100644 --- a/WickedEngine/shaders/screenspaceshadowCS.hlsl +++ b/WickedEngine/shaders/screenspaceshadowCS.hlsl @@ -5,15 +5,6 @@ PUSHCONSTANT(postprocess, PostProcess); -uint load_entitytile(uint tileIndex) -{ -#ifdef TRANSPARENT - return bindless_buffers[GetCamera().buffer_entitytiles_transparent_index].Load(tileIndex * sizeof(uint)); -#else - return bindless_buffers[GetCamera().buffer_entitytiles_opaque_index].Load(tileIndex * sizeof(uint)); -#endif // TRANSPARENT -} - static const uint MAX_RTSHADOWS = 16; RWTexture2D output : register(u0); diff --git a/WickedEngine/shaders/surfaceHF.hlsli b/WickedEngine/shaders/surfaceHF.hlsli index 7f47a7b69..8501572ce 100644 --- a/WickedEngine/shaders/surfaceHF.hlsli +++ b/WickedEngine/shaders/surfaceHF.hlsli @@ -280,7 +280,7 @@ struct Surface return true; } - void load_internal() + void load_internal(uint flatTileIndex = 0) { SamplerState sam = bindless_samplers[material.sampler_descriptor]; @@ -383,16 +383,16 @@ struct Surface if (geometry.vb_tan >= 0 && material.textures[NORMALMAP].IsValid() && material.normalMapStrength > 0) { #ifdef SURFACE_LOAD_QUAD_DERIVATIVES - const float3 normalMap = float3(material.textures[NORMALMAP].SampleGrad(sam, uvsets, uvsets_dx, uvsets_dy).rg, 1) * 2 - 1; + bumpColor = float3(material.textures[NORMALMAP].SampleGrad(sam, uvsets, uvsets_dx, uvsets_dy).rg, 1); #else float lod = 0; #ifdef SURFACE_LOAD_MIPCONE lod = compute_texture_lod(material.textures[NORMALMAP].GetTexture(), material.textures[NORMALMAP].GetUVSet() == 0 ? lod_constant0 : lod_constant1, ray_direction, surf_normal, cone_width); #endif // SURFACE_LOAD_MIPCONE - const float3 normalMap = float3(material.textures[NORMALMAP].SampleLevel(sam, uvsets, lod).rg, 1) * 2 - 1; + bumpColor = float3(material.textures[NORMALMAP].SampleLevel(sam, uvsets, lod).rg, 1); #endif // SURFACE_LOAD_QUAD_DERIVATIVES - N = normalize(lerp(N, mul(normalMap, TBN), material.normalMapStrength)); - bumpColor = normalMap * material.normalMapStrength; + bumpColor = bumpColor * 2 - 1; + bumpColor.rg *= material.normalMapStrength; } } @@ -446,6 +446,105 @@ struct Surface flags |= SURFACE_FLAG_GI_APPLIED; } +#ifdef SURFACE_LOAD_QUAD_DERIVATIVES + // I need to copy the decal code here because include resolve issues: +#ifndef DISABLE_DECALS + [branch] + if (GetFrame().decalarray_count > 0) + { + // decals are enabled, loop through them first: + float4 decalAccumulation = 0; + float4 decalBumpAccumulation = 0; + + // 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) + { + // 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 & 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]; + decalProjection[3] = float4(0, 0, 0, 1); + const float3 clipSpacePos = mul(decalProjection, float4(P, 1)).xyz; + const float3 uvw = clipspace_to_uv(clipSpacePos.xyz); + [branch] + if (is_saturated(uvw)) + { + // 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); + decalColor.a *= edgeBlend; + [branch] + if (decalTexture >= 0) + { + decalColor *= bindless_textures[NonUniformResourceIndex(decalTexture)].SampleGrad(sam, uvw.xy, decalDX, decalDY); + // 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); + } + } + } + else if (entity_index > last_item) + { + // force exit: + bucket = SHADER_ENTITY_TILE_BUCKET_COUNT; + break; + } + + } + } + + baseColor.rgb = lerp(baseColor.rgb, decalAccumulation.rgb, decalAccumulation.a); + bumpColor.rgb = lerp(bumpColor.rgb, decalBumpAccumulation.rgb, decalBumpAccumulation.a); + } +#endif // DISABLE_DECALS +#endif // SURFACE_LOAD_QUAD_DERIVATIVES + + if (any(bumpColor)) + { + const float3x3 TBN = float3x3(T.xyz, B, N); + N = normalize(lerp(N, mul(bumpColor, TBN), length(bumpColor))); + } + float4 surfaceMap = 1; [branch] if (material.textures[SURFACEMAP].IsValid() && !simple_lighting) @@ -617,7 +716,7 @@ struct Surface #endif // SURFACE_LOAD_QUAD_DERIVATIVES clearcoatNormalMap = clearcoatNormalMap * 2 - 1; - const float3x3 TBN = float3x3(T.xyz, B, N); + const float3x3 TBN = float3x3(T.xyz, B, facenormal); clearcoat.N = mul(clearcoatNormalMap, TBN); } @@ -738,7 +837,7 @@ struct Surface load_internal(); return true; } - bool load(in PrimitiveID prim, in float3 rayOrigin, in float3 rayDirection, in float3 rayDirection_quad_x, in float3 rayDirection_quad_y) + bool load(in PrimitiveID prim, in float3 rayOrigin, in float3 rayDirection, in float3 rayDirection_quad_x, in float3 rayDirection_quad_y, in uint flatTileIndex = 0) { if (!preload_internal(prim)) return false; @@ -781,7 +880,7 @@ struct Surface P_dy = P - attribute_at_bary(P0, P1, P2, bary_quad_y); #endif // SURFACE_LOAD_QUAD_DERIVATIVES - load_internal(); + load_internal(flatTileIndex); return true; } }; diff --git a/WickedEngine/shaders/visibility_surfaceCS.hlsl b/WickedEngine/shaders/visibility_surfaceCS.hlsl index 353a69af7..b91a5f62e 100644 --- a/WickedEngine/shaders/visibility_surfaceCS.hlsl +++ b/WickedEngine/shaders/visibility_surfaceCS.hlsl @@ -42,17 +42,14 @@ void main(uint Gid : SV_GroupID, uint groupIndex : SV_GroupIndex) Surface surface; surface.init(); - - [branch] - if (!surface.load(prim, ray.Origin, ray.Direction, rayDirection_quad_x, rayDirection_quad_y)) - { - return; - } surface.pixel = pixel.xy; surface.screenUV = uv; - TiledDecals(surface, tile.entity_flat_tile_index); - + [branch] + if (!surface.load(prim, ray.Origin, ray.Direction, rayDirection_quad_x, rayDirection_quad_y, tile.entity_flat_tile_index)) + { + return; + } #ifdef UNLIT float4 color = float4(surface.albedo, 1); diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index f27f02b14..f5fd0cd3b 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -3769,6 +3769,7 @@ void UpdateRenderData( } shadermatrix.r[0] = XMVectorSetW(shadermatrix.r[0], *(float*)&texture); shadermatrix.r[1] = XMVectorSetW(shadermatrix.r[1], *(float*)&normal); + shadermatrix.r[2] = XMVectorSetW(shadermatrix.r[2], decal.normal_strength); std::memcpy(matrixArray + matrixCounter, &shadermatrix, sizeof(XMMATRIX)); matrixCounter++; diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 395940f40..763d60259 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -3795,6 +3795,7 @@ namespace wi::scene decal.emissive = material.GetEmissiveStrength(); decal.texture = material.textures[MaterialComponent::BASECOLORMAP].resource; decal.normal = material.textures[MaterialComponent::NORMALMAP].resource; + decal.normal_strength = material.normalMapStrength; } } void Scene::RunProbeUpdateSystem(wi::jobsystem::context& ctx) diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index e1e4a8ca9..8a8cc4ccd 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -1054,9 +1054,10 @@ namespace wi::scene uint32_t _flags = EMPTY; // Non-serialized attributes: - XMFLOAT4 color; float emissive; + XMFLOAT4 color; XMFLOAT3 front; + float normal_strength; XMFLOAT3 position; float range; XMFLOAT4X4 world; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 940ee7264..f3795e325 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 = 163; + const int revision = 164; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);