add refraction support for materials; two pass rain shader

This commit is contained in:
Wls50
2025-11-23 23:45:06 +01:00
committed by Hirek
parent 90538c8878
commit ff50fdf110
17 changed files with 614 additions and 145 deletions

View File

@@ -190,6 +190,7 @@ class NvRenderer : public gfx_renderer, public MaResourceRegistry {
std::shared_ptr<struct Bloom> m_bloom;
std::shared_ptr<struct Sky> m_sky;
std::shared_ptr<struct MaAutoExposure> m_auto_exposure;
std::shared_ptr<struct WindshieldRain> m_windshield_rain;
std::unordered_map<TModel3d const *, std::shared_ptr<Rt::IRtModel>> rt_models;
std::shared_ptr<Rt::IRtModel> GetRtModel(TModel3d const *);

View File

@@ -85,6 +85,15 @@ void GbufferBlitPass::Init() {
.setKeepInitialState(true));
RegisterResource(true, "scene_lit_texture", m_output,
nvrhi::ResourceType::Texture_SRV);
m_output_copy = m_backend->GetDevice()->createTexture(
nvrhi::TextureDesc()
.setWidth(m_gbuffer->m_framebuffer->getFramebufferInfo().width)
.setHeight(m_gbuffer->m_framebuffer->getFramebufferInfo().height)
.setFormat(nvrhi::Format::RGBA16_FLOAT)
.setInitialState(nvrhi::ResourceStates::ShaderResource)
.setKeepInitialState(true));
RegisterResource(true, "scene_lit_texture_copy", m_output_copy,
nvrhi::ResourceType::Texture_SRV);
m_binding_layout = m_backend->GetDevice()->createBindingLayout(
nvrhi::BindingLayoutDesc()
.addItem(nvrhi::BindingLayoutItem::VolatileConstantBuffer(2))
@@ -187,6 +196,8 @@ void GbufferBlitPass::UpdateConstants(nvrhi::ICommandList* command_list,
constants.m_light_color);
constants.m_altitude = Global.pCamera.Pos.y;
constants.m_time = Timer::GetTime();
constants.m_vertical_fov =
glm::radians(Global.FieldOfView / Global.ZoomFactor);
{
float percipitation_intensity = glm::saturate(Global.Overcast - 1.);
@@ -238,6 +249,10 @@ void GbufferBlitPass::Render(nvrhi::ICommandList* command_list,
m_scene_depth, nvrhi::TextureSlice().resolve(m_scene_depth->getDesc()),
m_gbuffer->m_gbuffer_depth,
nvrhi::TextureSlice().resolve(m_scene_depth->getDesc()));
command_list->copyTexture(
m_output_copy, nvrhi::TextureSlice().resolve(m_output_copy->getDesc()),
m_output,
nvrhi::TextureSlice().resolve(m_output->getDesc()));
}
void GbufferBlitPass::Render(nvrhi::ICommandList* command_list) {

View File

@@ -22,7 +22,7 @@ struct GbufferBlitPass : public FullScreenPass, public MaResourceRegistry {
const glm::dmat4& projection);
virtual void Render(nvrhi::ICommandList* command_list) override;
struct DrawConstants {
struct alignas(16) DrawConstants {
glm::mat4 m_inverse_model_view;
glm::mat4 m_inverse_projection;
glm::vec3 m_light_dir;
@@ -33,6 +33,7 @@ struct GbufferBlitPass : public FullScreenPass, public MaResourceRegistry {
glm::vec4 m_wiper_pos;
glm::vec4 m_wiper_timer_out;
glm::vec4 m_wiper_timer_return;
float m_vertical_fov;
};
nvrhi::BindingLayoutHandle m_binding_layout;
@@ -53,5 +54,6 @@ struct GbufferBlitPass : public FullScreenPass, public MaResourceRegistry {
nvrhi::ComputePipelineHandle m_pso;
nvrhi::TextureHandle m_output;
nvrhi::TextureHandle m_output_copy;
virtual nvrhi::IFramebuffer* GetFramebuffer() override;
};

View File

@@ -121,13 +121,18 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
binding.disable_anisotropy = it.second["no_anisotropy"].as<bool>(false);
binding.disable_filter = it.second["no_filter"].as<bool>(false);
binding.disable_mip_bias = it.second["no_mip_bias"].as<bool>(false);
size_t default_texture = m_renderer->GetTextureManager()->FetchTexture(
it.second["default"].as<std::string>(""), binding.m_hint, 0, false);
if (!default_texture) {
default_texture = 1;
}
texture_mappings.emplace_back(
MaResourceMapping::Texture_SRV(index, binding.m_name.c_str()));
sampler_mappings.emplace_back(
MaResourceMapping::Sampler(index, binding.m_sampler_name.c_str()));
RegisterTexture(binding.m_name.c_str(), 1);
RegisterTexture(binding.m_name.c_str(), default_texture);
RegisterResource(
false, "masked_shadow_sampler",
GetTextureManager()->GetSamplerForTraits(0, RenderPassType::ShadowMap),
@@ -236,6 +241,7 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
.Add(MaResourceMapping::Texture_SRV(10, "env_brdf_lut"))
.Add(MaResourceMapping::Texture_SRV(11, "shadow_depths"))
.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(
16, "forwardplus_index_grid_transparent"))

View File

@@ -39,6 +39,7 @@
#include "rt_model.h"
#include "tinyexr.h"
#include "windshield_rain.h"
bool NvRenderer::Init(GLFWwindow *Window) {
m_message_callback = std::make_shared<NvRendererMessageCallback>();
@@ -92,6 +93,7 @@ bool NvRenderer::Init(GLFWwindow *Window) {
m_auto_exposure = std::make_shared<MaAutoExposure>(this);
m_fsr = std::make_shared<NvFSR>(this);
m_bloom = std::make_shared<Bloom>(GetBackend());
m_windshield_rain = std::make_shared<WindshieldRain>();
// protect from undefined framebuffer size in ini (default -1)
int w = Global.gfx_framebuffer_width, h = Global.gfx_framebuffer_height;
@@ -136,7 +138,10 @@ bool NvRenderer::Init(GLFWwindow *Window) {
// RegisterResource(true, "gbuffer_depth", m_gbuffer->m_gbuffer_depth,
// nvrhi::ResourceType::Texture_SRV);
m_windshield_rain->Init(this);
if (!InitMaterials()) return false;
return true;
}
@@ -631,6 +636,7 @@ bool NvRenderer::Render() {
command_list->endMarker();
if (true) {
m_windshield_rain->Render(pass);
command_list->beginMarker("Forward pass");
pass.m_framebuffer = m_framebuffer_forward;
pass.m_type = RenderPassType::Forward;

View File

@@ -373,6 +373,19 @@ size_t NvTextureManager::FetchTexture(std::string path, int format_hint,
return index;
}
size_t NvTextureManager::RegisterExternalTexture(std::string const& path,
nvrhi::ITexture *texture) {
auto [it, added] = m_texture_map.emplace(path, -1);
if (added) {
m_texture_cache.emplace_back(std::make_shared<NvTexture>());
it->second = m_texture_cache.size();
}
auto cache = m_texture_cache[it->second - 1];
cache->m_rhi_texture = texture;
cache->m_last_change = ++NvTexture::s_change_counter;
return it->second;
}
bool NvTexture::CreateRhiTexture() {
if (m_rhi_texture) return true;
m_last_change = ++s_change_counter;
@@ -495,8 +508,14 @@ nvrhi::SamplerHandle NvTextureManager::GetSamplerForTraits(
: nvrhi::SamplerAddressMode::Wrap)
.setAllFilters(!traits[MaTextureTraits_NoFilter])
.setMipFilter(false)
.setMaxAnisotropy(traits[MaTextureTraits_NoAnisotropy] || traits[MaTextureTraits_NoFilter] ? 0.f : 16.f)
.setMipBias(traits[MaTextureTraits_NoMipBias] || traits[MaTextureTraits_NoFilter] ? 0.f : -1.76f);
.setMaxAnisotropy(traits[MaTextureTraits_NoAnisotropy] ||
traits[MaTextureTraits_NoFilter]
? 0.f
: 16.f)
.setMipBias(traits[MaTextureTraits_NoMipBias] ||
traits[MaTextureTraits_NoFilter]
? 0.f
: -1.76f);
sampler = m_backend->GetDevice()->createSampler(desc);
}
return sampler;

View File

@@ -83,6 +83,7 @@ class NvTextureManager {
NvTextureManager(class NvRenderer* renderer);
size_t FetchTexture(std::string path, int format_hint, int size_bias,
bool unload_on_location);
size_t RegisterExternalTexture(std::string const& path, nvrhi::ITexture *texture);
void UpdateLastUse(size_t handle, const glm::dvec3& location);
bool IsValidHandle(size_t handle);
NvTexture* GetTexture(size_t handle);

View File

@@ -0,0 +1,246 @@
#include "windshield_rain.h"
#include "gbuffer.h"
#include "gbufferblitpass.h"
#include "nvrendererbackend.h"
#include "nvrhi/utils.h"
#include "nvtexture.h"
void WindshieldRain::Init(NvRenderer* in_renderer) {
renderer = in_renderer;
{
auto const src_desc = renderer->m_gbuffer->m_gbuffer_depth->getDesc();
width = src_desc.width / 2;
height = src_desc.height / 2;
}
auto backend = renderer->GetBackend();
tex_droplets = backend->GetDevice()->createTexture(
nvrhi::TextureDesc()
.setDebugName("Raindrop buffer")
.setWidth(width)
.setHeight(height)
.setFormat(nvrhi::Format::R32_FLOAT)
.setIsRenderTarget(true)
.setInitialState(nvrhi::ResourceStates::RenderTarget)
.setClearValue(nvrhi::Color(0.))
.setUseClearValue(true)
.setKeepInitialState(true));
tex_depth_temp = backend->GetDevice()->createTexture(
nvrhi::TextureDesc()
.setDebugName("Raindrop depths temp")
.setWidth(width)
.setHeight(height)
.setFormat(nvrhi::Format::D32)
.setIsUAV(true)
.setInitialState(nvrhi::ResourceStates::UnorderedAccess)
.setKeepInitialState(true));
tex_depth = backend->GetDevice()->createTexture(
nvrhi::TextureDesc()
.setDebugName("Raindrop depths")
.setWidth(width)
.setHeight(height)
.setFormat(nvrhi::Format::D32)
.setIsRenderTarget(true)
.setInitialState(nvrhi::ResourceStates::DepthWrite)
.setClearValue(nvrhi::Color(0.))
.setUseClearValue(true)
.setKeepInitialState(true));
framebuffer = backend->GetDevice()->createFramebuffer(
nvrhi::FramebufferDesc()
.addColorAttachment(tex_droplets)
.setDepthAttachment(tex_depth));
ps_rain_anim =
backend->CreateShader("windshield_rain_anim", nvrhi::ShaderType::Pixel);
vs_rain_anim =
backend->CreateShader("default_vertex_no_jitter", nvrhi::ShaderType::Vertex);
cs_max_depth =
backend->CreateShader("max_depth_4x4", nvrhi::ShaderType::Compute);
auto const texture_manager = renderer->GetTextureManager();
texture_handle_droplets = texture_manager->FetchTexture(
"textures/fx/raindrops_height", GL_R, 0, false);
texture_handle_wipermask = texture_manager->FetchTexture(
"dynamic/pkp/ep09_v1/104ec/szyby_wipermask", GL_SRGB, 0, false);
texture_manager->RegisterExternalTexture("system/raindrops_buffer",
tex_droplets);
{
nvrhi::SamplerHandle sampler = backend->GetDevice()->createSampler(
nvrhi::SamplerDesc().setAllFilters(true).setAllAddressModes(
nvrhi::SamplerAddressMode::Clamp));
nvrhi::BindingLayoutHandle binding_layout;
nvrhi::utils::CreateBindingSetAndLayout(
backend->GetDevice(), nvrhi::ShaderType::Compute, 0,
nvrhi::BindingSetDesc()
.addItem(nvrhi::BindingSetItem::Texture_SRV(
0, renderer->m_gbuffer->m_gbuffer_depth))
.addItem(nvrhi::BindingSetItem::Texture_UAV(0, tex_depth_temp))
.addItem(nvrhi::BindingSetItem::Sampler(0, sampler)),
binding_layout, bindings_max_depth);
pso_max_depth = backend->GetDevice()->createComputePipeline(
nvrhi::ComputePipelineDesc()
.addBindingLayout(binding_layout)
.setComputeShader(cs_max_depth));
}
}
void WindshieldRain::Resize(int width, int height) {}
nvrhi::ITexture* WindshieldRain::GetTexture() const { return tex_droplets; }
void WindshieldRain::Render(NvRenderer::RenderPass const& pass) {
if (!pso_droplets) {
CreatePso(pass.m_command_list_draw);
}
if (renderer->m_dynamic_with_kabina < renderer->m_dynamics.size()) {
const auto& dynamic = renderer->m_dynamics[renderer->m_dynamic_with_kabina];
pass.m_command_list_draw->beginMarker("Render cab rain buffer");
pass.m_command_list_draw->clearTextureFloat(
tex_droplets, nvrhi::AllSubresources, nvrhi::Color(0.));
{
nvrhi::ComputeState compute_state;
compute_state.setPipeline(pso_max_depth);
compute_state.addBindingSet(bindings_max_depth);
pass.m_command_list_draw->setComputeState(compute_state);
pass.m_command_list_draw->dispatch((width + 7) / 8, (height + 7) / 8);
}
pass.m_command_list_draw->copyTexture(tex_depth, nvrhi::TextureSlice(),
tex_depth_temp, nvrhi::TextureSlice());
for (auto const& item : dynamic.m_renderable_kabina.m_items) {
auto const& material = renderer->m_material_cache[item.m_material - 1];
if (!IsRainShader(material.m_template)) {
continue;
}
nvrhi::GraphicsState gfx_state{};
nvrhi::DrawArguments draw_arguments;
bool indexed;
if (!renderer->BindGeometry(item.m_geometry, pass, gfx_state,
draw_arguments, indexed)) {
continue;
}
auto transform = item.m_transform;
transform[3] -= pass.m_origin;
auto& binding_set = binding_sets_per_material[item.m_material];
if (!binding_set) {
auto const& material = renderer->m_material_cache[item.m_material - 1];
auto texture_wipermask = renderer->GetTextureManager()->GetRhiTexture(
material.m_texture_handles[2], pass.m_command_list_draw);
binding_set = renderer->m_backend->GetDevice()->createBindingSet(
nvrhi::BindingSetDesc()
.addItem(nvrhi::BindingSetItem::ConstantBuffer(
0, renderer->m_drawconstant_buffer))
.addItem(nvrhi::BindingSetItem::ConstantBuffer(
2, renderer->m_gbuffer_blit->m_draw_constants))
.addItem(nvrhi::BindingSetItem::PushConstants(
1, sizeof(NvRenderer::PushConstantsDraw)))
.addItem(
nvrhi::BindingSetItem::Texture_SRV(0, texture_droplets))
.addItem(
nvrhi::BindingSetItem::Texture_SRV(1, texture_wipermask))
.addItem(nvrhi::BindingSetItem::Sampler(0, sampler))
.addItem(nvrhi::BindingSetItem::Sampler(1, sampler_point)),
binding_layout);
}
gfx_state.setFramebuffer(framebuffer);
gfx_state.setPipeline(pso_droplets);
gfx_state.addBindingSet(binding_set);
gfx_state.setViewport(nvrhi::ViewportState().addViewportAndScissorRect(
framebuffer->getFramebufferInfo().getViewport()));
pass.m_command_list_draw->beginMarker(item.m_name.data());
pass.m_command_list_draw->setGraphicsState(gfx_state);
{
NvRenderer::PushConstantsDraw data{};
data.m_modelview = static_cast<glm::mat3x4>(
transpose(static_cast<glm::dmat4>(pass.m_transform) *
static_cast<glm::dmat4>(transform)));
data.m_modelview_history = data.m_modelview;
pass.m_command_list_draw->setPushConstants(&data, sizeof(data));
}
if (indexed)
pass.m_command_list_draw->drawIndexed(draw_arguments);
else
pass.m_command_list_draw->draw(draw_arguments);
pass.m_command_list_draw->endMarker();
}
pass.m_command_list_draw->endMarker();
}
std::erase_if(binding_sets_per_material, [this](auto const& kv) {
auto const& material = renderer->m_material_cache[kv.first - 1];
return renderer->GetCurrentFrame() - material.m_last_frame_requested > 100;
});
}
bool WindshieldRain::IsRainShader(
NvRenderer::MaterialTemplate const* mt) const {
return mt->m_name == "windshield_rain";
}
void WindshieldRain::CreatePso(nvrhi::ICommandList* command_list) {
auto backend = renderer->GetBackend();
texture_droplets = renderer->GetTextureManager()->GetRhiTexture(
texture_handle_droplets, command_list);
sampler = backend->GetDevice()->createSampler(
nvrhi::SamplerDesc()
.setAllFilters(true)
.setMipFilter(false)
.setAllAddressModes(nvrhi::SamplerAddressMode::Repeat));
sampler_point = backend->GetDevice()->createSampler(
nvrhi::SamplerDesc().setAllFilters(false).setAllAddressModes(
nvrhi::SamplerAddressMode::Repeat));
binding_layout = backend->GetDevice()->createBindingLayout(
nvrhi::BindingLayoutDesc()
.setVisibility(nvrhi::ShaderType::AllGraphics)
.setRegisterSpace(0)
.addItem(nvrhi::BindingLayoutItem::ConstantBuffer(0))
.addItem(nvrhi::BindingLayoutItem::VolatileConstantBuffer(2))
.addItem(nvrhi::BindingLayoutItem::PushConstants(
1, sizeof(NvRenderer::PushConstantsDraw)))
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(1))
.addItem(nvrhi::BindingLayoutItem::Sampler(0))
.addItem(nvrhi::BindingLayoutItem::Sampler(1)));
pso_droplets = backend->GetDevice()->createGraphicsPipeline(
nvrhi::GraphicsPipelineDesc()
.addBindingLayout(binding_layout)
.setVertexShader(vs_rain_anim)
.setInputLayout(renderer->m_input_layout[static_cast<size_t>(
RendererEnums::DrawType::Model)])
.setPixelShader(ps_rain_anim)
.setRenderState(
nvrhi::RenderState()
.setDepthStencilState(
nvrhi::DepthStencilState()
.enableDepthTest()
.enableDepthWrite()
.disableStencil()
.setDepthFunc(nvrhi::ComparisonFunc::Greater))
.setRasterState(nvrhi::RasterState()
.setFillSolid()
.enableDepthClip()
.disableScissor()
.setCullFront())
.setBlendState(nvrhi::BlendState().setRenderTarget(
0, nvrhi::BlendState::RenderTarget().disableBlend())))
.setPrimType(nvrhi::PrimitiveType::TriangleList),
framebuffer);
}

View File

@@ -0,0 +1,46 @@
#pragma once
#include "nvrenderer/nvrenderer.h"
struct WindshieldRain {
void Init(NvRenderer *in_renderer);
void Resize(int width, int height);
uint32_t width;
uint32_t height;
[[nodiscard]] nvrhi::ITexture *GetTexture() const;
void Render(NvRenderer::RenderPass const &pass);
bool IsRainShader(NvRenderer::MaterialTemplate const *mt) const;
size_t texture_handle_droplets;
size_t texture_handle_wipermask;
nvrhi::TextureHandle texture_droplets;
nvrhi::SamplerHandle sampler;
nvrhi::SamplerHandle sampler_point;
void CreatePso(nvrhi::ICommandList *command_list);
NvRenderer *renderer;
nvrhi::FramebufferHandle framebuffer;
nvrhi::TextureHandle tex_droplets;
nvrhi::TextureHandle tex_depth;
nvrhi::TextureHandle tex_depth_temp;
nvrhi::ShaderHandle ps_rain_anim;
nvrhi::ShaderHandle vs_rain_anim;
nvrhi::ShaderHandle cs_max_depth;
nvrhi::BindingSetHandle bindings;
nvrhi::BindingSetHandle bindings_max_depth;
nvrhi::GraphicsPipelineHandle pso_droplets;
nvrhi::ComputePipelineHandle pso_max_depth;
nvrhi::BindingLayoutHandle binding_layout;
std::unordered_map<size_t, nvrhi::BindingSetHandle> binding_sets_per_material;
};