Skip to content

Commit

Permalink
ocean improvements: extinction, scattering, volumetric light fix
Browse files Browse the repository at this point in the history
  • Loading branch information
turanszkij committed Jul 9, 2024
1 parent ec8d7af commit 62bcee6
Show file tree
Hide file tree
Showing 27 changed files with 232 additions and 116 deletions.
7 changes: 7 additions & 0 deletions Editor/MaterialWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ void MaterialWindow::Create(EditorComponent* _editor)
colorComboBox.AddItem("Emissive color");
colorComboBox.AddItem("Subsurface color");
colorComboBox.AddItem("Sheen color");
colorComboBox.AddItem("Extinction color");
colorComboBox.SetTooltip("Choose the destination data of the color picker.");
AddWidget(&colorComboBox);

Expand Down Expand Up @@ -550,6 +551,9 @@ void MaterialWindow::Create(EditorComponent* _editor)
case 4:
material->SetSheenColor(args.color.toFloat3());
break;
case 5:
material->SetExtinctionColor(args.color.toFloat4());
break;
}
}
});
Expand Down Expand Up @@ -874,6 +878,9 @@ void MaterialWindow::SetEntity(Entity entity)
case 4:
colorPicker.SetPickColor(wi::Color::fromFloat3(XMFLOAT3(material->sheenColor.x, material->sheenColor.y, material->sheenColor.z)));
break;
case 5:
colorPicker.SetPickColor(wi::Color::fromFloat4(material->extinctionColor));
break;
}

sheenRoughnessSlider.SetEnabled(false);
Expand Down
23 changes: 15 additions & 8 deletions Editor/WeatherWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ void WeatherWindow::Create(EditorComponent* _editor)
colorComboBox.AddItem("Horizon color");
colorComboBox.AddItem("Zenith color");
colorComboBox.AddItem("Ocean color");
colorComboBox.AddItem("Ocean extinction");
colorComboBox.AddItem("Cloud color 1");
colorComboBox.AddItem("Cloud color 2");
colorComboBox.AddItem("Cloud extinction 1");
Expand Down Expand Up @@ -88,18 +89,21 @@ void WeatherWindow::Create(EditorComponent* _editor)
weather.oceanParameters.waterColor = args.color.toFloat4();
break;
case 4:
weather.volumetricCloudParameters.layerFirst.albedo = args.color.toFloat3();
weather.oceanParameters.extinctionColor = args.color.toFloat4();
break;
case 5:
weather.volumetricCloudParameters.layerSecond.albedo = args.color.toFloat3();
weather.volumetricCloudParameters.layerFirst.albedo = args.color.toFloat3();
break;
case 6:
weather.volumetricCloudParameters.layerFirst.extinctionCoefficient = args.color.toFloat3();
weather.volumetricCloudParameters.layerSecond.albedo = args.color.toFloat3();
break;
case 7:
weather.volumetricCloudParameters.layerSecond.extinctionCoefficient = args.color.toFloat3();
weather.volumetricCloudParameters.layerFirst.extinctionCoefficient = args.color.toFloat3();
break;
case 8:
weather.volumetricCloudParameters.layerSecond.extinctionCoefficient = args.color.toFloat3();
break;
case 9:
weather.rain_color = args.color.toFloat4();
break;
}
Expand Down Expand Up @@ -1093,18 +1097,21 @@ void WeatherWindow::Update()
colorPicker.SetPickColor(wi::Color::fromFloat4(weather.oceanParameters.waterColor));
break;
case 4:
colorPicker.SetPickColor(wi::Color::fromFloat3(weather.volumetricCloudParameters.layerFirst.albedo));
colorPicker.SetPickColor(wi::Color::fromFloat4(weather.oceanParameters.extinctionColor));
break;
case 5:
colorPicker.SetPickColor(wi::Color::fromFloat3(weather.volumetricCloudParameters.layerSecond.albedo));
colorPicker.SetPickColor(wi::Color::fromFloat3(weather.volumetricCloudParameters.layerFirst.albedo));
break;
case 6:
colorPicker.SetPickColor(wi::Color::fromFloat3(weather.volumetricCloudParameters.layerFirst.extinctionCoefficient));
colorPicker.SetPickColor(wi::Color::fromFloat3(weather.volumetricCloudParameters.layerSecond.albedo));
break;
case 7:
colorPicker.SetPickColor(wi::Color::fromFloat3(weather.volumetricCloudParameters.layerSecond.extinctionCoefficient));
colorPicker.SetPickColor(wi::Color::fromFloat3(weather.volumetricCloudParameters.layerFirst.extinctionCoefficient));
break;
case 8:
colorPicker.SetPickColor(wi::Color::fromFloat3(weather.volumetricCloudParameters.layerSecond.extinctionCoefficient));
break;
case 9:
colorPicker.SetPickColor(wi::Color::fromFloat4(weather.rain_color));
break;
}
Expand Down
1 change: 1 addition & 0 deletions WickedEngine/shaders/ShaderInterop_Ocean.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ CBUFFER(Ocean_Simulation_PerFrameCB, CBSLOT_OTHER_OCEAN_SIMULATION_PERFRAME)
CBUFFER(Ocean_RenderCB, CBSLOT_OTHER_OCEAN_RENDER)
{
float4 xOceanWaterColor;
float4 xOceanExtinctionColor;
float4 xOceanScreenSpaceParams;

float xOceanTexelLength;
Expand Down
3 changes: 3 additions & 0 deletions WickedEngine/shaders/ShaderInterop_Weather.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,10 +341,13 @@ struct ShaderWind
struct ShaderOcean
{
float4 water_color;
float4 extinction_color;
float water_height;
float patch_size_rcp;
int texture_displacementmap;
int texture_gradientmap;

bool IsValid() { return texture_displacementmap >= 0; }
};

struct ShaderWeather
Expand Down
10 changes: 10 additions & 0 deletions WickedEngine/shaders/globals.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,16 @@ inline float GetTimePrev() { return GetFrame().time_previous; }
inline uint2 GetTemporalAASampleRotation() { return uint2((GetFrame().temporalaa_samplerotation >> 0u) & 0x000000FF, (GetFrame().temporalaa_samplerotation >> 8) & 0x000000FF); }
inline bool IsStaticSky() { return GetScene().globalenvmap >= 0; }

// Mie scaterring approximated with Henyey-Greenstein phase function.
// https://www.alexandre-pestana.com/volumetric-lights/
#define G_SCATTERING 0.66
float ComputeScattering(float lightDotView)
{
float result = 1.0f - G_SCATTERING * G_SCATTERING;
result /= (4.0f * PI * pow(1.0f + G_SCATTERING * G_SCATTERING - (2.0f * G_SCATTERING) * lightDotView, 1.5f));
return result;
}

inline float3 tonemap(float3 x)
{
return x / (x + 1); // Reinhard tonemap
Expand Down
7 changes: 6 additions & 1 deletion WickedEngine/shaders/lightingHF.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,12 @@ inline void light_directional(in ShaderEntity light, in Surface surface, inout L
lighting.direct.diffuse = mad(light_color, BRDF_GetDiffuse(surface, surface_to_light), lighting.direct.diffuse);
lighting.direct.specular = mad(light_color, BRDF_GetSpecular(surface, surface_to_light), lighting.direct.specular);

#ifndef WATER
#ifdef WATER
// Water extinction scattering:
const float scattering = ComputeScattering(saturate(dot(L, -surface.V)));
lighting.direct.specular += scattering * light_color * (1 - surface.extinction) * (1 - sqr(1 - saturate(1 - surface.N.y)));
#else
// On non-water surfaces there can be procedural caustic if it's under ocean:
const ShaderOcean ocean = GetWeather().ocean;
if (ocean.texture_displacementmap >= 0)
{
Expand Down
10 changes: 8 additions & 2 deletions WickedEngine/shaders/objectHF.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -828,10 +828,13 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target
#endif // OBJECTSHADER_USE_UVSETS
#endif // CLEARCOAT


surface.sss = GetMaterial().subsurfaceScattering;
surface.sss_inv = GetMaterial().subsurfaceScattering_inv;

#ifdef WATER
surface.extinction = GetMaterial().GetSheenColor().rgb; // Note: sheen color is repurposed as extinction color for water
#endif // WATER

surface.pixel = pixel;
surface.screenUV = ScreenCoord;

Expand Down Expand Up @@ -996,7 +999,10 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target
if(camera_above_water)
water_depth = -water_depth;
// Water fog computation:
surface.refraction.a = saturate(exp(-water_depth * color.a));
float waterfog = saturate(exp(-water_depth * color.a));
float3 transmittance = saturate(exp(-water_depth * surface.extinction * color.a));
surface.refraction.a = waterfog;
surface.refraction.rgb *= transmittance;
color.a = 1;
}
#endif // WATER
Expand Down
19 changes: 12 additions & 7 deletions WickedEngine/shaders/oceanSurfacePS.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ float4 main(PSIn input) : SV_TARGET
const float4 gradientNear = texture_gradientmap.Sample(sampler_aniso_wrap, input.uv);
const float4 gradientFar = texture_gradientmap.Sample(sampler_aniso_wrap, input.uv * 0.125);
float4 gradient = lerp(gradientNear, gradientFar, gradient_fade);
const float sss_amount = gradient.a;

float2 ScreenCoord = pixel * GetCamera().internal_resolution_rcp;

Expand All @@ -46,8 +45,9 @@ float4 main(PSIn input) : SV_TARGET
surface.P = input.pos3D;
surface.N = normalize(float3(gradient.x, xOceanTexelLength * 2, gradient.y));
surface.V = V;
//surface.sss = color * sss_amount;
//surface.sss_inv = 1.0f / ((1 + surface.sss) * (1 + surface.sss));
surface.sss = 1;
surface.sss_inv = 1.0f / ((1 + surface.sss) * (1 + surface.sss));
surface.extinction = xOceanExtinctionColor.rgb;
surface.update();

Lighting lighting;
Expand Down Expand Up @@ -113,13 +113,18 @@ float4 main(PSIn input) : SV_TARGET
if (camera_above_water)
water_depth = -water_depth;
// Water fog computation:
surface.refraction.a = saturate(exp(-water_depth * color.a));
float waterfog = saturate(exp(-water_depth * color.a));
float3 transmittance = saturate(exp(-water_depth * surface.extinction * color.a));
surface.refraction.a = waterfog;
surface.refraction.rgb *= transmittance;
color.a = 1;
}

#if 1
// FOAM:
float foam_shore = saturate(exp(-water_depth * 4));
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()));
Expand All @@ -129,8 +134,8 @@ float4 main(PSIn input) : SV_TARGET
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_shore;
foam += smoothstep(0.5, 0.6, foam_shore + 0.2);
foam += foam_voronoi * foam_simplex * foam_combined;
foam += smoothstep(0.5, 0.6, saturate(foam_combined + 0.2));
foam *= 2;
foam = saturate(foam);
surface.albedo = lerp(surface.albedo, 1, foam);
Expand Down
8 changes: 0 additions & 8 deletions WickedEngine/shaders/skyPS_dynamic.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,6 @@
#include "skyHF.hlsli"
#include "fogHF.hlsli"

#define G_SCATTERING 0.66
float ComputeScattering(float lightDotView)
{
float result = 1.0f - G_SCATTERING * G_SCATTERING;
result /= (4.0f * PI * pow(1.0f + G_SCATTERING * G_SCATTERING - (2.0f * G_SCATTERING) * lightDotView, 1.5f));
return result;
}

float4 main(float4 pos : SV_POSITION, float2 clipspace : TEXCOORD) : SV_TARGET
{
float4 unprojected = mul(GetCamera().inverse_view_projection, float4(clipspace, 0.0f, 1.0f));
Expand Down
2 changes: 2 additions & 0 deletions WickedEngine/shaders/surfaceHF.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ struct Surface
float3 gi;
float3 bumpColor;
float3 ssgi;
float3 extinction;

// These will be computed when calling Update():
float NdotV; // cos(angle between normal and view vector)
Expand Down Expand Up @@ -147,6 +148,7 @@ struct Surface
gi = 0;
bumpColor = 0;
ssgi = 0;
extinction = 0;

uid_validate = 0;
hit_depth = 0;
Expand Down
7 changes: 5 additions & 2 deletions WickedEngine/shaders/underwaterCS.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,11 @@ void main(uint3 DTid : SV_DispatchThreadID)
}
float water_depth = ocean_pos.y - surface_position.y;
water_depth = max(min(lineardepth, ocean_dist), water_depth);

color.rgb = lerp(ocean.water_color.rgb, color.rgb, saturate(exp(-water_depth * ocean.water_color.a)));

float waterfog = saturate(exp(-water_depth * ocean.water_color.a));
float3 transmittance = saturate(exp(-water_depth * ocean.extinction_color.rgb * ocean.water_color.a));
color.rgb *= transmittance;
color.rgb = lerp(ocean.water_color.rgb, color.rgb, waterfog);
//color = float4(1, 0, 0, 1);
}

Expand Down
10 changes: 0 additions & 10 deletions WickedEngine/shaders/volumetricLightHF.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,4 @@ struct VertexToPixel {
float4 pos2D : POSITION2D;
};

// Mie scaterring approximated with Henyey-Greenstein phase function.
// https://www.alexandre-pestana.com/volumetric-lights/
#define G_SCATTERING 0.66
float ComputeScattering(float lightDotView)
{
float result = 1.0f - G_SCATTERING * G_SCATTERING;
result /= (4.0f * PI * pow(1.0f + G_SCATTERING * G_SCATTERING - (2.0f * G_SCATTERING) * lightDotView, 1.5f));
return result;
}

#endif // WI_VOLUMETRICLIGHT_HF
22 changes: 15 additions & 7 deletions WickedEngine/shaders/volumetricLight_DirectionalPS.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,12 @@
#include "volumetricLightHF.hlsli"
#include "volumetricCloudsHF.hlsli"
#include "fogHF.hlsli"
#include "oceanSurfaceHF.hlsli"

float4 main(VertexToPixel input) : SV_TARGET
{
ShaderEntity light = load_entity(GetFrame().lightarray_offset + (uint)g_xColor.x);

if (!light.IsCastingShadow())
{
// Dirlight volume has no meaning without shadows!!
return 0;
}


float2 ScreenCoord = input.pos2D.xy / input.pos2D.w * float2(0.5f, -0.5f) + 0.5f;
float4 depths = texture_depth.GatherRed(sampler_point_clamp, ScreenCoord);
float depth = max(depths.x, max(depths.y, max(depths.z, depths.w)));
Expand All @@ -22,6 +17,19 @@ float4 main(VertexToPixel input) : SV_TARGET
float cameraDistance = length(V);
V /= cameraDistance;

// Fix for ocean: because ocean is not in linear depth, we trace it instead
const ShaderOcean ocean = GetWeather().ocean;
if(ocean.IsValid() && V.y > 0)
{
float3 ocean_surface_pos = intersectPlaneClampInfinite(GetCamera().position, V, float3(0, 1, 0), ocean.water_height);
float dist = distance(ocean_surface_pos, GetCamera().position);
if(dist < cameraDistance)
{
P = ocean_surface_pos;
cameraDistance = dist;
}
}

float marchedDistance = 0;
float3 accumulation = 0;

Expand Down
14 changes: 14 additions & 0 deletions WickedEngine/shaders/volumetricLight_PointPS.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK // fix the lack of depth testing
#include "volumetricLightHF.hlsli"
#include "fogHF.hlsli"
#include "oceanSurfaceHF.hlsli"

float4 main(VertexToPixel input) : SV_TARGET
{
Expand All @@ -15,6 +16,19 @@ float4 main(VertexToPixel input) : SV_TARGET
float cameraDistance = length(V);
V /= cameraDistance;

// Fix for ocean: because ocean is not in linear depth, we trace it instead
const ShaderOcean ocean = GetWeather().ocean;
if(ocean.IsValid() && V.y > 0)
{
float3 ocean_surface_pos = intersectPlaneClampInfinite(GetCamera().position, V, float3(0, 1, 0), ocean.water_height);
float dist = distance(ocean_surface_pos, GetCamera().position);
if(dist < cameraDistance)
{
P = ocean_surface_pos;
cameraDistance = dist;
}
}

float marchedDistance = 0;
float3 accumulation = 0;

Expand Down
14 changes: 14 additions & 0 deletions WickedEngine/shaders/volumetricLight_SpotPS.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK // fix the lack of depth testing
#include "volumetricLightHF.hlsli"
#include "fogHF.hlsli"
#include "oceanSurfaceHF.hlsli"

// https://github.com/dong-zhan/ray-tracer/blob/master/ray%20cone%20intersect.hlsl
//p: ray o
Expand Down Expand Up @@ -47,6 +48,19 @@ float4 main(VertexToPixel input) : SV_TARGET
float cameraDistance = length(V);
V /= cameraDistance;

// Fix for ocean: because ocean is not in linear depth, we trace it instead
const ShaderOcean ocean = GetWeather().ocean;
if(ocean.IsValid() && V.y > 0)
{
float3 ocean_surface_pos = intersectPlaneClampInfinite(GetCamera().position, V, float3(0, 1, 0), ocean.water_height);
float dist = distance(ocean_surface_pos, GetCamera().position);
if(dist < cameraDistance)
{
P = ocean_surface_pos;
cameraDistance = dist;
}
}

float marchedDistance = 0;
float3 accumulation = 0;

Expand Down
1 change: 1 addition & 0 deletions WickedEngine/wiGraphicsDevice_Vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4487,6 +4487,7 @@ using namespace vulkan_internal;
}

copyOffset += dst_slicepitch * depth;
copyOffset = AlignTo(copyOffset, VkDeviceSize(4)); // fix for validation: on transfer queue the srcOffset must be 4-byte aligned

width = std::max(1u, width / 2);
height = std::max(1u, height / 2);
Expand Down
Loading

0 comments on commit 62bcee6

Please sign in to comment.