From 39d73dabcfe3f41d6870e5ce64164c903235260b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Thu, 23 Apr 2026 17:16:18 +0200 Subject: [PATCH] improvement for the transition between underwater and air --- WickedEngine/shaders/oceanSurfaceHF.hlsli | 2 ++ WickedEngine/shaders/oceanSurfacePS.hlsl | 5 +++ WickedEngine/shaders/underwaterCS.hlsl | 41 ++++++++++++++++++----- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/WickedEngine/shaders/oceanSurfaceHF.hlsli b/WickedEngine/shaders/oceanSurfaceHF.hlsli index 697399acb..d80a774dd 100644 --- a/WickedEngine/shaders/oceanSurfaceHF.hlsli +++ b/WickedEngine/shaders/oceanSurfaceHF.hlsli @@ -3,6 +3,8 @@ #include "globals.hlsli" #include "ShaderInterop_Ocean.h" +static const float OCEAN_NEARPLANE_CUTOFF = 0.1; + struct PSIn { float4 pos : SV_POSITION; diff --git a/WickedEngine/shaders/oceanSurfacePS.hlsl b/WickedEngine/shaders/oceanSurfacePS.hlsl index a951a2571..55e0923c3 100644 --- a/WickedEngine/shaders/oceanSurfacePS.hlsl +++ b/WickedEngine/shaders/oceanSurfacePS.hlsl @@ -18,6 +18,11 @@ float4 main(PSIn input) : SV_TARGET float lineardepth = camera.IsOrtho() ? ((1 - input.pos.z) * camera.z_far) : input.pos.w; half4 color = xOceanWaterColor; float2 ScreenCoord = input.pos.xy * camera.internal_resolution_rcp; + + float4 pos2D = mul(camera.view_projection, float4(input.GetPos3D(), 1)); + pos2D.xyz /= pos2D.w; + if (pos2D.z > OCEAN_NEARPLANE_CUTOFF) + discard; float3 V = input.GetViewVector(); float dist = length(V); diff --git a/WickedEngine/shaders/underwaterCS.hlsl b/WickedEngine/shaders/underwaterCS.hlsl index e840e6011..dd7a95d79 100644 --- a/WickedEngine/shaders/underwaterCS.hlsl +++ b/WickedEngine/shaders/underwaterCS.hlsl @@ -4,6 +4,7 @@ #include "lightingHF.hlsli" #include "fogHF.hlsli" +#define INTERSECTION_DISTORT #define LENS_DISTORT //#define ANIMATED_DISTORT @@ -52,7 +53,7 @@ void main(uint3 DTid : SV_DispatchThreadID) float2 uv = (DTid.xy + 0.5f) * postprocess.resolution_rcp; // Unproject near plane and determine for every pixel if it's below water surface: - float4 clipspace = float4(uv_to_clipspace(uv), 0.1, 1); // push further away from near plane + float4 clipspace = float4(uv_to_clipspace(uv), OCEAN_NEARPLANE_CUTOFF, 1); // push further away from near plane float4 unproj = mul(GetCamera().inverse_view_projection, clipspace); unproj.xyz /= unproj.w; float3 world_pos = unproj.xyz; @@ -67,9 +68,34 @@ void main(uint3 DTid : SV_DispatchThreadID) ocean_pos += displacement; } +#ifdef INTERSECTION_DISTORT + // Distort at intersection: + float intersection_direction = world_pos.y - ocean_pos.y; + float intersection_distance = abs(intersection_direction); + float intersection_blend = saturate(exp(-intersection_distance * 50)); + clipspace.xy *= lerp(1, 0.5, intersection_blend); + uv = clipspace_to_uv(clipspace.xy); + //color.rgb = lerp(color.rgb, ocean.water_color.rgb, intersection_blend); + + // Recompute ray after distortion: + unproj = mul(GetCamera().inverse_view_projection, clipspace); + unproj.xyz /= unproj.w; + world_pos = unproj.xyz; + ocean_pos = float3(world_pos.x, ocean.water_height, world_pos.z); + [branch] + if (ocean.texture_displacementmap >= 0) + { + const float2 ocean_uv = ocean_pos.xz * ocean.patch_size_rcp; + Texture2D texture_displacementmap = bindless_textures[descriptor_index(ocean.texture_displacementmap)]; + const float3 displacement = texture_displacementmap.SampleLevel(sampler_linear_wrap, ocean_uv, 0).xzy; + ocean_pos += displacement; + } +#endif // INTERSECTION_DISTORT + float4 original_color = input.SampleLevel(sampler_linear_clamp, uv, 0); float4 color = original_color; - if (world_pos.y < ocean_pos.y) // if below water surface, apply effects + + // Apply effects on full screen: { #ifdef LENS_DISTORT @@ -85,7 +111,7 @@ void main(uint3 DTid : SV_DispatchThreadID) color = input.SampleLevel(sampler_linear_mirror, uv, 0); - const float depth = texture_depth.SampleLevel(sampler_point_clamp, uv, 0); + const float depth = texture_depth.SampleLevel(sampler_linear_clamp, uv, 0); float3 surface_position = reconstruct_position(uv, depth); float4 clipspace2 = float4(uv_to_clipspace(uv), 1, 1); // exact near plane @@ -157,12 +183,9 @@ void main(uint3 DTid : SV_DispatchThreadID) //color = float4(1, 0, 0, 1); } - // Transition at intersection: - float intersection_direction = world_pos.y - ocean_pos.y; - float intersection_distance = abs(intersection_direction); - float intersection_blend = saturate(exp(-intersection_distance * 100)); - float3 intersection_color = ocean.water_color.rgb; - color.rgb = lerp(color.rgb, original_color, intersection_blend); + // Constrain the effect smoothly just below the water line: + color = lerp(color, original_color, smoothstep(0.0, 0.025, saturate(world_pos.y - ocean_pos.y - 0.01))); + //color = smoothstep(0.0, 0.05, saturate(intersection_direction)); output[DTid.xy] = color; }