From 0794a0f621b1ccd85c4d387d2db3b4e4d686b280 Mon Sep 17 00:00:00 2001 From: Wls50 Date: Wed, 10 Dec 2025 19:06:19 +0100 Subject: [PATCH] add clouds --- betterRenderer/renderer/source/config.cpp | 2 + betterRenderer/renderer/source/config.h | 2 + .../renderer/source/environment.cpp | 41 ++++++++- betterRenderer/renderer/source/environment.h | 5 + .../renderer/source/gbufferblitpass.cpp | 3 + betterRenderer/renderer/source/nvmaterial.cpp | 4 + betterRenderer/renderer/source/nvrenderer.cpp | 2 +- betterRenderer/renderer/source/sky.cpp | 91 ++++++++++--------- betterRenderer/renderer/source/sky.h | 6 +- .../shaders/gbuffer_cube_lighting.hlsl | 2 + betterRenderer/shaders/manul/clouds.hlsli | 69 ++++++++++++++ betterRenderer/shaders/manul/lighting.hlsli | 12 +++ betterRenderer/shaders/manul/sky.hlsli | 4 +- .../shaders/manul/sky_aerial_lut.hlsl | 5 +- .../shaders/manul/sky_inscattering.hlsli | 58 ++++++++++++ betterRenderer/shaders/skybox.hlsl | 2 + 16 files changed, 258 insertions(+), 50 deletions(-) create mode 100644 betterRenderer/shaders/manul/clouds.hlsli diff --git a/betterRenderer/renderer/source/config.cpp b/betterRenderer/renderer/source/config.cpp index bc067076..675fa4fb 100644 --- a/betterRenderer/renderer/source/config.cpp +++ b/betterRenderer/renderer/source/config.cpp @@ -14,6 +14,8 @@ void MaConfig::Init(const YAML::Node& node) { m_weight_lines = node["wire_diameter_lines"].as(.01f); m_weight_tractions = node["wire_diameter_tractions"].as(.005f); m_envmap_resolution = node["envmap_resolution"].as(256); + m_cloud_texture = node["cloud_texture"].as("textures/clouds/clear"); + m_high_cloud_texture = node["high_cloud_texture"].as("textures/clouds/clear"); } void MaConfig::MaConfigDisplay::Init(const YAML::Node& node) { diff --git a/betterRenderer/renderer/source/config.h b/betterRenderer/renderer/source/config.h index fee23692..51477471 100644 --- a/betterRenderer/renderer/source/config.h +++ b/betterRenderer/renderer/source/config.h @@ -38,6 +38,8 @@ struct MaConfig { float m_min_luminance_ev; float m_max_luminance_ev; } m_lighting; + std::string m_cloud_texture; + std::string m_high_cloud_texture; int m_envmap_resolution; float m_weight_lines; float m_weight_tractions; diff --git a/betterRenderer/renderer/source/environment.cpp b/betterRenderer/renderer/source/environment.cpp index 0840c37d..e665a199 100644 --- a/betterRenderer/renderer/source/environment.cpp +++ b/betterRenderer/renderer/source/environment.cpp @@ -7,6 +7,7 @@ #include "gbuffer.h" #include "nvrenderer/nvrenderer.h" #include "nvrendererbackend.h" +#include "nvtexture.h" #include "simulationenvironment.h" #include "sky.h" @@ -50,6 +51,8 @@ nvrhi::BindingSetHandle MaEnvironment::GetBindingSet(int pass, int mip, int set, Format::UNKNOWN, AllSubresources)) .addItem(BindingSetItem::Texture_SRV(13, m_sky_texture)) .addItem(BindingSetItem::Texture_SRV(14, m_aerial_lut)) + .addItem(BindingSetItem::Texture_SRV(15, m_clouds_texture)) + .addItem(BindingSetItem::Texture_SRV(16, m_high_clouds_texture)) .addItem(BindingSetItem::Texture_UAV( 0, m_dynamic_skybox[set], Format::UNKNOWN, TextureSubresourceSet( @@ -58,6 +61,7 @@ nvrhi::BindingSetHandle MaEnvironment::GetBindingSet(int pass, int mip, int set, .addItem(BindingSetItem::Sampler(0, m_sampler_linear_clamp)) .addItem(BindingSetItem::Sampler(1, m_sampler_point_clamp)) .addItem(BindingSetItem::Sampler(13, m_sampler_linear_clamp)) + .addItem(BindingSetItem::Sampler(15, m_sampler_linear_clamp)) .addItem(BindingSetItem::ConstantBuffer( 13, m_sky->m_sky_constants)) .addItem(BindingSetItem::ConstantBuffer( @@ -125,11 +129,13 @@ nvrhi::BindingSetHandle MaEnvironment::GetBindingSet(int pass, int mip, int set, MaEnvironment::MaEnvironment(NvRenderer* renderer) : MaResourceRegistry(renderer), + m_renderer(renderer), m_backend(renderer->m_backend.get()), m_gbuffer(renderer->m_gbuffer.get()), - m_sky(renderer->m_sky.get()) {} + m_sky() {} void MaEnvironment::Init(const std::string& texture, float pre_exposure) { + m_sky = m_renderer->m_sky.get(); InitResourceRegistry(); using namespace nvrhi; m_cs_sample_equirectangular = m_backend->CreateShader( @@ -174,10 +180,13 @@ void MaEnvironment::Init(const std::string& texture, float pre_exposure) { .addItem(BindingLayoutItem::Texture_SRV(5)) .addItem(BindingLayoutItem::Texture_SRV(13)) .addItem(BindingLayoutItem::Texture_SRV(14)) + .addItem(BindingLayoutItem::Texture_SRV(15)) + .addItem(BindingLayoutItem::Texture_SRV(16)) .addItem(BindingLayoutItem::Texture_UAV(0)) .addItem(BindingLayoutItem::Sampler(0)) .addItem(BindingLayoutItem::Sampler(1)) .addItem(BindingLayoutItem::Sampler(13)) + .addItem(BindingLayoutItem::Sampler(15)) .addItem(BindingLayoutItem::VolatileConstantBuffer(13)) .addItem(BindingLayoutItem::ConstantBuffer(1)) .addItem(BindingLayoutItem::PushConstants( @@ -305,6 +314,25 @@ void MaEnvironment::Init(const std::string& texture, float pre_exposure) { RegisterResource(true, "sampler_linear_clamp_v_repeat_h", m_sampler_linear_clamp_v_repeat_h, ResourceType::Sampler); + { + size_t texture_handle_clouds = + m_renderer->GetTextureManager()->FetchTexture( + NvRenderer::Config()->m_cloud_texture, GL_RGBA, 0, false); + size_t texture_handle_high_clouds = + m_renderer->GetTextureManager()->FetchTexture( + NvRenderer::Config()->m_high_cloud_texture, GL_R, 0, false); + nvrhi::CommandListHandle command_list = + m_backend->GetDevice()->createCommandList(); + command_list->open(); + m_clouds_texture = m_renderer->GetTextureManager()->GetRhiTexture( + texture_handle_clouds, command_list); + m_high_clouds_texture = m_renderer->GetTextureManager()->GetRhiTexture( + texture_handle_high_clouds, command_list); + + command_list->close(); + m_backend->GetDevice()->executeCommandList(command_list); + } + { m_brdf_lut = m_backend->GetDevice()->createTexture( TextureDesc() @@ -412,6 +440,9 @@ void MaEnvironment::Init(const std::string& texture, float pre_exposure) { ResourceType::Texture_SRV); } + RegisterResource(true, "sky_clouds", m_clouds_texture, + nvrhi::ResourceType::Texture_SRV); + m_sky_texture = m_backend->GetDevice()->createTexture( TextureDesc(m_sky->m_aerial_lut->m_sky_texture->getDesc()) .setDebugName("Envmap Sky Texture")); @@ -870,13 +901,17 @@ void EnvironmentRenderPass::Init() { .setVisibility(nvrhi::ShaderType::Pixel) .addItem(nvrhi::BindingLayoutItem::Texture_SRV(0)) .addItem(nvrhi::BindingLayoutItem::Texture_SRV(13)) + .addItem(nvrhi::BindingLayoutItem::Texture_SRV(15)) + .addItem(nvrhi::BindingLayoutItem::Texture_SRV(16)) .addItem(nvrhi::BindingLayoutItem::Sampler(0)) .addItem(nvrhi::BindingLayoutItem::Sampler(13)) + .addItem(nvrhi::BindingLayoutItem::Sampler(15)) .addItem(nvrhi::BindingLayoutItem::VolatileConstantBuffer(0))); auto sampler = m_backend->GetDevice()->createSampler( nvrhi::SamplerDesc() .setAllAddressModes(nvrhi::SamplerAddressMode::Clamp) .setAllFilters(true)); + for (int i = 0; i < 2; ++i) { m_binding_set[i] = m_backend->GetDevice()->createBindingSet( nvrhi::BindingSetDesc() @@ -884,10 +919,14 @@ void EnvironmentRenderPass::Init() { nvrhi::BindingSetItem::Texture_SRV(0, m_environment->m_skybox)) .addItem(nvrhi::BindingSetItem::Texture_SRV( 13, m_environment->m_sky->m_aerial_lut->m_sky_texture)) + .addItem(nvrhi::BindingSetItem::Texture_SRV(15, m_environment->m_clouds_texture)) + .addItem(nvrhi::BindingSetItem::Texture_SRV(16, m_environment->m_high_clouds_texture)) .addItem(nvrhi::BindingSetItem::Sampler( 0, m_environment->m_sampler_linear_clamp)) .addItem(nvrhi::BindingSetItem::Sampler( 13, m_environment->m_sampler_linear_clamp_v_repeat_h)) + .addItem(nvrhi::BindingSetItem::Sampler( + 15, m_environment->m_sampler_linear_clamp)) .addItem(nvrhi::BindingSetItem::ConstantBuffer( 0, m_environment_constants)), m_binding_layout); diff --git a/betterRenderer/renderer/source/environment.h b/betterRenderer/renderer/source/environment.h index 7a3637b1..920e5952 100644 --- a/betterRenderer/renderer/source/environment.h +++ b/betterRenderer/renderer/source/environment.h @@ -15,6 +15,8 @@ struct MaEnvironment : public MaResourceRegistry { nvrhi::TextureHandle m_brdf_lut; nvrhi::TextureHandle m_sky_texture; nvrhi::TextureHandle m_aerial_lut; + nvrhi::TextureHandle m_clouds_texture; + nvrhi::TextureHandle m_high_clouds_texture; nvrhi::SamplerHandle m_sampler_linear_clamp_v_repeat_h; nvrhi::SamplerHandle m_sampler_linear_clamp; @@ -45,6 +47,7 @@ struct MaEnvironment : public MaResourceRegistry { nvrhi::BufferHandle m_face_inverse_projection_buffer; + class NvRenderer* m_renderer; class NvRendererBackend* m_backend; struct NvGbuffer* m_gbuffer; struct Sky* m_sky; @@ -107,6 +110,8 @@ struct MaEnvironment : public MaResourceRegistry { struct EnvironmentRenderPass : public FullScreenPass { EnvironmentRenderPass(MaEnvironment* environment); + size_t m_texture_handle_clouds; + struct EnvironmentConstants { glm::mat4 m_inverse_view_projection; glm::mat4 m_reproject_matrix; diff --git a/betterRenderer/renderer/source/gbufferblitpass.cpp b/betterRenderer/renderer/source/gbufferblitpass.cpp index 42898ec5..97123f91 100644 --- a/betterRenderer/renderer/source/gbufferblitpass.cpp +++ b/betterRenderer/renderer/source/gbufferblitpass.cpp @@ -110,6 +110,7 @@ void GbufferBlitPass::Init() { .addItem(nvrhi::BindingLayoutItem::Texture_SRV(11)) .addItem(nvrhi::BindingLayoutItem::Texture_SRV(12)) .addItem(nvrhi::BindingLayoutItem::Texture_SRV(14)) + .addItem(nvrhi::BindingLayoutItem::Texture_SRV(15)) .addItem(nvrhi::BindingLayoutItem::Texture_SRV(16)) .addItem(nvrhi::BindingLayoutItem::StructuredBuffer_SRV(17)) .addItem(nvrhi::BindingLayoutItem::StructuredBuffer_SRV(18)) @@ -147,6 +148,8 @@ void GbufferBlitPass::Init() { 12, m_contact_shadows->m_output_texture)) .addItem(nvrhi::BindingSetItem::Texture_SRV( 14, m_sky->m_aerial_lut->m_lut)) + .addItem(nvrhi::BindingSetItem::Texture_SRV( + 15, m_environment->m_clouds_texture)) .addItem(nvrhi::BindingSetItem::Texture_SRV( 16, static_cast( GetResource("forwardplus_index_grid_opaque", nvrhi::ResourceType::Texture_SRV) diff --git a/betterRenderer/renderer/source/nvmaterial.cpp b/betterRenderer/renderer/source/nvmaterial.cpp index 434b3a06..6afe4428 100644 --- a/betterRenderer/renderer/source/nvmaterial.cpp +++ b/betterRenderer/renderer/source/nvmaterial.cpp @@ -244,6 +244,7 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) { .Add(MaResourceMapping::Texture_SRV(12, "gbuffer_depth")) .Add(MaResourceMapping::Texture_SRV(13, "scene_lit_texture_copy")) .Add(MaResourceMapping::Texture_SRV(14, "sky_aerial_lut")) + .Add(MaResourceMapping::Texture_SRV(15, "sky_clouds")) .Add(MaResourceMapping::Texture_SRV( 16, "forwardplus_index_grid_transparent")) .Add(MaResourceMapping::StructuredBuffer_SRV( @@ -423,6 +424,7 @@ bool NvRenderer::InitMaterials() { .addItem(nvrhi::BindingLayoutItem::Texture_SRV(11)) .addItem(nvrhi::BindingLayoutItem::Texture_SRV(12)) .addItem(nvrhi::BindingLayoutItem::Texture_SRV(14)) + .addItem(nvrhi::BindingLayoutItem::Texture_SRV(15)) .addItem(nvrhi::BindingLayoutItem::Sampler(8)) .addItem(nvrhi::BindingLayoutItem::Sampler(11)) .addItem(nvrhi::BindingLayoutItem::Sampler(13))); @@ -445,6 +447,8 @@ bool NvRenderer::InitMaterials() { 12, m_gbuffer->m_gbuffer_depth)) .addItem(nvrhi::BindingSetItem::Texture_SRV( 14, m_sky->m_aerial_lut->m_lut)) + .addItem(nvrhi::BindingSetItem::Texture_SRV( + 15, m_environment->m_clouds_texture)) .addItem(nvrhi::BindingSetItem::Sampler( 8, m_backend->GetDevice()->createSampler( nvrhi::SamplerDesc().setAllFilters(true)))) diff --git a/betterRenderer/renderer/source/nvrenderer.cpp b/betterRenderer/renderer/source/nvrenderer.cpp index 24531b31..9156ab08 100644 --- a/betterRenderer/renderer/source/nvrenderer.cpp +++ b/betterRenderer/renderer/source/nvrenderer.cpp @@ -82,8 +82,8 @@ bool NvRenderer::Init(GLFWwindow *Window) { m_gbuffer_shadow = std::make_shared(this); m_contact_shadows = std::make_shared(this, m_gbuffer.get()); m_shadow_map = std::make_shared(this); - m_sky = std::make_shared(this); m_environment = std::make_shared(this); + m_sky = std::make_shared(this, m_environment.get()); m_ssao = std::make_shared(this); m_gbuffer_lighting = std::make_shared(this); m_gbuffer_blit = std::make_shared( diff --git a/betterRenderer/renderer/source/sky.cpp b/betterRenderer/renderer/source/sky.cpp index 8619b0b0..a833656a 100644 --- a/betterRenderer/renderer/source/sky.cpp +++ b/betterRenderer/renderer/source/sky.cpp @@ -2,6 +2,7 @@ #include +#include "environment.h" #include "nvrendererbackend.h" #include "simulationenvironment.h" #include "simulationtime.h" @@ -46,8 +47,8 @@ static const glm::mat4x3 M = { 8.572844237945445, -11.103384660054624, 117.47585277566478}; } // namespace -Sky::Sky(NvRenderer* renderer) - : m_backend(renderer->GetBackend()), MaResourceRegistry(renderer) { +Sky::Sky(NvRenderer* renderer, MaEnvironment *environment) + : m_backend(renderer->GetBackend()), MaResourceRegistry(renderer), m_environment(environment) { m_transmittance_pass = std::make_shared(this); m_aerial_lut = std::make_shared(this); } @@ -375,6 +376,7 @@ void SkyAerialLut::Init() { m_lut_width = 128; m_lut_height = 256; m_lut_slices = 16; + m_cloud_texture = m_sky->m_environment->m_clouds_texture; m_constant_buffer = m_sky->m_backend->GetDevice()->createBuffer( nvrhi::utils::CreateVolatileConstantBufferDesc( sizeof(DispatchConstants), "Sky Aerial LUT Dispatch Constants", 16)); @@ -398,51 +400,56 @@ void SkyAerialLut::Init() { .setInitialState(nvrhi::ResourceStates::Common) .setKeepInitialState(true) .setDebugName("Sky Texture")); - auto shader_lut = m_sky->m_backend->CreateShader("sky_aerial_lut", - nvrhi::ShaderType::Compute); - auto shader_sky = - m_sky->m_backend->CreateShader("sky", nvrhi::ShaderType::Compute); - auto sampler = m_sky->m_backend->GetDevice()->createSampler( - nvrhi::SamplerDesc() - .setAllAddressModes(nvrhi::SamplerAddressMode::ClampToEdge) - .setAllFilters(true)); - nvrhi::BindingLayoutHandle binding_layout_lut; - nvrhi::BindingLayoutHandle binding_layout_sky; - nvrhi::utils::CreateBindingSetAndLayout( - m_sky->m_backend->GetDevice(), nvrhi::ShaderType::Compute, 0, - nvrhi::BindingSetDesc() - .addItem(nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer)) - .addItem( - nvrhi::BindingSetItem::ConstantBuffer(13, m_sky->m_sky_constants)) - .addItem(nvrhi::BindingSetItem::Texture_UAV(0, m_lut)) - .addItem(nvrhi::BindingSetItem::Texture_SRV( - 13, m_sky->m_transmittance_pass->m_output)) - .addItem(nvrhi::BindingSetItem::Sampler(13, sampler)), - binding_layout_lut, m_bindings_lut); - nvrhi::utils::CreateBindingSetAndLayout( - m_sky->m_backend->GetDevice(), nvrhi::ShaderType::Compute, 0, - nvrhi::BindingSetDesc() - .addItem(nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer)) - .addItem( - nvrhi::BindingSetItem::ConstantBuffer(13, m_sky->m_sky_constants)) - .addItem(nvrhi::BindingSetItem::Texture_UAV(1, m_sky_texture)) - .addItem(nvrhi::BindingSetItem::Texture_SRV( - 13, m_sky->m_transmittance_pass->m_output)) - .addItem(nvrhi::BindingSetItem::Sampler(13, sampler)), - binding_layout_sky, m_bindings_sky); - m_pso_lut = m_sky->m_backend->GetDevice()->createComputePipeline( - nvrhi::ComputePipelineDesc() - .addBindingLayout(binding_layout_lut) - .setComputeShader(shader_lut)); - m_pso_sky = m_sky->m_backend->GetDevice()->createComputePipeline( - nvrhi::ComputePipelineDesc() - .addBindingLayout(binding_layout_sky) - .setComputeShader(shader_sky)); } void SkyAerialLut::Render(nvrhi::ICommandList* command_list, const glm::dmat4& projection, const glm::dmat4& view) { + if (!m_pso_sky) { + auto shader_lut = m_sky->m_backend->CreateShader( + "sky_aerial_lut", nvrhi::ShaderType::Compute); + auto shader_sky = + m_sky->m_backend->CreateShader("sky", nvrhi::ShaderType::Compute); + auto sampler = m_sky->m_backend->GetDevice()->createSampler( + nvrhi::SamplerDesc() + .setAllAddressModes(nvrhi::SamplerAddressMode::ClampToEdge) + .setAllFilters(true)); + nvrhi::BindingLayoutHandle binding_layout_lut; + nvrhi::BindingLayoutHandle binding_layout_sky; + nvrhi::utils::CreateBindingSetAndLayout( + m_sky->m_backend->GetDevice(), nvrhi::ShaderType::Compute, 0, + nvrhi::BindingSetDesc() + .addItem( + nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer)) + .addItem(nvrhi::BindingSetItem::ConstantBuffer( + 13, m_sky->m_sky_constants)) + .addItem(nvrhi::BindingSetItem::Texture_UAV(0, m_lut)) + .addItem(nvrhi::BindingSetItem::Texture_SRV( + 13, m_sky->m_transmittance_pass->m_output)) + .addItem(nvrhi::BindingSetItem::Texture_SRV(15, m_sky->m_environment->m_clouds_texture)) + .addItem(nvrhi::BindingSetItem::Sampler(13, sampler)), + binding_layout_lut, m_bindings_lut); + nvrhi::utils::CreateBindingSetAndLayout( + m_sky->m_backend->GetDevice(), nvrhi::ShaderType::Compute, 0, + nvrhi::BindingSetDesc() + .addItem( + nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer)) + .addItem(nvrhi::BindingSetItem::ConstantBuffer( + 13, m_sky->m_sky_constants)) + .addItem(nvrhi::BindingSetItem::Texture_UAV(1, m_sky_texture)) + .addItem(nvrhi::BindingSetItem::Texture_SRV( + 13, m_sky->m_transmittance_pass->m_output)) + .addItem(nvrhi::BindingSetItem::Sampler(13, sampler)), + binding_layout_sky, m_bindings_sky); + m_pso_lut = m_sky->m_backend->GetDevice()->createComputePipeline( + nvrhi::ComputePipelineDesc() + .addBindingLayout(binding_layout_lut) + .setComputeShader(shader_lut)); + m_pso_sky = m_sky->m_backend->GetDevice()->createComputePipeline( + nvrhi::ComputePipelineDesc() + .addBindingLayout(binding_layout_sky) + .setComputeShader(shader_sky)); + } { DispatchConstants constants{}; constants.g_InverseView = static_cast(glm::inverse(view)); diff --git a/betterRenderer/renderer/source/sky.h b/betterRenderer/renderer/source/sky.h index c9e9c8eb..5b21f4a4 100644 --- a/betterRenderer/renderer/source/sky.h +++ b/betterRenderer/renderer/source/sky.h @@ -4,7 +4,7 @@ #include "nvrenderer/resource_registry.h" struct Sky : public MaResourceRegistry { - Sky(class NvRenderer* renderer); + Sky(class NvRenderer* renderer, struct MaEnvironment *environment); void Init(); void Render(nvrhi::ICommandList* command_list, const glm::dmat4& projection, @@ -27,7 +27,7 @@ struct Sky : public MaResourceRegistry { Rural, Urban, Num - } m_aerosol_preset = AerosolPreset::Rural; + } m_aerosol_preset = AerosolPreset::Urban; float m_visibility = 1e4f; float m_fog_height_offset = 0.f; float m_fog_height_scale = .1f; @@ -39,6 +39,7 @@ struct Sky : public MaResourceRegistry { void ShowGui(); static const char* GetAerosolTypeDesc(AerosolPreset preset); class NvRendererBackend* m_backend; + MaEnvironment* m_environment; std::shared_ptr m_transmittance_pass; std::shared_ptr m_aerial_lut; float GetOzoneMean() const; @@ -104,6 +105,7 @@ struct SkyAerialLut { const glm::dmat4& view); nvrhi::TextureHandle m_lut; nvrhi::TextureHandle m_sky_texture; + nvrhi::TextureHandle m_cloud_texture; nvrhi::BufferHandle m_constant_buffer; nvrhi::ComputePipelineHandle m_pso_lut; nvrhi::ComputePipelineHandle m_pso_sky; diff --git a/betterRenderer/shaders/gbuffer_cube_lighting.hlsl b/betterRenderer/shaders/gbuffer_cube_lighting.hlsl index 1f37604e..1b9f2b72 100644 --- a/betterRenderer/shaders/gbuffer_cube_lighting.hlsl +++ b/betterRenderer/shaders/gbuffer_cube_lighting.hlsl @@ -18,6 +18,7 @@ SamplerState g_SamplerPointClamp : register(s1); #include "cubemap_utils.hlsli" #include "manul/sky.hlsli" +#include "manul/clouds.hlsli" struct FilterParameters { uint3 m_Offset; @@ -50,6 +51,7 @@ void main(uint3 PixCoord : SV_DispatchThreadID) { //g_OutCubemap[PixCoord + g_Offset] = g_Skybox.SampleLevel(g_SamplerLinearClamp, normal, 0.); float3 color = 1.e-7; CalcAtmosphere(color, normal, g_FilterParams.m_LightVector); + CalcClouds(color, normal, g_FilterParams.m_LightVector); //CalcAtmosphere(g_OutCubemap[PixCoord + g_Offset], 1., normal, g_LightVector, g_Altitude, SKY_INF, g_LightColor.rgb, 10); float3 normal_flipped = normal * float3(-1., 1., 1.); float depth = g_Depth.SampleLevel(g_SamplerPointClamp, normal_flipped, 0.); diff --git a/betterRenderer/shaders/manul/clouds.hlsli b/betterRenderer/shaders/manul/clouds.hlsli new file mode 100644 index 00000000..3dd664af --- /dev/null +++ b/betterRenderer/shaders/manul/clouds.hlsli @@ -0,0 +1,69 @@ +#ifndef CLOUDS_HLSLI +#define CLOUDS_HLSLI + +#include "sky.hlsli" + +Texture2D g_Clouds : register(t15); +Texture2D g_HighClouds : register(t16); +SamplerState g_CloudsSampler : register(s15); + +float3 desaturate(float3 col, float amount) { + return lerp(col, dot(col, float3(.2126, .7152, .0722)), amount); +} + +// https://iquilezles.org/articles/smin/ +// sigmoid +float smin( float a, float b, float k ) +{ + k *= log(2.0); + float x = b-a; + return a + x/(1.0-exp2(x/k)); +} + +float ComputeTopDown(float value) { + value = -0.9501426 * value * value + 2.09511187 * value + -0.16186117; + return -smin(-value, 0., .045); +} + +void CalcClouds(inout float3 color, in float3 viewDir, in float3 sunDir) { + float3 emissive_top = 1.e-7; + float3 emissive_sun = linear_srgb_from_spectral_samples(sun_spectral_irradiance) * exp(-4.); + float3 emissive_view = 1.e-7; + CalcAtmosphere(emissive_top, float3(0., 1., 0.), sunDir); + CalcAtmosphere(emissive_sun, sunDir, sunDir); + CalcAtmosphere(emissive_view, viewDir, sunDir); + float3 cloud_dir = viewDir; + cloud_dir.y = 4. * abs(cloud_dir.y); + cloud_dir = normalize(cloud_dir); + float4 cloud_mask = g_Clouds.SampleLevel(g_CloudsSampler, cloud_dir.xz * .5 + .5, 0.); + float high_cloud_mask = g_HighClouds.SampleLevel(g_CloudsSampler, cloud_dir.xz * .5 + .5, 0.) * .5; + + float selector = atan2(sunDir.z, sunDir.x) / TWO_PI; + selector -= floor(selector); + selector *= 3.; + int idx = floor(selector); + float cloud_lit = lerp(cloud_mask[idx], cloud_mask[(idx + 1) % 3], frac(selector)); + + float topdown = ComputeTopDown(saturate(viewDir.y)); + + float3 ndotl = saturate(dot(viewDir, sunDir) * .5 + .5); + float shine = pow(ndotl, 17.); + + float3 shadow_color = desaturate(lerp(emissive_view, emissive_top, .5), .5);// * lerp(1., .1, shine); + float3 lit_color = lerp(emissive_view, emissive_sun, .5) * lerp(1., 4., shine); + + + + cloud_lit = pow(cloud_lit, lerp(lerp(1.6, 1.2, topdown), 3., shine)); + + float3 cloud_color = lerp( shadow_color, lit_color, cloud_lit); + cloud_color = lerp(cloud_color, emissive_view, smoothstep(.05, 0., topdown)); + + float3 high_cloud_color = lit_color; + high_cloud_color = lerp(high_cloud_color, emissive_view, smoothstep(.05, 0., topdown)); + + color = lerp(color, high_cloud_color, high_cloud_mask * smoothstep(-.025, .025, viewDir.y)); + color = lerp(color, cloud_color, cloud_mask.a * smoothstep(-.025, .025, viewDir.y)); +} + +#endif diff --git a/betterRenderer/shaders/manul/lighting.hlsli b/betterRenderer/shaders/manul/lighting.hlsli index 9d0ddb6a..18f99388 100644 --- a/betterRenderer/shaders/manul/lighting.hlsli +++ b/betterRenderer/shaders/manul/lighting.hlsli @@ -5,6 +5,8 @@ #include "material_common.hlsli" +#include "sky_common.hlsli" // ray_sphere_intersection + #include "view_data.hlsli" #include "lighting_functions.hlsli" @@ -16,6 +18,7 @@ TextureCube g_DiffuseEnvmap : register(t8); TextureCube g_SpecularEnvmap : register(t9); Texture2D g_BrdfLUT : register(t10); +Texture2D g_CloudShadowMap : register(t15); Texture2D g_LightGrid : register(t16); StructuredBuffer g_LightIndexBuffer : register(t17); StructuredBuffer g_LightBuffer : register(t18); @@ -83,6 +86,15 @@ void ApplyMaterialLighting(out float4 lit, in MaterialData material) #ifdef GBUFFER_CONTACT_SHADOWS_HLSLI shadow = min(shadow, GetContactShadows(pixel_position)); #endif + + float t = ray_sphere_intersection(view, g_LightDir.xyz, 10000.); + if(t >= 0.) { + float3 cloud_dir = normalize(view + g_LightDir.xyz * t); + cloud_dir.y = 4. * abs(cloud_dir.y); + cloud_dir = normalize(cloud_dir); + float4 cloud_mask = g_CloudShadowMap.SampleLevel(g_SamplerLinearClamp, cloud_dir.xz * .5 + .5, 0.); + shadow = min(shadow, 1. - cloud_mask.a * .6); + } // Apply IBL cubemap ApplyIBL(lit.rgb, surface_data); diff --git a/betterRenderer/shaders/manul/sky.hlsli b/betterRenderer/shaders/manul/sky.hlsli index bbc2eb0a..bcc8f779 100644 --- a/betterRenderer/shaders/manul/sky.hlsli +++ b/betterRenderer/shaders/manul/sky.hlsli @@ -22,7 +22,7 @@ void CalcSun(inout float3 color, in float3 viewDir, in float3 sunDir, in float a { if (dot(viewDir, sunDir) > 0.99998869014) { - color = linear_srgb_from_spectral_samples(sun_spectral_irradiance); + color = linear_srgb_from_spectral_samples(sun_spectral_irradiance) * exp(-2.); } } } @@ -37,7 +37,7 @@ void CalcMoon(inout float3 color, in float3 viewDir, in float3 moonDir, in float float3 normal = CalcSphereNormal(viewDir, moonDir, 0.99998869014); if (dot(normal, normal) > 0.) { - color = .07 * max(dot(normal, sunDir), 0.) * linear_srgb_from_spectral_samples(sun_spectral_irradiance); + color = .07 * max(dot(normal, sunDir), 0.) * linear_srgb_from_spectral_samples(sun_spectral_irradiance) * exp(-2.); } } } diff --git a/betterRenderer/shaders/manul/sky_aerial_lut.hlsl b/betterRenderer/shaders/manul/sky_aerial_lut.hlsl index e5104f8a..a6cb02c3 100644 --- a/betterRenderer/shaders/manul/sky_aerial_lut.hlsl +++ b/betterRenderer/shaders/manul/sky_aerial_lut.hlsl @@ -14,6 +14,7 @@ cbuffer DispatchConstants : register(b0) RWTexture2DArray g_AerialLut : register(u0); RWTexture2D g_Sky : register(u1); +Texture2D g_Clouds : register(t15); Texture2D g_TransmittanceLut : register(t13); SamplerState g_TransmittanceLutSampler : register(s13); @@ -77,8 +78,8 @@ SamplerState g_TransmittanceLutSampler : register(s13); { float t = (i + 1.) / (float)texture_size.z; float end_depth = min(t_d, t * t * g_MaxDepth); - compute_inscattering(g_TransmittanceLut, g_TransmittanceLutSampler, molecular_phase, aerosol_phase, 5, ray_origin, ray_dir, start_depth, end_depth, g_SunDir, L, transmittance); - compute_inscattering(g_TransmittanceLut, g_TransmittanceLutSampler, molecular_phase_moon, aerosol_phase_moon, 5, ray_origin, ray_dir, start_depth, end_depth, g_MoonDir, M, transmittance_m); + compute_inscattering_with_cloud_shadow(g_TransmittanceLut, g_Clouds, g_TransmittanceLutSampler, molecular_phase, aerosol_phase, 5, ray_origin, ray_dir, start_depth, end_depth, g_SunDir, L, transmittance); + compute_inscattering_with_cloud_shadow(g_TransmittanceLut, g_Clouds, g_TransmittanceLutSampler, molecular_phase_moon, aerosol_phase_moon, 5, ray_origin, ray_dir, start_depth, end_depth, g_MoonDir, M, transmittance_m); g_AerialLut[uint3(pix_coord, i)] = float4(linear_srgb_from_spectral_samples(L + .07 * moon_phase * M) * exp2(EXPOSURE), dot(transmittance, .25)); start_depth = end_depth; } diff --git a/betterRenderer/shaders/manul/sky_inscattering.hlsli b/betterRenderer/shaders/manul/sky_inscattering.hlsli index 118fd061..17ff15c8 100644 --- a/betterRenderer/shaders/manul/sky_inscattering.hlsli +++ b/betterRenderer/shaders/manul/sky_inscattering.hlsli @@ -66,6 +66,64 @@ void compute_inscattering(Texture2D transmittance_lut, SamplerState lut_sampler, } } +void compute_inscattering_with_cloud_shadow(Texture2D transmittance_lut, Texture2D clouds, SamplerState lut_sampler, in float molecular_phase, in float aerosol_phase, int steps, float3 ray_origin, float3 ray_dir, float t_min, float t_max, float3 sun_dir, inout float4 L_inscattering, inout float4 transmittance) +{ + float dt = (t_max - t_min) / float(steps); + + for (int i = 0; i < steps; ++i) { + float t = t_min + (float(i) + 0.5) * dt; + float3 x_t = ray_origin + ray_dir * t; + + float distance_to_earth_center = length(x_t); + float3 zenith_dir = x_t / distance_to_earth_center; + float altitude = distance_to_earth_center - EARTH_RADIUS; + float normalized_altitude = altitude / ATMOSPHERE_THICKNESS; + + float sample_cos_theta = dot(zenith_dir, sun_dir); + + float shadow = 1.; + float c_t = ray_sphere_intersection(ray_dir * t, sun_dir, 10000.); + if(c_t >= 0.) { + float3 cloud_dir = normalize(ray_dir * t + sun_dir * c_t); + cloud_dir.y = 4. * cloud_dir.y; + cloud_dir = normalize(cloud_dir); + float4 cloud_mask = clouds.SampleLevel(lut_sampler, cloud_dir.xz * .5 + .5, 0.); + shadow = min(shadow, 1. - cloud_mask.a * smoothstep(-.01, .01, cloud_dir.y)); + } + + float4 aerosol_absorption, aerosol_scattering; + float4 molecular_absorption, molecular_scattering; + float4 fog_scattering; + float4 extinction; + get_atmosphere_collision_coefficients( + altitude, + aerosol_absorption, aerosol_scattering, + molecular_absorption, molecular_scattering, + fog_scattering, + extinction); + + float4 transmittance_to_sun = transmittance_from_lut( + transmittance_lut, lut_sampler, sample_cos_theta, normalized_altitude) * shadow; + + float4 ms = get_multiple_scattering( + transmittance_lut, lut_sampler, sample_cos_theta, normalized_altitude, + distance_to_earth_center); + + float4 S = sun_spectral_irradiance * + (molecular_scattering * (molecular_phase * transmittance_to_sun + ms) + + (aerosol_scattering + fog_scattering) * (aerosol_phase * transmittance_to_sun + ms)); + + float4 step_transmittance = exp(-dt * extinction); + + // Energy-conserving analytical integration + // "Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite" + // by Sébastien Hillaire + float4 S_int = (S - S * step_transmittance) / max(extinction, 1e-7); + L_inscattering += transmittance * S_int; + transmittance *= step_transmittance; + } +} + float4 get_inscattering(Texture2D transmittance_lut, SamplerState lut_sampler, int steps, float altitude, float3 ray_dir, float t_min, float t_max, float3 sun_dir) { float cos_theta = dot(-ray_dir, sun_dir); float molecular_phase = molecular_phase_function(cos_theta); diff --git a/betterRenderer/shaders/skybox.hlsl b/betterRenderer/shaders/skybox.hlsl index 6a19ffde..315909d5 100644 --- a/betterRenderer/shaders/skybox.hlsl +++ b/betterRenderer/shaders/skybox.hlsl @@ -24,6 +24,7 @@ sampler g_SkyboxSampler : register(s0); TextureCube g_Skybox : register(t0); #include "manul/sky.hlsli" +#include "manul/clouds.hlsli" PixelOutput main(VertexOutput ps_in) { PixelOutput result; @@ -38,6 +39,7 @@ PixelOutput main(VertexOutput ps_in) { CalcSun(result.m_Emission, viewDir, g_SunDirection, g_Altitude); CalcMoon(result.m_Emission, viewDir, g_MoonDirection, g_SunDirection, g_Altitude); CalcAtmosphere(result.m_Emission, viewDir, g_SunDirection); + CalcClouds(result.m_Emission, viewDir, g_SunDirection); //result.m_Emission = g_Skybox.Sample(g_SkyboxSampler, normalize(mul(g_InverseViewProjection, positionNdc).xyz)).rgb; //result.m_Emission = 0.; //Sky(normalize(mul(g_InverseViewProjection, positionNdc).xyz), g_SunDirection, g_Altitude); float4 positionReproject = mul(g_HistoryReproject, positionNdc);