From b37b99f63711dc67b487afdf3ef47719fb610454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Tue, 17 Feb 2026 16:59:51 +0000 Subject: [PATCH] envprobe: ocean and recursive reflection support (#1556) --- WickedEngine/offlineshadercompiler.cpp | 5 +- WickedEngine/shaders/ShaderInterop_Renderer.h | 1 + WickedEngine/shaders/Shaders_SOURCE.vcxitems | 3 +- .../shaders/Shaders_SOURCE.vcxitems.filters | 9 +- .../shaders/aerialPerspectiveCS_capture.hlsl | 2 - .../aerialPerspectiveCS_capture_MSAA.hlsl | 2 - WickedEngine/shaders/lightingHF.hlsli | 28 ------ WickedEngine/shaders/objectHF.hlsli | 12 +-- WickedEngine/shaders/oceanSurfaceHF.hlsli | 9 +- WickedEngine/shaders/oceanSurfacePS.hlsl | 81 +++++++++------- .../shaders/oceanSurfacePS_envmap.hlsl | 3 + WickedEngine/shaders/oceanSurfaceVS.hlsl | 16 +-- WickedEngine/shaders/shadingHF.hlsli | 4 - WickedEngine/shaders/surfaceHF.hlsli | 6 -- WickedEngine/wiEnums.h | 2 - WickedEngine/wiGraphicsDevice.h | 16 +++ WickedEngine/wiOcean.cpp | 71 +++++++++++++- WickedEngine/wiOcean.h | 5 + WickedEngine/wiRenderPath3D.cpp | 4 + WickedEngine/wiRenderer.cpp | 97 +++++-------------- WickedEngine/wiScene_Components.cpp | 2 +- WickedEngine/wiVersion.cpp | 2 +- 22 files changed, 198 insertions(+), 182 deletions(-) delete mode 100644 WickedEngine/shaders/aerialPerspectiveCS_capture.hlsl delete mode 100644 WickedEngine/shaders/aerialPerspectiveCS_capture_MSAA.hlsl create mode 100644 WickedEngine/shaders/oceanSurfacePS_envmap.hlsl diff --git a/WickedEngine/offlineshadercompiler.cpp b/WickedEngine/offlineshadercompiler.cpp index e1d03119c..616d2f86b 100644 --- a/WickedEngine/offlineshadercompiler.cpp +++ b/WickedEngine/offlineshadercompiler.cpp @@ -10,7 +10,7 @@ class nullbuf_t : public std::streambuf { protected: virtual int_type overflow(int_type ch) override - { + { return traits_type::not_eof(ch); } } nullbuf; @@ -174,8 +174,6 @@ wi::vector shaders = { {"shadingRateClassificationCS", wi::graphics::ShaderStage::CS }, {"shadingRateClassificationCS_DEBUG", wi::graphics::ShaderStage::CS }, {"aerialPerspectiveCS", wi::graphics::ShaderStage::CS }, - {"aerialPerspectiveCS_capture", wi::graphics::ShaderStage::CS }, - {"aerialPerspectiveCS_capture_MSAA", wi::graphics::ShaderStage::CS }, {"skyAtmosphere_cameraVolumeLutCS", wi::graphics::ShaderStage::CS }, {"skyAtmosphere_transmittanceLutCS", wi::graphics::ShaderStage::CS }, {"skyAtmosphere_skyViewLutCS", wi::graphics::ShaderStage::CS }, @@ -230,6 +228,7 @@ wi::vector shaders = { {"imagePS", wi::graphics::ShaderStage::PS }, {"emittedparticlePS_soft_lighting", wi::graphics::ShaderStage::PS }, {"oceanSurfacePS", wi::graphics::ShaderStage::PS }, + {"oceanSurfacePS_envmap", wi::graphics::ShaderStage::PS }, {"hairparticlePS", wi::graphics::ShaderStage::PS }, {"hairparticlePS_simple", wi::graphics::ShaderStage::PS }, {"hairparticlePS_prepass", wi::graphics::ShaderStage::PS }, diff --git a/WickedEngine/shaders/ShaderInterop_Renderer.h b/WickedEngine/shaders/ShaderInterop_Renderer.h index e0d974b59..eb877eccb 100644 --- a/WickedEngine/shaders/ShaderInterop_Renderer.h +++ b/WickedEngine/shaders/ShaderInterop_Renderer.h @@ -1421,6 +1421,7 @@ struct alignas(16) ShaderCamera position = {}; output_index = 0; clip_plane = {}; + reflection_plane = float4(0, 1, 0, 0); forward = {}; z_near = {}; up = {}; diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems b/WickedEngine/shaders/Shaders_SOURCE.vcxitems index fd11e046f..4ea324a0c 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems @@ -345,6 +345,7 @@ Pixel + Pixel @@ -738,8 +739,6 @@ Compute - - Compute diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters index 735f699c5..a3dfec123 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters @@ -977,12 +977,6 @@ CS - - CS - - - CS - CS @@ -1139,6 +1133,9 @@ VS + + PS + diff --git a/WickedEngine/shaders/aerialPerspectiveCS_capture.hlsl b/WickedEngine/shaders/aerialPerspectiveCS_capture.hlsl deleted file mode 100644 index d5923c400..000000000 --- a/WickedEngine/shaders/aerialPerspectiveCS_capture.hlsl +++ /dev/null @@ -1,2 +0,0 @@ -#define AERIALPERSPECTIVE_CAPTURE -#include "aerialPerspectiveCS.hlsl" diff --git a/WickedEngine/shaders/aerialPerspectiveCS_capture_MSAA.hlsl b/WickedEngine/shaders/aerialPerspectiveCS_capture_MSAA.hlsl deleted file mode 100644 index b863a404a..000000000 --- a/WickedEngine/shaders/aerialPerspectiveCS_capture_MSAA.hlsl +++ /dev/null @@ -1,2 +0,0 @@ -#define MSAA -#include "aerialPerspectiveCS_capture.hlsl" diff --git a/WickedEngine/shaders/lightingHF.hlsli b/WickedEngine/shaders/lightingHF.hlsli index cb04203d5..ba9ab4659 100644 --- a/WickedEngine/shaders/lightingHF.hlsli +++ b/WickedEngine/shaders/lightingHF.hlsli @@ -545,16 +545,6 @@ inline half3 GetAmbient(in float3 N) { half3 ambient; -#ifdef ENVMAPRENDERING - - // Set realistic_sky_stationary to true so we capture ambient at float3(0.0, 0.0, 0.0), similar to the standard sky to avoid flickering and weird behavior - ambient = lerp( - GetDynamicSkyColor(float3(0, -1, 0), false, false, true), - GetDynamicSkyColor(float3(0, 1, 0), false, false, true), - saturate(N.y * 0.5 + 0.5)); - -#else - [branch] if (GetScene().globalprobe >= 0) { @@ -564,8 +554,6 @@ inline half3 GetAmbient(in float3 N) cubemap.GetDimensions(0, dim.x, dim.y, mipcount); ambient = cubemap.SampleLevel(sampler_linear_clamp, N, mipcount).rgb; } - -#endif // ENVMAPRENDERING #ifndef NO_FLAT_AMBIENT // This is not entirely correct if we have probes, because it shouldn't be added twice. @@ -583,20 +571,6 @@ inline half3 GetAmbient(in float3 N) inline half3 EnvironmentReflection_Global(in Surface surface) { half3 envColor; - -#ifdef ENVMAPRENDERING - - // There is no access to envmaps, so approximate sky color: - // Set realistic_sky_stationary to true so we capture environment at float3(0.0, 0.0, 0.0), similar to the standard sky to avoid flickering and weird behavior - float3 skycolor_real = GetDynamicSkyColor(surface.R, false, false, true); // false: disable sun disk and clouds - float3 skycolor_rough = lerp( - GetDynamicSkyColor(float3(0, -1, 0), false, false, true), - GetDynamicSkyColor(float3(0, 1, 0), false, false, true), - saturate(surface.R.y * 0.5 + 0.5)); - - envColor = lerp(skycolor_real, skycolor_rough, surface.roughness) * surface.F; - -#else [branch] if (GetScene().globalprobe < 0) @@ -623,8 +597,6 @@ inline half3 EnvironmentReflection_Global(in Surface surface) envColor += cubemap.SampleLevel(sampler_linear_clamp, surface.clearcoat.R, MIP).rgb * surface.clearcoat.F; #endif // CLEARCOAT -#endif // ENVMAPRENDERING - return envColor; } diff --git a/WickedEngine/shaders/objectHF.hlsli b/WickedEngine/shaders/objectHF.hlsli index 59c9e60b7..af9d6cb86 100644 --- a/WickedEngine/shaders/objectHF.hlsli +++ b/WickedEngine/shaders/objectHF.hlsli @@ -808,11 +808,11 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace APPEND_COVER #ifdef OBJECTSHADER_USE_COMMON half wet = input.ao_wet.y; - if(wet > 0) + if (wet > 0) { - surface.albedo = lerp(surface.albedo, 0, wet); - surface.roughness = clamp(surface.roughness * sqr(1 - wet), 0.01, 1); - surface.N = normalize(lerp(surface.N, input.nor, wet)); + surface.albedo = lerp(surface.albedo, 0, wet); // darken color when wet + surface.roughness = clamp(surface.roughness * saturate(sqr((1 - wet) * 2 - 1)), 0.01, 1); // decrease eoughness when wet, but only at shoreline, not deeper underwater (sand underwater shouldn't be shiny) + surface.N = normalize(lerp(surface.N, input.nor, wet)); // blend to vertex normal when wet } #endif // OBJECTSHADER_USE_COMMON @@ -1116,9 +1116,9 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace APPEND_COVER // Transparent objects has been rendered separately from opaque, so let's apply it now. // Must also be applied before fog since fog is layered over. -#ifdef TRANSPARENT +#if defined(TRANSPARENT) || defined(ENVMAPRENDERING) ApplyAerialPerspective(ScreenCoord, surface.P, color); -#endif // TRANSPARENT +#endif // defined(TRANSPARENT) || defined(ENVMAPRENDERING) ApplyFog(dist, surface.V, color); diff --git a/WickedEngine/shaders/oceanSurfaceHF.hlsli b/WickedEngine/shaders/oceanSurfaceHF.hlsli index 3a856c7f8..697399acb 100644 --- a/WickedEngine/shaders/oceanSurfaceHF.hlsli +++ b/WickedEngine/shaders/oceanSurfaceHF.hlsli @@ -5,17 +5,18 @@ struct PSIn { - float4 pos : SV_POSITION; - float2 uv : TEXCOORD0; + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + min16uint cameraIndex : CAMERAINDEX; inline float3 GetPos3D() { - return GetCamera().screen_to_world(pos); + return GetCameraIndexed(cameraIndex).screen_to_world(pos); } inline float3 GetViewVector() { - return GetCamera().screen_to_nearplane(pos) - GetPos3D(); // ortho support, cannot use cameraPos! + return GetCameraIndexed(cameraIndex).screen_to_nearplane(pos) - GetPos3D(); // ortho support, cannot use cameraPos! } }; diff --git a/WickedEngine/shaders/oceanSurfacePS.hlsl b/WickedEngine/shaders/oceanSurfacePS.hlsl index 7437f2223..da315c068 100644 --- a/WickedEngine/shaders/oceanSurfacePS.hlsl +++ b/WickedEngine/shaders/oceanSurfacePS.hlsl @@ -14,9 +14,10 @@ Texture2D texture_gradientmap : register(t1); [earlydepthstencil] float4 main(PSIn input) : SV_TARGET { - float lineardepth = GetCamera().IsOrtho() ? ((1 - input.pos.z) * GetCamera().z_far) : input.pos.w; + ShaderCamera camera = GetCameraIndexed(input.cameraIndex); + float lineardepth = camera.IsOrtho() ? ((1 - input.pos.z) * camera.z_far) : input.pos.w; half4 color = xOceanWaterColor; - float2 ScreenCoord = input.pos.xy * GetCamera().internal_resolution_rcp; + float2 ScreenCoord = input.pos.xy * camera.internal_resolution_rcp; float3 V = input.GetViewVector(); float dist = length(V); @@ -30,9 +31,9 @@ float4 main(PSIn input) : SV_TARGET half4 gradient = lerp(gradientNear, gradientFar, gradient_fade); [branch] - if (GetCamera().texture_waterriples_index >= 0) + if (camera.texture_waterriples_index >= 0) { - gradient.rg += bindless_textures_half4[descriptor_index(GetCamera().texture_waterriples_index)].SampleLevel(sampler_linear_clamp, ScreenCoord, 0).rg * 0.025; + gradient.rg += bindless_textures_half4[descriptor_index(camera.texture_waterriples_index)].SampleLevel(sampler_linear_clamp, ScreenCoord, 0).rg * 0.025; } Surface surface; @@ -54,24 +55,28 @@ float4 main(PSIn input) : SV_TARGET Lighting lighting; lighting.create(0, 0, GetAmbient(surface.N), 0); +#ifdef FORWARD + ForwardLighting(surface, lighting); +#else TiledLighting(surface, lighting, GetFlatTileIndex(pixel)); +#endif // FORWARD const float bump_strength = 0.1; - float4 water_plane = GetCamera().reflection_plane; + float4 water_plane = camera.reflection_plane; [branch] - if (GetCamera().texture_reflection_index >= 0) + if (camera.texture_reflection_index >= 0) { //REFLECTION - float4 reflectionPos = mul(GetCamera().reflection_view_projection, float4(surface.P, 1)); + float4 reflectionPos = mul(camera.reflection_view_projection, float4(surface.P, 1)); float2 reflectionUV = clipspace_to_uv(reflectionPos.xy / reflectionPos.w) + surface.N.xz * bump_strength; - half4 reflectiveColor = bindless_textures[descriptor_index(GetCamera().texture_reflection_index)].SampleLevel(sampler_linear_mirror, reflectionUV, 0); + half4 reflectiveColor = bindless_textures[descriptor_index(camera.texture_reflection_index)].SampleLevel(sampler_linear_mirror, reflectionUV, 0); [branch] - if(GetCamera().texture_reflection_depth_index >=0) + if(camera.texture_reflection_depth_index >=0) { - float reflectiveDepth = bindless_textures[descriptor_index(GetCamera().texture_reflection_depth_index)].SampleLevel(sampler_point_clamp, reflectionUV, 0).r; - float3 reflectivePosition = reconstruct_position(reflectionUV, reflectiveDepth, GetCamera().reflection_inverse_view_projection); + float reflectiveDepth = bindless_textures[descriptor_index(camera.texture_reflection_depth_index)].SampleLevel(sampler_point_clamp, reflectionUV, 0).r; + float3 reflectivePosition = reconstruct_position(reflectionUV, reflectiveDepth, camera.reflection_inverse_view_projection); float water_depth = -dot(float4(reflectivePosition, 1), water_plane); water_depth += texture_ocean_displacementmap.SampleLevel(sampler_linear_wrap, reflectivePosition.xz * xOceanPatchSizeRecip, 0).z; // texture contains xzy! reflectiveColor.rgb = lerp(color.rgb, reflectiveColor.rgb, saturate(exp(-water_depth * color.a))); @@ -86,11 +91,11 @@ float4 main(PSIn input) : SV_TARGET float water_depth = FLT_MAX; [branch] - if (GetCamera().texture_refraction_index >= 0) + if (camera.texture_refraction_index >= 0) { // Water refraction: - const float camera_above_water = dot(float4(GetCamera().position, 1), water_plane) < 0; - Texture2D texture_refraction = bindless_textures[descriptor_index(GetCamera().texture_refraction_index)]; + const float camera_above_water = dot(float4(camera.position, 1), water_plane) < 0; + Texture2D texture_refraction = bindless_textures[descriptor_index(camera.texture_refraction_index)]; // First sample using full perturbation: float2 refraction_uv = ScreenCoord.xy + surface.N.xz * bump_strength; float refraction_depth = find_max_depth(refraction_uv, 2, 2); @@ -126,33 +131,37 @@ float4 main(PSIn input) : SV_TARGET } #if 1 - // FOAM: - float water_depth_diff = abs(texture_lineardepth[pixel] * GetCamera().z_far - lineardepth); // Note: for the shore foam, this is more accurate than water plane distance - float foam_shore = saturate(exp(-water_depth_diff * 2)); - float foam_wave = pow(saturate(gradient.a), 4) * saturate(exp(-water_depth * 0.1)); - float foam_combined = saturate(foam_shore + foam_wave); - float foam_simplex = 0; - foam_simplex += smoothstep(0, 0.8, noise_simplex_2D(surface.P.xz * 1 + GetTime())); - foam_simplex += smoothstep(0, 0.8, noise_simplex_2D(surface.P.xz * 2 + GetTime())); - foam_simplex += smoothstep(0, 0.8, noise_simplex_2D(surface.P.zx * 4 - GetTime() * 2)); - float foam_voronoi = 0; - foam_voronoi += smoothstep(0.5, 0.8, noise_voronoi(surface.P.xz * 1, GetTime()).x); - foam_voronoi += smoothstep(0.5, 0.8, noise_voronoi(surface.P.xz * 2, GetTime()).x); - foam_voronoi += smoothstep(0.5, 0.8, noise_voronoi(surface.P.xz * 4, GetTime()).x); - float foam = 0; - foam += foam_voronoi * foam_simplex * foam_combined; - foam += smoothstep(0.5, 0.6, saturate(foam_combined + 0.1)); - foam *= 2; - foam = saturate(foam); - surface.albedo = lerp(surface.albedo, 0.6, foam); - surface.refraction.a *= 1 - foam; - surface.refraction.a = saturate(surface.refraction.a + saturate(exp(-water_depth_diff * 4))); + [branch] + if (camera.texture_lineardepth_index >= 0) + { + // FOAM: + float water_depth_diff = abs(texture_lineardepth[pixel] * camera.z_far - lineardepth); // Note: for the shore foam, this is more accurate than water plane distance + float foam_shore = saturate(exp(-water_depth_diff * 2)); + float foam_wave = pow(saturate(gradient.a), 4) * saturate(exp(-water_depth * 0.1)); + float foam_combined = saturate(foam_shore + foam_wave); + float foam_simplex = 0; + foam_simplex += smoothstep(0, 0.8, noise_simplex_2D(surface.P.xz * 1 + GetTime())); + foam_simplex += smoothstep(0, 0.8, noise_simplex_2D(surface.P.xz * 2 + GetTime())); + foam_simplex += smoothstep(0, 0.8, noise_simplex_2D(surface.P.zx * 4 - GetTime() * 2)); + float foam_voronoi = 0; + foam_voronoi += smoothstep(0.5, 0.8, noise_voronoi(surface.P.xz * 1, GetTime()).x); + foam_voronoi += smoothstep(0.5, 0.8, noise_voronoi(surface.P.xz * 2, GetTime()).x); + foam_voronoi += smoothstep(0.5, 0.8, noise_voronoi(surface.P.xz * 4, GetTime()).x); + float foam = 0; + foam += foam_voronoi * foam_simplex * foam_combined; + foam += smoothstep(0.5, 0.6, saturate(foam_combined + 0.1)); + foam *= 2; + foam = saturate(foam); + surface.albedo = lerp(surface.albedo, 0.6, foam); + surface.refraction.a *= 1 - foam; + surface.refraction.a = saturate(surface.refraction.a + saturate(exp(-water_depth_diff * 4))); + } #endif ApplyLighting(surface, lighting, color); // Blend out at distance: - color.a = saturate(1 - saturate(dist / GetCamera().z_far - 0.8) * 5.0); // fade will be on edge and inwards 20% + color.a = saturate(1 - saturate(dist / camera.z_far - 0.8) * 5.0); // fade will be on edge and inwards 20% ApplyAerialPerspective(ScreenCoord, surface.P, color); diff --git a/WickedEngine/shaders/oceanSurfacePS_envmap.hlsl b/WickedEngine/shaders/oceanSurfacePS_envmap.hlsl new file mode 100644 index 000000000..a40bee8c7 --- /dev/null +++ b/WickedEngine/shaders/oceanSurfacePS_envmap.hlsl @@ -0,0 +1,3 @@ +#define ENVMAPRENDERING +#define FORWARD +#include "oceanSurfacePS.hlsl" diff --git a/WickedEngine/shaders/oceanSurfaceVS.hlsl b/WickedEngine/shaders/oceanSurfaceVS.hlsl index 6cc9e4c35..e0e36d872 100644 --- a/WickedEngine/shaders/oceanSurfaceVS.hlsl +++ b/WickedEngine/shaders/oceanSurfaceVS.hlsl @@ -3,9 +3,13 @@ Texture2D texture_displacementmap : register(t0); -PSIn main(uint vertexID : SV_VertexID) +PSIn main(uint vertexID : SV_VertexID, uint instanceID : SV_InstanceID, out uint RTIndex : SV_RenderTargetArrayIndex) { PSIn Out; + Out.cameraIndex = instanceID; + + ShaderCamera camera = GetCameraIndexed(Out.cameraIndex); + RTIndex = camera.output_index; float2 dim = xOceanScreenSpaceParams.xy; float2 invdim = xOceanScreenSpaceParams.zw; @@ -18,9 +22,9 @@ PSIn main(uint vertexID : SV_VertexID) Out.pos.xy *= max(1, xOceanSurfaceDisplacementTolerance); // extrude screen space grid to tolerate displacement // Perform ray tracing of screen grid and plane surface to unproject to world space: - float4 unprojNEAR = mul(GetCamera().inverse_view_projection, float4(Out.pos.xy, 1, 1)); + float4 unprojNEAR = mul(camera.inverse_view_projection, float4(Out.pos.xy, 1, 1)); unprojNEAR.xyz /= unprojNEAR.w; - float4 unprojFAR = mul(GetCamera().inverse_view_projection, float4(Out.pos.xy, 0, 1)); + float4 unprojFAR = mul(camera.inverse_view_projection, float4(Out.pos.xy, 0, 1)); unprojFAR.xyz /= unprojFAR.w; const float3 d = normalize(unprojNEAR.xyz - unprojFAR.xyz); const float3 o = unprojNEAR.xyz; @@ -32,13 +36,13 @@ PSIn main(uint vertexID : SV_VertexID) { // Displace surface: float3 displacement = texture_displacementmap.SampleLevel(sampler_linear_wrap, uv, 0).xzy; - float dist = length(worldPos - GetCamera().position); - displacement *= saturate(1 - saturate(dist / GetCamera().z_far - 0.8) * 5.0); // fade will be on edge and inwards 20% + float dist = length(worldPos - camera.position); + displacement *= saturate(1 - saturate(dist / camera.z_far - 0.8) * 5.0); // fade will be on edge and inwards 20% worldPos += displacement; } // Reproject displaced surface and output: - Out.pos = mul(GetCamera().view_projection, float4(worldPos, 1)); + Out.pos = mul(camera.view_projection, float4(worldPos, 1)); Out.uv = uv; return Out; diff --git a/WickedEngine/shaders/shadingHF.hlsli b/WickedEngine/shaders/shadingHF.hlsli index 6e94d651f..f9eb69ee9 100644 --- a/WickedEngine/shaders/shadingHF.hlsli +++ b/WickedEngine/shaders/shadingHF.hlsli @@ -48,7 +48,6 @@ inline void ForwardLighting(inout Surface surface, inout Lighting lighting) // Apply environment maps: half4 envmapAccumulation = 0; -#ifndef ENVMAPRENDERING #ifndef DISABLE_LOCALENVPMAPS [branch] if (xForwardEnvProbeMask != 0) @@ -91,7 +90,6 @@ inline void ForwardLighting(inout Surface surface, inout Lighting lighting) } } #endif // DISABLE_LOCALENVPMAPS -#endif //ENVMAPRENDERING // Apply global envmap where there is no local envmap information: [branch] @@ -288,9 +286,7 @@ inline uint GetFlatTileIndex(min16uint2 pixel) inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint flatTileIndex) { if (GetFrame().options & OPTION_BIT_FORCE_UNLIT) - { return; - } #ifndef DISABLE_ENVMAPS // Apply environment maps: diff --git a/WickedEngine/shaders/surfaceHF.hlsli b/WickedEngine/shaders/surfaceHF.hlsli index af87f453c..d9817b86e 100644 --- a/WickedEngine/shaders/surfaceHF.hlsli +++ b/WickedEngine/shaders/surfaceHF.hlsli @@ -208,16 +208,12 @@ struct Surface } f0 = material.GetSpecular() * specularMap.rgb * specularMap.a; -#ifndef ENVMAPRENDERING if (GetFrame().options & OPTION_BIT_FORCE_DIFFUSE_LIGHTING) -#endif // ENVMAPRENDERING { f0 = surfaceMap.b = surfaceMap.a = 0; } -#ifndef ENVMAPRENDERING if (GetFrame().options & OPTION_BIT_FORCE_UNLIT) -#endif // ENVMAPRENDERING { albedo = baseColor.rgb; } @@ -308,9 +304,7 @@ struct Surface F = smoothstep(0.1, 0.5, F); #endif // CARTOON -#ifndef ENVMAPRENDERING if (GetFrame().options & OPTION_BIT_FORCE_DIFFUSE_LIGHTING || GetFrame().options & OPTION_BIT_FORCE_UNLIT) -#endif // ENVMAPRENDERING { F = 0; } diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index 56ae005e3..0740ccc13 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -321,8 +321,6 @@ namespace wi::enums CSTYPE_POSTPROCESS_MOTIONBLUR_CHEAP, CSTYPE_POSTPROCESS_BLOOMSEPARATE, CSTYPE_POSTPROCESS_AERIALPERSPECTIVE, - CSTYPE_POSTPROCESS_AERIALPERSPECTIVE_CAPTURE, - CSTYPE_POSTPROCESS_AERIALPERSPECTIVE_CAPTURE_MSAA, CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_SHAPENOISE, CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_DETAILNOISE, CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_CURLNOISE, diff --git a/WickedEngine/wiGraphicsDevice.h b/WickedEngine/wiGraphicsDevice.h index b5870c336..4021a9324 100644 --- a/WickedEngine/wiGraphicsDevice.h +++ b/WickedEngine/wiGraphicsDevice.h @@ -285,6 +285,22 @@ namespace wi::graphics return CreateBufferCleared(desc, 0, buffer, alias, alias_offset); } + // This can be used to create a texture filled with a single value + bool CreateTextureCleared(const TextureDesc* desc, uint8_t value, Texture* texture, const GPUResource* alias = nullptr, uint64_t alias_offset = 0ull) const + { + wi::vector texturedata(ComputeTextureMemorySizeInBytes(*desc)); + std::fill(texturedata.begin(), texturedata.end(), value); + wi::vector initdata; + CreateTextureSubresourceDatas(*desc, texturedata.data(), initdata); + return CreateTexture(desc, initdata.data(), texture, alias, alias_offset); + } + + // This can be used to create a texture filled with zeroes + bool CreateTextureZeroed(const TextureDesc* desc, Texture* texture, const GPUResource* alias = nullptr, uint64_t alias_offset = 0ull) const + { + return CreateTextureCleared(desc, 0, texture, alias, alias_offset); + } + // Execute a single GPU barrier void Barrier(const GPUBarrier& barrier, CommandList cmd) { diff --git a/WickedEngine/wiOcean.cpp b/WickedEngine/wiOcean.cpp index 89aa958dd..465c0588d 100644 --- a/WickedEngine/wiOcean.cpp +++ b/WickedEngine/wiOcean.cpp @@ -24,13 +24,14 @@ namespace wi Shader oceanSurfVS; Shader wireframePS; Shader oceanSurfPS; + Shader oceanSurfPS_envmap; RasterizerState rasterizerState; RasterizerState wireRS; DepthStencilState depthStencilState, depthStencilState_occlusionTest; BlendState blendState, blendState_occlusionTest; - PipelineState PSO, PSO_wire, PSO_occlusionTest; + PipelineState PSO, PSO_envmap, PSO_wire, PSO_occlusionTest; void LoadShaders() @@ -42,6 +43,7 @@ namespace wi wi::renderer::LoadShader(ShaderStage::VS, oceanSurfVS, "oceanSurfaceVS.cso"); wi::renderer::LoadShader(ShaderStage::PS, oceanSurfPS, "oceanSurfacePS.cso"); + wi::renderer::LoadShader(ShaderStage::PS, oceanSurfPS_envmap, "oceanSurfacePS_envmap.cso"); wi::renderer::LoadShader(ShaderStage::PS, wireframePS, "oceanSurfaceSimplePS.cso"); @@ -56,6 +58,9 @@ namespace wi desc.dss = &depthStencilState; device->CreatePipelineState(&desc, &PSO); + desc.ps = &oceanSurfPS_envmap; + device->CreatePipelineState(&desc, &PSO_envmap); + desc.ps = &wireframePS; desc.rs = &wireRS; device->CreatePipelineState(&desc, &PSO_wire); @@ -474,6 +479,63 @@ namespace wi device->EventEnd(cmd); } + void Ocean::RenderForCubemap(CommandList cmd) const + { + GraphicsDevice* device = wi::graphics::GetDevice(); + + device->EventBegin("Ocean Rendering into Cubemap", cmd); + + const uint2 dim = uint2(64, 64); + const uint index_count = dim.x * dim.y * 6; + const uint64_t indexbuffer_required_size = index_count * sizeof(uint16_t); + static std::mutex locker; + locker.lock(); // in case two threads draw the ocean the same time, index buffer creation must be locked + if (indexBuffer_cubemap.GetDesc().size != indexbuffer_required_size) + { + wi::vector index_data(index_count); + size_t counter = 0; + for (uint16_t x = 0; x < dim.x - 1; x++) + { + for (uint16_t y = 0; y < dim.y - 1; y++) + { + uint16_t lowerLeft = x + y * dim.x; + uint16_t lowerRight = (x + 1) + y * dim.x; + uint16_t topLeft = x + (y + 1) * dim.x; + uint16_t topRight = (x + 1) + (y + 1) * dim.x; + + index_data[counter++] = topLeft; + index_data[counter++] = lowerLeft; + index_data[counter++] = lowerRight; + + index_data[counter++] = topLeft; + index_data[counter++] = lowerRight; + index_data[counter++] = topRight; + } + } + + GPUBufferDesc desc; + desc.bind_flags = BindFlag::INDEX_BUFFER; + desc.size = indexbuffer_required_size; + device->CreateBuffer(&desc, index_data.data(), &indexBuffer_cubemap); + device->SetName(&indexBuffer_cubemap, "Ocean::indexBuffer_cubemap"); + } + locker.unlock(); + + device->BindPipelineState(&PSO_envmap, cmd); + + OceanCB cb = GetOceanCBAtDim(params, dim); + device->BindDynamicConstantBuffer(cb, CB_GETBINDSLOT(OceanCB), cmd); + + device->BindResource(&displacementMap, 0, cmd); + device->BindResource(&gradientMap, 1, cmd); + + device->BindIndexBuffer(&indexBuffer_cubemap, IndexBufferFormat::UINT16, 0, cmd); + + device->DrawIndexedInstanced(index_count, 6, 0, 0, 0, cmd); // 6 instance for each cube side + + device->EventEnd(cmd); + } + void Ocean::Render(const CameraComponent& camera, CommandList cmd) const { GraphicsDevice* device = wi::graphics::GetDevice(); @@ -605,4 +667,11 @@ namespace wi return &gradientMap; } + const wi::primitive::AABB Ocean::GetAABB(const XMFLOAT3& camera_pos) const + { + wi::primitive::AABB aabb; + aabb.createFromHalfWidth(XMFLOAT3(camera_pos.x, params.waterHeight, camera_pos.z), XMFLOAT3(1000, 10, 1000)); + return aabb; + } + } diff --git a/WickedEngine/wiOcean.h b/WickedEngine/wiOcean.h index 6d7d963dc..aff1625d6 100644 --- a/WickedEngine/wiOcean.h +++ b/WickedEngine/wiOcean.h @@ -4,6 +4,7 @@ #include "wiFFTGenerator.h" #include "wiScene_Decl.h" #include "wiMath.h" +#include "wiPrimitive.h" namespace wi { @@ -42,6 +43,7 @@ namespace wi void UpdateDisplacementMap(wi::graphics::CommandList cmd) const; void RenderForOcclusionTest(const wi::scene::CameraComponent& camera, wi::graphics::CommandList cmd) const; + void RenderForCubemap(wi::graphics::CommandList cmd) const; void Render(const wi::scene::CameraComponent& camera, wi::graphics::CommandList cmd) const; void CopyDisplacementMapReadback(wi::graphics::CommandList cmd) const; @@ -49,6 +51,8 @@ namespace wi const wi::graphics::Texture* getDisplacementMap() const; const wi::graphics::Texture* getGradientMap() const; + const wi::primitive::AABB GetAABB(const XMFLOAT3& camera_pos) const; + static void Initialize(); bool IsValid() const { return displacementMap.IsValid(); } @@ -97,5 +101,6 @@ namespace wi wi::graphics::GPUBuffer constantBuffer; mutable wi::graphics::GPUBuffer indexBuffer; mutable wi::graphics::GPUBuffer indexBuffer_occlusionTest; + mutable wi::graphics::GPUBuffer indexBuffer_cubemap; }; } diff --git a/WickedEngine/wiRenderPath3D.cpp b/WickedEngine/wiRenderPath3D.cpp index 1ebe5e475..c8fc34e28 100644 --- a/WickedEngine/wiRenderPath3D.cpp +++ b/WickedEngine/wiRenderPath3D.cpp @@ -1241,6 +1241,10 @@ namespace wi cmd_updatetextures = device->BeginCommandList(); cmd = cmd_updatetextures; device->WaitCommandList(cmd, cmd_prepareframe_async); + if (cmd_ocean.IsValid()) + { + device->WaitCommandList(cmd, cmd_ocean); + } wi::jobsystem::Execute(ctx, [cmd, this](wi::jobsystem::JobArgs args) { wi::renderer::BindCommonResources(cmd); wi::renderer::BindCameraCB( diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 180855736..f0a780798 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -1055,8 +1055,6 @@ void LoadShaders() wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_POSTPROCESS_MOTIONBLUR_CHEAP], "motionblurCS_cheap.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_POSTPROCESS_BLOOMSEPARATE], "bloomseparateCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_POSTPROCESS_AERIALPERSPECTIVE], "aerialPerspectiveCS.cso"); }); - wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_POSTPROCESS_AERIALPERSPECTIVE_CAPTURE], "aerialPerspectiveCS_capture.cso"); }); - wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_POSTPROCESS_AERIALPERSPECTIVE_CAPTURE_MSAA], "aerialPerspectiveCS_capture_MSAA.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_SHAPENOISE], "volumetricCloud_shapenoiseCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_DETAILNOISE], "volumetricCloud_detailnoiseCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_CURLNOISE], "volumetricCloud_curlnoiseCS.cso"); }); @@ -3070,7 +3068,7 @@ inline void CreateCubemapCameras(const XMFLOAT3& position, float zNearP, float z shcams[5].init(position, XMFLOAT4(0, 0.707f, 0.707f, 0), zNearP, zFarP, XM_PIDIV2); //-z } -ForwardEntityMaskCB ForwardEntityCullingCPU(const Visibility& vis, const AABB& batch_aabb, RENDERPASS renderPass) +ForwardEntityMaskCB ForwardEntityCullingCPU(const Visibility& vis, const AABB& batch_aabb) { // Performs CPU light culling for a renderable batch: // Similar to GPU-based tiled light culling, but this is only for simple forward passes (drawcall-granularity) @@ -3107,17 +3105,14 @@ ForwardEntityMaskCB ForwardEntityCullingCPU(const Visibility& vis, const AABB& b } } - if (renderPass != RENDERPASS_ENVMAPCAPTURE) + for (size_t i = 0; i < std::min(size_t(32), vis.visibleEnvProbes.size()); ++i) { - for (size_t i = 0; i < std::min(size_t(32), vis.visibleEnvProbes.size()); ++i) + const uint32_t probeIndex = vis.visibleEnvProbes[vis.visibleEnvProbes.size() - 1 - i]; // note: reverse order, for correct blending! + const AABB& probe_aabb = vis.scene->aabb_probes[probeIndex]; + if (probe_aabb.intersects(batch_aabb)) { - const uint32_t probeIndex = vis.visibleEnvProbes[vis.visibleEnvProbes.size() - 1 - i]; // note: reverse order, for correct blending! - const AABB& probe_aabb = vis.scene->aabb_probes[probeIndex]; - if (probe_aabb.intersects(batch_aabb)) - { - const uint8_t bucket_place = uint8_t(i % 32); - cb.xForwardEnvProbeMask |= 1 << bucket_place; - } + const uint8_t bucket_place = uint8_t(i % 32); + cb.xForwardEnvProbeMask |= 1 << bucket_place; } } @@ -3244,7 +3239,7 @@ void RenderMeshes( if (forwardLightmaskRequest) { - ForwardEntityMaskCB cb = ForwardEntityCullingCPU(vis, instancedBatch.aabb, renderPass); + ForwardEntityMaskCB cb = ForwardEntityCullingCPU(vis, instancedBatch.aabb); device->BindDynamicConstantBuffer(cb, CB_GETBINDSLOT(ForwardEntityMaskCB), cmd); } @@ -9109,12 +9104,9 @@ void RefreshEnvProbes(const Visibility& vis, CommandList cmd) desc.mip_levels = 1; desc.bind_flags = BindFlag::DEPTH_STENCIL | BindFlag::SHADER_RESOURCE; desc.format = format_depthbuffer_envprobe; - desc.layout = ResourceState::SHADER_RESOURCE; + desc.layout = ResourceState::DEPTHSTENCIL; desc.sample_count = required_sample_count; - if (required_sample_count == 1) - { - desc.misc_flags = ResourceMiscFlag::TEXTURECUBE; - } + desc.misc_flags = ResourceMiscFlag::TRANSIENT_ATTACHMENT; device->CreateTexture(&desc, nullptr, &envrenderingDepthBuffer); device->SetName(&envrenderingDepthBuffer, "envrenderingDepthBuffer"); render_textures[id_depth.raw] = envrenderingDepthBuffer; @@ -9249,10 +9241,7 @@ void RefreshEnvProbes(const Visibility& vis, CommandList cmd) RenderPassImage::DepthStencil( &envrenderingDepthBuffer, RenderPassImage::LoadOp::CLEAR, - RenderPassImage::StoreOp::STORE, - ResourceState::SHADER_RESOURCE, - ResourceState::DEPTHSTENCIL, - ResourceState::SHADER_RESOURCE + RenderPassImage::StoreOp::DONTCARE ), }; device->RenderPassBegin(rp, arraysize(rp), cmd); @@ -9260,21 +9249,18 @@ void RefreshEnvProbes(const Visibility& vis, CommandList cmd) else { const RenderPassImage rp[] = { - RenderPassImage::DepthStencil( - &envrenderingDepthBuffer, - RenderPassImage::LoadOp::CLEAR, - RenderPassImage::StoreOp::STORE, - ResourceState::SHADER_RESOURCE, - ResourceState::DEPTHSTENCIL, - ResourceState::SHADER_RESOURCE - ), RenderPassImage::RenderTarget( &envrenderingColorBuffer, RenderPassImage::LoadOp::CLEAR, RenderPassImage::StoreOp::STORE, ResourceState::SHADER_RESOURCE, ResourceState::SHADER_RESOURCE - ) + ), + RenderPassImage::DepthStencil( + &envrenderingDepthBuffer, + RenderPassImage::LoadOp::CLEAR, + RenderPassImage::StoreOp::DONTCARE + ), }; device->RenderPassBegin(rp, arraysize(rp), cmd); } @@ -9333,6 +9319,14 @@ void RefreshEnvProbes(const Visibility& vis, CommandList cmd) device->DrawInstanced(240, 6, 0, 0, cmd); // 6 instances so it will be replicated for every cubemap face } + if (vis.scene->ocean.IsValid() && vis.scene->weather.IsOceanEnabled()) + { + ForwardEntityMaskCB cb = ForwardEntityCullingCPU(vis, vis.scene->ocean.GetAABB(probe.position)); + device->BindDynamicConstantBuffer(cb, CB_GETBINDSLOT(ForwardEntityMaskCB), cmd); + + vis.scene->ocean.RenderForCubemap(cmd); + } + if (probe_aabb.layerMask & vis.layerMask) // only draw light visualizers if this is a hand placed probe { DrawLightVisualizers(vis, cmd, 6); // 6 instances so it will be replicated for every cubemap face @@ -9340,47 +9334,6 @@ void RefreshEnvProbes(const Visibility& vis, CommandList cmd) device->RenderPassEnd(cmd); - // Compute Aerial Perspective for environment map - if (vis.scene->weather.IsRealisticSky() && vis.scene->weather.IsRealisticSkyAerialPerspective() && (probe_aabb.layerMask & vis.layerMask)) - { - if (probe.IsMSAA()) - { - device->EventBegin("Aerial Perspective Capture [MSAA]", cmd); - device->BindComputeShader(&shaders[CSTYPE_POSTPROCESS_AERIALPERSPECTIVE_CAPTURE_MSAA], cmd); - } - else - { - device->EventBegin("Aerial Perspective Capture", cmd); - device->BindComputeShader(&shaders[CSTYPE_POSTPROCESS_AERIALPERSPECTIVE_CAPTURE], cmd); - } - - device->BindResource(&envrenderingDepthBuffer, 0, cmd); - - TextureDesc desc = envrenderingColorBuffer.GetDesc(); - - AerialPerspectiveCapturePushConstants push = {}; - push.resolution.x = desc.width; - push.resolution.y = desc.height; - push.resolution_rcp.x = 1.0f / push.resolution.x; - push.resolution_rcp.y = 1.0f / push.resolution.y; - push.texture_output = device->GetDescriptorIndex(&envrenderingColorBuffer, SubresourceType::UAV); - - device->PushConstants(&push, sizeof(push), cmd); - - device->Barrier(GPUBarrier::Image(&envrenderingColorBuffer, ResourceState::SHADER_RESOURCE, ResourceState::UNORDERED_ACCESS), cmd); - - device->Dispatch( - (desc.width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, - (desc.height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, - 6, - cmd - ); - - device->Barrier(GPUBarrier::Image(&envrenderingColorBuffer, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), cmd); - - device->EventEnd(cmd); - } - GenerateMipChain(envrenderingColorBuffer, MIPGENFILTER_LINEAR, cmd); // Filter the enviroment map mip chain according to BRDF: diff --git a/WickedEngine/wiScene_Components.cpp b/WickedEngine/wiScene_Components.cpp index 76c61df26..1dd80e5dc 100644 --- a/WickedEngine/wiScene_Components.cpp +++ b/WickedEngine/wiScene_Components.cpp @@ -2313,7 +2313,7 @@ namespace wi::scene desc.mip_levels = GetMipCount(resolution, resolution, 1, 16); desc.misc_flags = ResourceMiscFlag::TEXTURECUBE; desc.layout = ResourceState::SHADER_RESOURCE; - device->CreateTexture(&desc, nullptr, &texture); + device->CreateTextureZeroed(&desc, &texture); device->SetName(&texture, "EnvironmentProbeComponent::texture"); subresource = -1; } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 5413dded8..b04543ab5 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 = 72; // minor bug fixes, alterations, refactors, updates - const int revision = 40; + const int revision = 41; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);