envprobe: ocean and recursive reflection support (#1556)

This commit is contained in:
Turánszki János
2026-02-17 16:59:51 +00:00
committed by GitHub
parent 9df332114f
commit b37b99f637
22 changed files with 198 additions and 182 deletions
+2 -3
View File
@@ -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<ShaderEntry> 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<ShaderEntry> 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 },
@@ -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 = {};
+1 -2
View File
@@ -345,6 +345,7 @@
<FxCompile Include="$(MSBuildThisFileDirectory)objectPS_prepass_depthonly_alphatest.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)oceanSurfacePS_envmap.hlsl" />
<FxCompile Include="$(MSBuildThisFileDirectory)paintdecalPS.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
</FxCompile>
@@ -738,8 +739,6 @@
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Compute</ShaderType>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)aerialPerspectiveCS.hlsl" />
<FxCompile Include="$(MSBuildThisFileDirectory)aerialPerspectiveCS_capture.hlsl" />
<FxCompile Include="$(MSBuildThisFileDirectory)aerialPerspectiveCS_capture_MSAA.hlsl" />
<FxCompile Include="$(MSBuildThisFileDirectory)skyAtmosphere_cameraVolumeLutCS.hlsl" />
<FxCompile Include="$(MSBuildThisFileDirectory)skyAtmosphere_skyLuminanceLutCS.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compute</ShaderType>
@@ -977,12 +977,6 @@
<FxCompile Include="$(MSBuildThisFileDirectory)skyAtmosphere_cameraVolumeLutCS.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)aerialPerspectiveCS_capture.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)aerialPerspectiveCS_capture_MSAA.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)windCS.hlsl">
<Filter>CS</Filter>
</FxCompile>
@@ -1139,6 +1133,9 @@
<FxCompile Include="$(MSBuildThisFileDirectory)voxelgridVS.hlsl">
<Filter>VS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)oceanSurfacePS_envmap.hlsl">
<Filter>PS</Filter>
</FxCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop.h">
@@ -1,2 +0,0 @@
#define AERIALPERSPECTIVE_CAPTURE
#include "aerialPerspectiveCS.hlsl"
@@ -1,2 +0,0 @@
#define MSAA
#include "aerialPerspectiveCS_capture.hlsl"
-28
View File
@@ -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;
}
+6 -6
View File
@@ -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);
+5 -4
View File
@@ -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!
}
};
+45 -36
View File
@@ -14,9 +14,10 @@ Texture2D<float4> 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);
@@ -0,0 +1,3 @@
#define ENVMAPRENDERING
#define FORWARD
#include "oceanSurfacePS.hlsl"
+10 -6
View File
@@ -3,9 +3,13 @@
Texture2D<float4> 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;
-4
View File
@@ -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:
-6
View File
@@ -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;
}
-2
View File
@@ -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,
+16
View File
@@ -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<uint8_t> texturedata(ComputeTextureMemorySizeInBytes(*desc));
std::fill(texturedata.begin(), texturedata.end(), value);
wi::vector<SubresourceData> 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)
{
+70 -1
View File
@@ -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<uint16_t> 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;
}
}
+5
View File
@@ -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;
};
}
+4
View File
@@ -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(
+25 -72
View File
@@ -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:
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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);