mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
Merge pull request #33 from MaSzyna-EU07/wipers
Improve wipers shader + chromatic abberation improvements
This commit is contained in:
29
Model3d.cpp
29
Model3d.cpp
@@ -1866,7 +1866,8 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
|
||||
{
|
||||
uint32_t type = sn_utils::ld_uint32(s);
|
||||
uint32_t size = sn_utils::ld_uint32(s) - 8;
|
||||
std::streampos end = s.tellg() + (std::streampos)size;
|
||||
size_t pos = s.tellg();
|
||||
std::streampos end = pos + (std::streampos)size;
|
||||
|
||||
if ((type & 0x00FFFFFF) == MAKE_ID4('S', 'U', 'B', 0)) // submodels
|
||||
{
|
||||
@@ -1877,7 +1878,6 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
|
||||
size_t sm_cnt = size / sm_size;
|
||||
iSubModelsCount = (int)sm_cnt;
|
||||
Root = new TSubModel[sm_cnt];
|
||||
size_t pos = s.tellg();
|
||||
for (size_t i = 0; i < sm_cnt; ++i)
|
||||
{
|
||||
s.seekg(pos + sm_size * i);
|
||||
@@ -1906,7 +1906,31 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
|
||||
size_t const vertextype { ( ( ( type & 0xFF000000 ) >> 24 ) - '0' ) };
|
||||
hastangents = ( (vertextype & 3) > 0 );
|
||||
hasuserdata = (vertextype & 4);
|
||||
size_t vertex_size = 0;
|
||||
switch (vertextype & 3)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
{
|
||||
vertex_size = 8;
|
||||
if(hastangents)
|
||||
vertex_size += 4;
|
||||
if(hasuserdata)
|
||||
vertex_size += 4;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
vertex_size = 4;
|
||||
if(hastangents)
|
||||
vertex_size += 1;
|
||||
if (hasuserdata)
|
||||
vertex_size += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for( auto const &submodeloffset : submodeloffsets ) {
|
||||
s.seekg(pos + submodeloffset.first * vertex_size * sizeof(float)); // Ensure that we start reading from the correct offset even if geometry is not encoded contiguously
|
||||
auto &submodel { Root[ submodeloffset.second ] };
|
||||
auto const &submodelgeometry { submodel.m_geometry };
|
||||
submodel.Vertices.resize( submodelgeometry.vertex_count );
|
||||
@@ -1978,6 +2002,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
|
||||
// once sorted we can grab indices in a continuous read, and assign them to the chunks they belong to
|
||||
size_t const indexsize { ( ( ( type & 0xFF000000 ) >> 24 ) - '0' ) };
|
||||
for( auto const &submodeloffset : submodeloffsets ) {
|
||||
s.seekg(pos + submodeloffset.first * indexsize);
|
||||
auto &submodel { Root[ submodeloffset.second ] };
|
||||
auto const &submodelgeometry { submodel.m_geometry };
|
||||
submodel.Indices.resize( submodelgeometry.index_count );
|
||||
|
||||
1
Timer.h
1
Timer.h
@@ -58,6 +58,7 @@ struct subsystem_stopwatches {
|
||||
stopwatch gfx_reflections;
|
||||
stopwatch gfx_swap;
|
||||
stopwatch gfx_gui;
|
||||
stopwatch gfx_animate;
|
||||
stopwatch sim_total;
|
||||
stopwatch sim_dynamics;
|
||||
stopwatch sim_events;
|
||||
|
||||
@@ -274,6 +274,11 @@ bool MaShaderCompiler::CompileMaterial(YAML::Node &dest, const YAML::Node &src,
|
||||
local_definitions.insert(local_definitions.end(), definitions.begin(),
|
||||
definitions.end());
|
||||
|
||||
if (pass == MaterialRenderPass::Forward &&
|
||||
TemplateOverride("refraction", src, templates).as<bool>(false)) {
|
||||
local_definitions.emplace_back(L"REFRACTION", L"1");
|
||||
}
|
||||
|
||||
auto blob = CompileShaderToBlob(file_name, ToWide(entry_name),
|
||||
local_definitions, target, platform);
|
||||
|
||||
|
||||
@@ -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 *);
|
||||
@@ -424,6 +425,7 @@ class NvRenderer : public gfx_renderer, public MaResourceRegistry {
|
||||
float m_opacity;
|
||||
float m_selfillum;
|
||||
glm::vec3 m_diffuse;
|
||||
std::string_view m_name = "";
|
||||
};
|
||||
struct SpotLight {
|
||||
glm::vec3 m_color;
|
||||
@@ -497,8 +499,12 @@ class NvRenderer : public gfx_renderer, public MaResourceRegistry {
|
||||
std::string m_name;
|
||||
std::string m_sampler_name;
|
||||
int m_hint;
|
||||
bool disable_anisotropy = false;
|
||||
bool disable_filter = false;
|
||||
bool disable_mip_bias = false;
|
||||
texture_handle m_default_texture;
|
||||
};
|
||||
bool m_enable_refraction = false;
|
||||
nvrhi::static_vector<TextureBinding, 8> m_texture_bindings;
|
||||
std::array<nvrhi::GraphicsPipelineHandle, Constants::NumMaterialPipelines()>
|
||||
m_pipelines;
|
||||
@@ -610,16 +616,21 @@ class NvRenderer : public gfx_renderer, public MaResourceRegistry {
|
||||
nvrhi::BufferHandle m_cubedrawconstant_buffer;
|
||||
nvrhi::BufferHandle m_drawconstant_buffer;
|
||||
std::array<nvrhi::ShaderHandle, Constants::NumDrawTypes()> m_vertex_shader;
|
||||
std::array<nvrhi::ShaderHandle, Constants::NumDrawTypes()> m_vertex_shader_prepass;
|
||||
std::array<nvrhi::ShaderHandle, Constants::NumDrawTypes()>
|
||||
m_vertex_shader_cubemap;
|
||||
std::array<nvrhi::ShaderHandle, Constants::NumDrawTypes()>
|
||||
m_vertex_shader_shadow;
|
||||
nvrhi::BindingLayoutHandle m_binding_layout_shadow_masked;
|
||||
nvrhi::BindingLayoutHandle m_binding_layout_prepass;
|
||||
nvrhi::ShaderHandle m_pixel_shader_shadow_masked;
|
||||
nvrhi::ShaderHandle m_pixel_shader_prepass_masked;
|
||||
std::array<nvrhi::InputLayoutHandle, Constants::NumDrawTypes()>
|
||||
m_input_layout;
|
||||
m_input_layout;
|
||||
std::array<nvrhi::GraphicsPipelineHandle, Constants::NumShadowPipelines()>
|
||||
m_pso_shadow;
|
||||
std::array<nvrhi::GraphicsPipelineHandle, Constants::NumShadowPipelines()>
|
||||
m_pso_prepass;
|
||||
nvrhi::GraphicsPipelineHandle m_pso_line;
|
||||
|
||||
std::condition_variable m_cv_next_frame;
|
||||
@@ -689,7 +700,7 @@ class NvRenderer : public gfx_renderer, public MaResourceRegistry {
|
||||
|
||||
bool BindMaterial(material_handle handle, DrawType draw_type,
|
||||
const RenderPass &pass, nvrhi::GraphicsState &gfx_state,
|
||||
float &alpha_threshold);
|
||||
float &alpha_threshold, bool *out_is_refractive = nullptr);
|
||||
|
||||
bool BindLineMaterial(DrawType draw_type, const RenderPass &pass,
|
||||
nvrhi::GraphicsState &gfx_state);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace RendererEnums {
|
||||
|
||||
enum class RenderPassType {
|
||||
DepthOnly,
|
||||
Deferred,
|
||||
Forward,
|
||||
CubeMap,
|
||||
|
||||
@@ -161,21 +161,21 @@ namespace XeGTAO
|
||||
template<class T> inline T clamp( T const & v, T const & min, T const & max ) { assert( max >= min ); if( v < min ) return min; if( v > max ) return max; return v; }
|
||||
|
||||
// If using TAA then set noiseIndex to frameIndex % 64 - otherwise use 0
|
||||
inline void GTAOUpdateConstants( XeGTAO::GTAOConstants& consts, int viewportWidth, int viewportHeight, const XeGTAO::GTAOSettings & settings, const float projMatrix[16], bool rowMajor, unsigned int frameCounter )
|
||||
inline void GTAOUpdateConstants( XeGTAO::GTAOConstants& consts, int viewportWidth, int viewportHeight, const XeGTAO::GTAOSettings & settings, const glm::mat4& projMatrix, bool rowMajor, unsigned int frameCounter )
|
||||
{
|
||||
consts.ViewportSize = { viewportWidth, viewportHeight };
|
||||
consts.ViewportPixelSize = { 1.0f / (float)viewportWidth, 1.0f / (float)viewportHeight };
|
||||
|
||||
float depthLinearizeMul = (rowMajor)?(-projMatrix[3 * 4 + 2]):(-projMatrix[3 + 2 * 4]); // float depthLinearizeMul = ( clipFar * clipNear ) / ( clipFar - clipNear );
|
||||
float depthLinearizeAdd = (rowMajor)?( projMatrix[2 * 4 + 2]):( projMatrix[2 + 2 * 4]); // float depthLinearizeAdd = clipFar / ( clipFar - clipNear );
|
||||
float depthLinearizeMul = -projMatrix[3][2]; // float depthLinearizeMul = ( clipFar * clipNear ) / ( clipFar - clipNear );
|
||||
float depthLinearizeAdd = -projMatrix[2][2]; // float depthLinearizeAdd = clipFar / ( clipFar - clipNear );
|
||||
|
||||
// correct the handedness issue. need to make sure this below is correct, but I think it is.
|
||||
if( depthLinearizeMul * depthLinearizeAdd < 0 )
|
||||
depthLinearizeAdd = -depthLinearizeAdd;
|
||||
consts.DepthUnpackConsts = { -depthLinearizeMul, depthLinearizeAdd };
|
||||
consts.DepthUnpackConsts = { depthLinearizeMul, depthLinearizeAdd };
|
||||
|
||||
float tanHalfFOVY = 1.0f / ((rowMajor)?(projMatrix[1 * 4 + 1]):(projMatrix[1 + 1 * 4])); // = tanf( drawContext.Camera.GetYFOV( ) * 0.5f );
|
||||
float tanHalfFOVX = 1.0F / ((rowMajor)?(projMatrix[0 * 4 + 0]):(projMatrix[0 + 0 * 4])); // = tanHalfFOVY * drawContext.Camera.GetAspect( );
|
||||
float tanHalfFOVY = 1.0f / projMatrix[1][1]; // = tanf( drawContext.Camera.GetYFOV( ) * 0.5f );
|
||||
float tanHalfFOVX = 1.0F / projMatrix[0][0]; // = tanHalfFOVY * drawContext.Camera.GetAspect( );
|
||||
consts.CameraTanHalfFOV = { tanHalfFOVX, tanHalfFOVY };
|
||||
|
||||
consts.NDCToViewMul = { consts.CameraTanHalfFOV.x * 2.0f, consts.CameraTanHalfFOV.y * -2.0f };
|
||||
|
||||
@@ -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))
|
||||
@@ -183,14 +192,65 @@ void GbufferBlitPass::UpdateConstants(nvrhi::ICommandList* command_list,
|
||||
|
||||
const auto& daylight = Global.DayLight;
|
||||
|
||||
m_sky->CalcLighting(constants.m_light_dir,
|
||||
constants.m_light_color);
|
||||
m_sky->CalcLighting(constants.m_light_dir, 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.);
|
||||
constants.m_rain_params.x =
|
||||
percipitation_intensity; // % amount of droplets
|
||||
constants.m_rain_params.y =
|
||||
glm::mix(15., 1., percipitation_intensity); // Regeneration time
|
||||
static glm::vec4 wiper_timer_out;
|
||||
static glm::vec4 wiper_timer_return;
|
||||
if (TDynamicObject const* owner = Global.pCamera.m_owner;
|
||||
owner && !!owner->MoverParameters->CabActive) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (i < owner->dWiperPos.size()) {
|
||||
int index = owner->MoverParameters->CabActive > 0
|
||||
? i
|
||||
: static_cast<int>(owner->dWiperPos.size() - 1) - i;
|
||||
constants.m_wiper_pos[i] = owner->dWiperPos[index];
|
||||
if (owner->dWiperPos[index] > 0. && owner->wiperDirection[index]) {
|
||||
constants.m_wiper_pos[i] += 1.;
|
||||
}
|
||||
if (owner->dWiperPos[index] < .025) {
|
||||
wiper_timer_out[i] = constants.m_time;
|
||||
}
|
||||
if (owner->dWiperPos[index] > .975) {
|
||||
wiper_timer_return[i] = constants.m_time;
|
||||
}
|
||||
constants.m_wiper_timer_out[i] = wiper_timer_out[i];
|
||||
constants.m_wiper_timer_return[i] = wiper_timer_return[i];
|
||||
} else {
|
||||
constants.m_wiper_pos[i] = 0.;
|
||||
wiper_timer_out[i] = constants.m_wiper_timer_out[i] = -1000.;
|
||||
wiper_timer_return[i] = constants.m_wiper_timer_return[i] = -1000.;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
constants.m_wiper_pos = glm::vec4{0.};
|
||||
wiper_timer_out = constants.m_wiper_timer_out = glm::vec4{-1000.};
|
||||
wiper_timer_return = constants.m_wiper_timer_return = glm::vec4{-1000.};
|
||||
}
|
||||
}
|
||||
|
||||
command_list->writeBuffer(m_draw_constants, &constants, sizeof(constants));
|
||||
}
|
||||
|
||||
void GbufferBlitPass::UpdateSceneColorForRefraction(
|
||||
nvrhi::ICommandList* command_list) const {
|
||||
command_list->copyTexture(
|
||||
m_output_copy, nvrhi::TextureSlice().resolve(m_output_copy->getDesc()),
|
||||
m_output, nvrhi::TextureSlice().resolve(m_output->getDesc()));
|
||||
command_list->setTextureState(m_output, nvrhi::AllSubresources,
|
||||
nvrhi::ResourceStates::RenderTarget);
|
||||
command_list->commitBarriers();
|
||||
}
|
||||
|
||||
void GbufferBlitPass::Render(nvrhi::ICommandList* command_list,
|
||||
glm::dmat4& view, const glm::dmat4& projection) {
|
||||
UpdateConstants(command_list, view, projection);
|
||||
|
||||
@@ -18,17 +18,24 @@ struct GbufferBlitPass : public FullScreenPass, public MaResourceRegistry {
|
||||
void UpdateConstants(nvrhi::ICommandList* command_list, glm::dmat4& view,
|
||||
const glm::dmat4& projection);
|
||||
|
||||
void UpdateSceneColorForRefraction(nvrhi::ICommandList *command_list) const;
|
||||
|
||||
void Render(nvrhi::ICommandList* command_list, glm::dmat4& view,
|
||||
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;
|
||||
float m_altitude;
|
||||
glm::vec3 m_light_color;
|
||||
float m_time;
|
||||
glm::vec4 m_rain_params;
|
||||
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;
|
||||
@@ -49,5 +56,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;
|
||||
};
|
||||
@@ -133,6 +133,9 @@ std::string_view MaterialAdapterLegacyMatFile::GetShader() const {
|
||||
if (m_shader == "water") {
|
||||
return "legacy_water";
|
||||
}
|
||||
if (m_shader == "rain_windscreen") {
|
||||
return "windshield_rain";
|
||||
}
|
||||
if (IsSpecGlossShader() && HasSpecGlossMap()) {
|
||||
if (IsNormalMapShader() && HasNormalMap()) {
|
||||
return "legacy_normalmap_specgloss";
|
||||
|
||||
@@ -94,6 +94,10 @@ nvrhi::IGraphicsPipeline *NvRenderer::MaterialTemplate::GetPipeline(
|
||||
return m_renderer->m_pso_shadow[Constants::GetDefaultShadowPipelineIndex(
|
||||
draw_type, alpha_masked)];
|
||||
}
|
||||
if (pass_type == RenderPassType::DepthOnly) {
|
||||
return m_renderer->m_pso_prepass[Constants::GetDefaultShadowPipelineIndex(
|
||||
draw_type, alpha_masked)];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -105,22 +109,31 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
|
||||
MaResourceMapping sampler_mapping_shadow{};
|
||||
m_pipelines.fill(nullptr);
|
||||
m_masked_shadow_texture = conf["masked_shadow_texture"].as<std::string>();
|
||||
m_enable_refraction = conf["refraction"].as<bool>(false);
|
||||
for (const auto it : conf["textures"]) {
|
||||
auto index = it.second["binding"].as<int>();
|
||||
m_texture_bindings.resize(
|
||||
glm::max(m_texture_bindings.size(), static_cast<size_t>(index) + 1));
|
||||
auto &[name, sampler_name, hint, default_texture] =
|
||||
m_texture_bindings[index];
|
||||
auto &binding = m_texture_bindings[index];
|
||||
|
||||
name = it.first.as<std::string>();
|
||||
sampler_name = fmt::format("{:s}_sampler", name.c_str());
|
||||
binding.m_name = it.first.as<std::string>();
|
||||
binding.m_sampler_name = fmt::format("{:s}_sampler", binding.m_name.c_str());
|
||||
|
||||
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, name.c_str()));
|
||||
MaResourceMapping::Texture_SRV(index, binding.m_name.c_str()));
|
||||
sampler_mappings.emplace_back(
|
||||
MaResourceMapping::Sampler(index, sampler_name.c_str()));
|
||||
MaResourceMapping::Sampler(index, binding.m_sampler_name.c_str()));
|
||||
|
||||
RegisterTexture(name.c_str(), 1);
|
||||
RegisterTexture(binding.m_name.c_str(), default_texture);
|
||||
RegisterResource(
|
||||
false, "masked_shadow_sampler",
|
||||
GetTextureManager()->GetSamplerForTraits(0, RenderPassType::ShadowMap),
|
||||
@@ -128,10 +141,10 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
|
||||
|
||||
const static std::unordered_map<std::string_view, int> hints{
|
||||
{"color", GL_SRGB_ALPHA}, {"linear", GL_RGBA}, {"normalmap", GL_RG}};
|
||||
hint = hints.at(it.second["hint"].as<std::string_view>());
|
||||
binding.m_hint = hints.at(it.second["hint"].as<std::string_view>());
|
||||
|
||||
if (it.first.Scalar() == conf["masked_shadow_texture"].Scalar()) {
|
||||
texture_mapping_shadow = MaResourceMapping::Texture_SRV(0, name.c_str());
|
||||
texture_mapping_shadow = MaResourceMapping::Texture_SRV(0, binding.m_name.c_str());
|
||||
sampler_mapping_shadow =
|
||||
MaResourceMapping::Sampler(0, "masked_shadow_sampler");
|
||||
}
|
||||
@@ -169,6 +182,14 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
|
||||
.Add(texture_mapping_shadow)
|
||||
.Add(sampler_mapping_shadow);
|
||||
}
|
||||
if (pass == RenderPassType::DepthOnly) {
|
||||
mappings
|
||||
.Add(MaResourceMapping::ConstantBuffer(
|
||||
0, "cb_draw_constants_static"))
|
||||
.Add(MaResourceMapping::PushConstants<PushConstantsDraw>(1))
|
||||
.Add(texture_mapping_shadow)
|
||||
.Add(sampler_mapping_shadow);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
pipeline_desc.setPixelShader(pixel_shader)
|
||||
@@ -181,6 +202,7 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
|
||||
pipeline_desc.setInputLayout(
|
||||
m_renderer->m_input_layout[static_cast<size_t>(draw)]);
|
||||
switch (pass) {
|
||||
case RenderPassType::DepthOnly:
|
||||
case RenderPassType::Deferred:
|
||||
case RenderPassType::Forward:
|
||||
pipeline_desc.setVertexShader(
|
||||
@@ -193,6 +215,7 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
|
||||
default:;
|
||||
}
|
||||
switch (pass) {
|
||||
case RenderPassType::DepthOnly:
|
||||
case RenderPassType::Deferred:
|
||||
case RenderPassType::Forward:
|
||||
mappings.Add(MaResourceMapping::PushConstants<PushConstantsDraw>(1))
|
||||
@@ -219,13 +242,18 @@ 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"))
|
||||
.Add(MaResourceMapping::StructuredBuffer_SRV(17, "forwardplus_index_buffer_transparent"))
|
||||
.Add(MaResourceMapping::StructuredBuffer_SRV(18, "forwardplus_light_buffer"))
|
||||
.Add(MaResourceMapping::Texture_SRV(
|
||||
16, "forwardplus_index_grid_transparent"))
|
||||
.Add(MaResourceMapping::StructuredBuffer_SRV(
|
||||
17, "forwardplus_index_buffer_transparent"))
|
||||
.Add(MaResourceMapping::StructuredBuffer_SRV(
|
||||
18, "forwardplus_light_buffer"))
|
||||
.Add(MaResourceMapping::Sampler(8, "sampler_linear_wrap"))
|
||||
.Add(MaResourceMapping::Sampler(11, "shadow_sampler_comp"))
|
||||
.Add(MaResourceMapping::Sampler(13, "sampler_linear_clamp_v_repeat_h"));
|
||||
.Add(MaResourceMapping::Sampler(
|
||||
13, "sampler_linear_clamp_v_repeat_h"));
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
@@ -243,7 +271,22 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
|
||||
}
|
||||
switch (pass) {
|
||||
case RenderPassType::Deferred:
|
||||
case RenderPassType::CubeMap:
|
||||
pipeline_desc.setRenderState(
|
||||
nvrhi::RenderState()
|
||||
.setDepthStencilState(
|
||||
nvrhi::DepthStencilState()
|
||||
.enableDepthTest()
|
||||
.disableStencil()
|
||||
.setDepthFunc(nvrhi::ComparisonFunc::Equal))
|
||||
.setRasterState(nvrhi::RasterState()
|
||||
.setFillSolid()
|
||||
.enableDepthClip()
|
||||
.disableScissor()
|
||||
.setCullFront())
|
||||
.setBlendState(nvrhi::BlendState().setRenderTarget(
|
||||
0, nvrhi::BlendState::RenderTarget().disableBlend())));
|
||||
break;
|
||||
case RenderPassType::CubeMap:
|
||||
pipeline_desc.setRenderState(
|
||||
nvrhi::RenderState()
|
||||
.setDepthStencilState(
|
||||
@@ -260,8 +303,8 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
|
||||
.setBlendState(nvrhi::BlendState().setRenderTarget(
|
||||
0, nvrhi::BlendState::RenderTarget().disableBlend())));
|
||||
break;
|
||||
case RenderPassType::Forward:
|
||||
pipeline_desc.setRenderState(
|
||||
case RenderPassType::Forward: {
|
||||
auto render_state =
|
||||
nvrhi::RenderState()
|
||||
.setDepthStencilState(
|
||||
nvrhi::DepthStencilState()
|
||||
@@ -273,19 +316,25 @@ void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
|
||||
.setFillSolid()
|
||||
.enableDepthClip()
|
||||
.disableScissor()
|
||||
.setCullFront())
|
||||
.setBlendState(
|
||||
nvrhi::BlendState()
|
||||
.setRenderTarget(
|
||||
0, nvrhi::BlendState::RenderTarget()
|
||||
.enableBlend()
|
||||
.setBlendOp(nvrhi::BlendOp::Add)
|
||||
.setSrcBlend(nvrhi::BlendFactor::One)
|
||||
.setDestBlend(
|
||||
nvrhi::BlendFactor::OneMinusSrcAlpha))
|
||||
.setRenderTarget(1, nvrhi::BlendState::RenderTarget()
|
||||
.disableBlend())));
|
||||
break;
|
||||
.setCullFront());
|
||||
if (m_enable_refraction) {
|
||||
render_state.setBlendState(nvrhi::BlendState().setRenderTarget(
|
||||
0, nvrhi::BlendState::RenderTarget().disableBlend()));
|
||||
} else {
|
||||
render_state.setBlendState(
|
||||
nvrhi::BlendState()
|
||||
.setRenderTarget(
|
||||
0,
|
||||
nvrhi::BlendState::RenderTarget()
|
||||
.enableBlend()
|
||||
.setBlendOp(nvrhi::BlendOp::Add)
|
||||
.setSrcBlend(nvrhi::BlendFactor::One)
|
||||
.setDestBlend(nvrhi::BlendFactor::OneMinusSrcAlpha))
|
||||
.setRenderTarget(
|
||||
1, nvrhi::BlendState::RenderTarget().disableBlend()));
|
||||
}
|
||||
pipeline_desc.setRenderState(render_state);
|
||||
} break;
|
||||
default:;
|
||||
}
|
||||
|
||||
@@ -419,8 +468,14 @@ bool NvRenderer::InitMaterials() {
|
||||
|
||||
m_vertex_shader[static_cast<size_t>(DrawType::Model)] =
|
||||
m_backend->CreateShader("default_vertex", nvrhi::ShaderType::Vertex);
|
||||
m_vertex_shader_prepass[static_cast<size_t>(DrawType::Model)] =
|
||||
m_backend->CreateShader("default_prepass_vertex",
|
||||
nvrhi::ShaderType::Vertex);
|
||||
m_vertex_shader[static_cast<size_t>(DrawType::InstancedModel)] =
|
||||
m_backend->CreateShader("instanced_vertex", nvrhi::ShaderType::Vertex);
|
||||
m_vertex_shader_prepass[static_cast<size_t>(DrawType::InstancedModel)] =
|
||||
m_backend->CreateShader("instanced_prepass_vertex",
|
||||
nvrhi::ShaderType::Vertex);
|
||||
m_vertex_shader_shadow[static_cast<size_t>(DrawType::Model)] =
|
||||
m_backend->CreateShader("shadow_vertex", nvrhi::ShaderType::Vertex);
|
||||
m_vertex_shader_shadow[static_cast<size_t>(DrawType::InstancedModel)] =
|
||||
@@ -433,6 +488,8 @@ bool NvRenderer::InitMaterials() {
|
||||
nvrhi::ShaderType::Vertex);
|
||||
m_pixel_shader_shadow_masked =
|
||||
m_backend->CreateShader("shadow_masked", nvrhi::ShaderType::Pixel);
|
||||
m_pixel_shader_prepass_masked =
|
||||
m_backend->CreateShader("prepass_masked", nvrhi::ShaderType::Pixel);
|
||||
|
||||
nvrhi::VertexAttributeDesc desc[]{
|
||||
nvrhi::VertexAttributeDesc()
|
||||
@@ -481,55 +538,82 @@ bool NvRenderer::InitMaterials() {
|
||||
m_vertex_shader[static_cast<size_t>(DrawType::InstancedModel)]);
|
||||
|
||||
{
|
||||
m_binding_layout_shadow_masked =
|
||||
m_backend->GetDevice()->createBindingLayout(
|
||||
nvrhi::BindingLayoutDesc()
|
||||
.setVisibility(nvrhi::ShaderType::Pixel)
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(0)));
|
||||
auto constexpr render_state_shadow =
|
||||
nvrhi::RenderState()
|
||||
.setDepthStencilState(
|
||||
nvrhi::DepthStencilState()
|
||||
.enableDepthTest()
|
||||
.enableDepthWrite()
|
||||
.disableStencil()
|
||||
.setDepthFunc(nvrhi::ComparisonFunc::Greater))
|
||||
.setRasterState(nvrhi::RasterState()
|
||||
.setFillSolid()
|
||||
.disableDepthClip()
|
||||
.disableScissor()
|
||||
.setCullBack()
|
||||
.setDepthBias(1)
|
||||
.setSlopeScaleDepthBias(-4.f))
|
||||
.setBlendState(nvrhi::BlendState().setRenderTarget(
|
||||
0, nvrhi::BlendState::RenderTarget().disableBlend()));
|
||||
auto constexpr render_state_depthonly =
|
||||
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()));
|
||||
for (int i = 0; i < Constants::NumDrawTypes(); ++i) {
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
DrawType draw = static_cast<DrawType>(i);
|
||||
bool masked = j;
|
||||
nvrhi::BindingLayoutDesc desc =
|
||||
nvrhi::BindingLayoutDesc desc_shadow =
|
||||
*m_binding_layout_shadowdrawconstants->getDesc();
|
||||
desc.visibility = nvrhi::ShaderType::All;
|
||||
if (masked)
|
||||
desc.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(0));
|
||||
auto binding_layout =
|
||||
GetBackend()->GetDevice()->createBindingLayout(desc);
|
||||
auto pipeline_desc =
|
||||
nvrhi::GraphicsPipelineDesc()
|
||||
.setRenderState(
|
||||
nvrhi::RenderState()
|
||||
.setDepthStencilState(
|
||||
nvrhi::DepthStencilState()
|
||||
.enableDepthTest()
|
||||
.enableDepthWrite()
|
||||
.disableStencil()
|
||||
.setDepthFunc(nvrhi::ComparisonFunc::Greater))
|
||||
.setRasterState(nvrhi::RasterState()
|
||||
.setFillSolid()
|
||||
.disableDepthClip()
|
||||
.disableScissor()
|
||||
.setCullBack()
|
||||
.setDepthBias(1)
|
||||
.setSlopeScaleDepthBias(-4.f))
|
||||
.setBlendState(nvrhi::BlendState().setRenderTarget(
|
||||
0,
|
||||
nvrhi::BlendState::RenderTarget().disableBlend())))
|
||||
.setVertexShader(
|
||||
m_vertex_shader_shadow[static_cast<size_t>(draw)])
|
||||
.setInputLayout(m_input_layout[static_cast<size_t>(draw)]);
|
||||
nvrhi::BindingLayoutDesc desc_prepass =
|
||||
*m_binding_layout_drawconstants->getDesc();
|
||||
desc_shadow.visibility = nvrhi::ShaderType::All;
|
||||
desc_prepass.visibility = nvrhi::ShaderType::All;
|
||||
if (masked) {
|
||||
pipeline_desc.setPixelShader(m_pixel_shader_shadow_masked);
|
||||
desc_shadow.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(0));
|
||||
desc_prepass.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(0));
|
||||
}
|
||||
pipeline_desc.addBindingLayout(binding_layout);
|
||||
auto binding_layout_shadow =
|
||||
GetBackend()->GetDevice()->createBindingLayout(desc_shadow);
|
||||
auto binding_layout_prepass =
|
||||
GetBackend()->GetDevice()->createBindingLayout(desc_prepass);
|
||||
auto pipeline_desc = nvrhi::GraphicsPipelineDesc().setInputLayout(
|
||||
m_input_layout[static_cast<size_t>(draw)]);
|
||||
|
||||
m_pso_shadow[Constants::GetDefaultShadowPipelineIndex(draw, masked)] =
|
||||
GetBackend()->GetDevice()->createGraphicsPipeline(
|
||||
pipeline_desc, m_gbuffer_shadow->m_framebuffer);
|
||||
nvrhi::GraphicsPipelineDesc(pipeline_desc)
|
||||
.setRenderState(render_state_shadow)
|
||||
.setVertexShader(
|
||||
m_vertex_shader_shadow[static_cast<size_t>(draw)])
|
||||
.setPixelShader(masked ? m_pixel_shader_shadow_masked
|
||||
: nullptr)
|
||||
.addBindingLayout(binding_layout_shadow),
|
||||
m_gbuffer_shadow->m_framebuffer);
|
||||
|
||||
m_pso_prepass[Constants::GetDefaultShadowPipelineIndex(draw, masked)] =
|
||||
GetBackend()->GetDevice()->createGraphicsPipeline(
|
||||
nvrhi::GraphicsPipelineDesc(pipeline_desc)
|
||||
.setVertexShader(
|
||||
m_vertex_shader_prepass[static_cast<size_t>(draw)])
|
||||
.setPixelShader(masked ? m_pixel_shader_prepass_masked
|
||||
: nullptr)
|
||||
.setRenderState(render_state_depthonly)
|
||||
.addBindingLayout(binding_layout_prepass),
|
||||
m_gbuffer->m_framebuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -381,12 +386,21 @@ bool NvRenderer::Render() {
|
||||
(static_cast<glm::dvec2>(Global.cursor_pos) /
|
||||
static_cast<glm::dvec2>(Global.window_size) -
|
||||
.5);
|
||||
m_mouse_ro = pass.m_origin;
|
||||
glm::dvec4 mouse_rd_norm =
|
||||
inverse(projection) * glm::dvec4(mousepos, 1., 1.);
|
||||
mouse_rd_norm /= mouse_rd_norm.w;
|
||||
m_mouse_rd =
|
||||
normalize(inverse(transform) * glm::dvec4(mouse_rd_norm.xyz, 0.));
|
||||
{
|
||||
glm::dvec4 mouse_ro_norm =
|
||||
inverse(projection) * glm::dvec4(mousepos, 1., 1.);
|
||||
mouse_ro_norm /= mouse_ro_norm.w;
|
||||
m_mouse_ro = pass.m_origin + static_cast<glm::dvec3>(
|
||||
inverse(transform) *
|
||||
glm::dvec4(mouse_ro_norm.xyz, 1.));
|
||||
}
|
||||
{
|
||||
glm::dvec4 mouse_rd_norm =
|
||||
inverse(projection) * glm::dvec4(mousepos, 0., 1.);
|
||||
mouse_rd_norm /= mouse_rd_norm.w;
|
||||
m_mouse_rd =
|
||||
normalize(inverse(transform) * glm::dvec4(mouse_rd_norm.xyz, 0.));
|
||||
}
|
||||
}
|
||||
|
||||
m_picked_submodel = nullptr;
|
||||
@@ -413,6 +427,18 @@ bool NvRenderer::Render() {
|
||||
pass.m_history_transform =
|
||||
std::exchange(m_previous_view, pass.m_transform);
|
||||
|
||||
command_list->beginMarker("Depth only");
|
||||
pass.m_type = RenderPassType::DepthOnly;
|
||||
RenderKabina(pass);
|
||||
RenderShapes(pass);
|
||||
RenderBatches(pass);
|
||||
RenderTracks(pass);
|
||||
RenderAnimateds(pass);
|
||||
RenderLines(pass);
|
||||
command_list->endMarker();
|
||||
|
||||
command_list->beginMarker("Gbuffer fill");
|
||||
pass.m_type = RenderPassType::Deferred;
|
||||
Timer::subsystem.gfx_color.start();
|
||||
RenderKabina(pass);
|
||||
RenderShapes(pass);
|
||||
@@ -420,6 +446,7 @@ bool NvRenderer::Render() {
|
||||
RenderTracks(pass);
|
||||
RenderAnimateds(pass);
|
||||
RenderLines(pass);
|
||||
command_list->endMarker();
|
||||
|
||||
GatherSpotLights(pass);
|
||||
|
||||
@@ -618,6 +645,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;
|
||||
@@ -991,19 +1019,23 @@ material_handle NvRenderer::Fetch_Material(std::string const &Filename,
|
||||
auto texture_manager = GetTextureManager();
|
||||
|
||||
for (int i = 0; i < material_template->m_texture_bindings.size(); ++i) {
|
||||
const auto &[key, sampler_key, hint, m_default_texture] =
|
||||
material_template->m_texture_bindings[i];
|
||||
const auto &binding = material_template->m_texture_bindings[i];
|
||||
auto handle = texture_manager->FetchTexture(
|
||||
static_cast<std::string>(adapter.GetTexturePathForEntry(key)), hint,
|
||||
adapter.GetTextureSizeBiasForEntry(key), true);
|
||||
static_cast<std::string>(
|
||||
adapter.GetTexturePathForEntry(binding.m_name)),
|
||||
binding.m_hint, adapter.GetTextureSizeBiasForEntry(binding.m_name),
|
||||
true);
|
||||
cache.m_texture_handles[i] = handle;
|
||||
cache.RegisterTexture(key.c_str(), handle);
|
||||
cache.RegisterResource(false, sampler_key.c_str(),
|
||||
auto traits = texture_manager->GetTraits(handle);
|
||||
traits[MaTextureTraits_NoFilter] = binding.disable_filter;
|
||||
traits[MaTextureTraits_NoAnisotropy] = binding.disable_anisotropy;
|
||||
traits[MaTextureTraits_NoMipBias] = binding.disable_mip_bias;
|
||||
cache.RegisterTexture(binding.m_name.c_str(), handle);
|
||||
cache.RegisterResource(false, binding.m_sampler_name.c_str(),
|
||||
texture_manager->GetSamplerForTraits(
|
||||
texture_manager->GetTraits(handle),
|
||||
NvRenderer::RenderPassType::Deferred),
|
||||
traits, RenderPassType::Deferred),
|
||||
nvrhi::ResourceType::Sampler);
|
||||
if (key == cache.m_template->m_masked_shadow_texture &&
|
||||
if (binding.m_name == cache.m_template->m_masked_shadow_texture &&
|
||||
texture_manager->IsValidHandle(handle)) {
|
||||
cache.m_masked_shadow =
|
||||
texture_manager->GetTexture(handle)->m_has_alpha;
|
||||
@@ -1298,6 +1330,8 @@ void NvRenderer::DebugUi() {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Bloom Config")) m_bloom->ShowGui();
|
||||
ImGui::SameLine();
|
||||
m_ssao->OnGui(ImGui::Button("GTAO Config"));
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Take Screenshot")) MakeScreenshot();
|
||||
}
|
||||
ImGui::End();
|
||||
@@ -1495,6 +1529,7 @@ void NvRenderer::UpdateDrawData(const RenderPass &pass,
|
||||
pass.m_command_list_draw->setPushConstants(&data, sizeof(data));
|
||||
break;
|
||||
}
|
||||
case RenderPassType::DepthOnly:
|
||||
case RenderPassType::Deferred:
|
||||
case RenderPassType::Forward: {
|
||||
PushConstantsDraw data{};
|
||||
@@ -1560,13 +1595,17 @@ void NvRenderer::BindConstants(const RenderPass &pass,
|
||||
bool NvRenderer::BindMaterial(material_handle handle, DrawType draw_type,
|
||||
const RenderPass &pass,
|
||||
nvrhi::GraphicsState &gfx_state,
|
||||
float &alpha_threshold) {
|
||||
float &alpha_threshold, bool *out_is_refractive) {
|
||||
if (pass.m_type == RenderPassType::RendererWarmUp) return true;
|
||||
if (!handle || handle > m_material_cache.size()) {
|
||||
return false;
|
||||
}
|
||||
MaterialCache &cache = m_material_cache[handle - 1];
|
||||
|
||||
if(out_is_refractive) {
|
||||
*out_is_refractive = cache.m_template->m_enable_refraction;
|
||||
}
|
||||
|
||||
if (!cache.ShouldRenderInPass(pass)) return false;
|
||||
|
||||
auto pipeline_index = Constants::GetPipelineIndex(pass.m_type, draw_type);
|
||||
@@ -1967,6 +2006,8 @@ void NvRenderer::Animate(Renderable &renderable, TSubModel *Submodel,
|
||||
m_batched_instances.end()) {
|
||||
auto &item = renderable.m_items.emplace_back();
|
||||
|
||||
item.m_name = Submodel->pName.c_str();
|
||||
|
||||
auto &motion_cache = m_motion_cache->Get(Submodel);
|
||||
|
||||
motion_cache.m_history_transform =
|
||||
|
||||
@@ -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;
|
||||
@@ -493,10 +506,16 @@ nvrhi::SamplerHandle NvTextureManager::GetSamplerForTraits(
|
||||
.setAddressV(traits[MaTextureTraits_ClampT]
|
||||
? nvrhi::SamplerAddressMode::Clamp
|
||||
: nvrhi::SamplerAddressMode::Wrap)
|
||||
.setAllFilters(true)
|
||||
.setAllFilters(!traits[MaTextureTraits_NoFilter])
|
||||
.setMipFilter(false)
|
||||
.setMaxAnisotropy(traits[MaTextureTraits_NoAnisotropy] ? 0.f : 16.f)
|
||||
.setMipBias(traits[MaTextureTraits_NoMipBias] ? 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;
|
||||
|
||||
@@ -16,6 +16,7 @@ enum MaTextureTraits {
|
||||
|
||||
MaTextureTraits_NoMipBias,
|
||||
MaTextureTraits_NoAnisotropy,
|
||||
MaTextureTraits_NoFilter,
|
||||
|
||||
MaTextureTraits_Num
|
||||
};
|
||||
@@ -82,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);
|
||||
|
||||
@@ -137,7 +137,9 @@ const TSubModel* Rt::RtModel::Intersect(
|
||||
[&](size_t const begin, size_t const end) {
|
||||
for (size_t i = begin; i < end; ++i) {
|
||||
size_t const j = submodel.bvh.prim_ids[i];
|
||||
if (auto hit = submodel.tris[j].intersect(ray)) {
|
||||
if (auto hit = submodel.tris[j].intersect(ray);
|
||||
!!hit && dot(rd_local, glm::make_vec3(
|
||||
submodel.tris[j].n.values)) > 0.) {
|
||||
prim_id = i;
|
||||
std::tie(ray.tmax, u, v) = *hit;
|
||||
result = submodel.submodel;
|
||||
|
||||
@@ -78,7 +78,7 @@ void NvSsao::Init() {
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setFormat(Format::R8_UINT)
|
||||
.setFormat(Format::R32_UINT)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
@@ -88,7 +88,7 @@ void NvSsao::Init() {
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setFormat(Format::R8_UINT)
|
||||
.setFormat(Format::R32_UINT)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
@@ -98,15 +98,16 @@ void NvSsao::Init() {
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setFormat(Format::R8_UNORM)
|
||||
.setFormat(Format::RGBA8_UNORM)
|
||||
.setIsTypeless(true)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
SamplerHandle sampler_point = m_SamplerPoint = m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc()
|
||||
.setAllAddressModes(SamplerAddressMode::Clamp)
|
||||
.setAllFilters(false));
|
||||
SamplerHandle sampler_point = m_SamplerPoint =
|
||||
m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc()
|
||||
.setAllAddressModes(SamplerAddressMode::Clamp)
|
||||
.setAllFilters(false));
|
||||
|
||||
{
|
||||
BindingLayoutHandle blPrefilterDepths;
|
||||
@@ -136,17 +137,19 @@ void NvSsao::Init() {
|
||||
BindingSetDesc()
|
||||
.addItem(BindingSetItem::ConstantBuffer(0, m_constantBuffer))
|
||||
.addItem(BindingSetItem ::Texture_SRV(0, m_workingDepths))
|
||||
.addItem(
|
||||
BindingSetItem::Texture_SRV(1, m_gbuffer->m_gbuffer_normal))
|
||||
.addItem(BindingSetItem::Texture_UAV(0, m_workingAOTerm))
|
||||
.addItem(BindingSetItem::Texture_UAV(1, m_workingEdges))
|
||||
.addItem(BindingSetItem::Texture_UAV(2, m_debugImage))
|
||||
.addItem(BindingSetItem::Sampler(0, sampler_point)),
|
||||
blGTAO, m_BSGTAO);
|
||||
m_PSOGTAO = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.setComputeShader(m_CSGTAOHigh)
|
||||
.addBindingLayout(blGTAO));
|
||||
std::array<IShader*, 4> const shaders{m_CSGTAOLow, m_CSGTAOMedium,
|
||||
m_CSGTAOHigh, m_CSGTAOUltra};
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
m_PSOGTAO[i] = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.setComputeShader(shaders[i])
|
||||
.addBindingLayout(blGTAO));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -187,12 +190,8 @@ void NvSsao::Render(nvrhi::ICommandList* command_list,
|
||||
command_list->beginMarker("XeGTAO");
|
||||
|
||||
XeGTAO::GTAOConstants constants{};
|
||||
XeGTAO::GTAOSettings settings{};
|
||||
settings.QualityLevel = 2;
|
||||
settings.Radius = 10.f;
|
||||
settings.ThinOccluderCompensation = .7f;
|
||||
XeGTAO::GTAOUpdateConstants(constants, m_width, m_height, settings,
|
||||
glm::value_ptr(projection), false, frame_index);
|
||||
projection, false, frame_index);
|
||||
command_list->writeBuffer(m_constantBuffer, &constants, sizeof(constants));
|
||||
|
||||
{
|
||||
@@ -210,7 +209,7 @@ void NvSsao::Render(nvrhi::ICommandList* command_list,
|
||||
{
|
||||
command_list->beginMarker("Main Pass");
|
||||
nvrhi::ComputeState state;
|
||||
state.setPipeline(m_PSOGTAO);
|
||||
state.setPipeline(m_PSOGTAO[glm::clamp(settings.QualityLevel, 0, 3)]);
|
||||
state.addBindingSet(m_BSGTAO);
|
||||
|
||||
command_list->setComputeState(state);
|
||||
@@ -222,7 +221,7 @@ void NvSsao::Render(nvrhi::ICommandList* command_list,
|
||||
|
||||
{
|
||||
command_list->beginMarker("Denoise Pass");
|
||||
int num_passes = 4;
|
||||
int num_passes = settings.DenoisePasses;
|
||||
nvrhi::ITexture* ping = m_workingAOTerm;
|
||||
nvrhi::ITexture* pong = m_workingAOTermPong;
|
||||
for (int i = 0; i < num_passes; ++i) {
|
||||
@@ -233,11 +232,10 @@ void NvSsao::Render(nvrhi::ICommandList* command_list,
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(0, m_constantBuffer))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(0, ping))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
1, m_gbuffer->m_gbuffer_normal))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(1, m_workingEdges))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(
|
||||
0, last_pass ? m_outputAO.Get() : pong,
|
||||
nvrhi::Format::R8_UINT))
|
||||
nvrhi::Format::R32_UINT))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(1, m_workingEdges))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(2, m_debugImage))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(0, m_SamplerPoint)),
|
||||
@@ -260,3 +258,25 @@ void NvSsao::Render(nvrhi::ICommandList* command_list,
|
||||
}
|
||||
command_list->endMarker();
|
||||
}
|
||||
|
||||
void NvSsao::OnGui(bool const open_now) {
|
||||
static bool open = false;
|
||||
open |= open_now;
|
||||
if (open && ImGui::Begin("GTAO Settings", &open)) {
|
||||
ImGui::InputInt("Quality level", &settings.QualityLevel);
|
||||
ImGui::InputInt("Denoise passes", &settings.DenoisePasses);
|
||||
ImGui::InputFloat("Radius", &settings.Radius);
|
||||
if (ImGui::CollapsingHeader("Advanced")) {
|
||||
ImGui::InputFloat("Radius multiplier", &settings.RadiusMultiplier);
|
||||
ImGui::InputFloat("Falloff range", &settings.FalloffRange);
|
||||
ImGui::InputFloat("Sample distribution power",
|
||||
&settings.SampleDistributionPower);
|
||||
ImGui::InputFloat("Thin occluder compensation",
|
||||
&settings.ThinOccluderCompensation);
|
||||
ImGui::InputFloat("Final value power", &settings.FinalValuePower);
|
||||
ImGui::InputFloat("Depth MIP sampling offset",
|
||||
&settings.DepthMIPSamplingOffset);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
#include "XeGTAO.h"
|
||||
|
||||
struct NvSsao {
|
||||
NvSsao(class NvRenderer* renderer);
|
||||
void Init();
|
||||
|
||||
XeGTAO::GTAOSettings settings{};
|
||||
|
||||
class NvRendererBackend* m_backend;
|
||||
struct NvGbuffer* m_gbuffer;
|
||||
|
||||
@@ -23,7 +26,7 @@ struct NvSsao {
|
||||
nvrhi::ShaderHandle m_CSGTAOMedium;
|
||||
nvrhi::ShaderHandle m_CSGTAOHigh;
|
||||
nvrhi::ShaderHandle m_CSGTAOUltra;
|
||||
nvrhi::ComputePipelineHandle m_PSOGTAO;
|
||||
std::array<nvrhi::ComputePipelineHandle, 4> m_PSOGTAO;
|
||||
nvrhi::BindingSetHandle m_BSGTAO;
|
||||
|
||||
nvrhi::ShaderHandle m_CSDenoisePass;
|
||||
@@ -52,4 +55,6 @@ struct NvSsao {
|
||||
|
||||
void Render(nvrhi::ICommandList* command_list, const glm::mat4& projection,
|
||||
size_t frame_index);
|
||||
|
||||
void OnGui(bool open_now);
|
||||
};
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "config.h"
|
||||
#include "gbufferblitpass.h"
|
||||
#include "motioncache.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
#include <Timer.h>
|
||||
#include <AnimModel.h>
|
||||
#include <simulation.h>
|
||||
|
||||
@@ -959,13 +961,19 @@ void NvRenderer::RenderAnimateds(const RenderPass& pass) {
|
||||
switch (command.m_type) {
|
||||
case RenderCommand::ObjectType_Animated:
|
||||
m_drawcall_counter = &m_drawcalls_tanimobj;
|
||||
pass.m_command_list_draw->beginMarker(
|
||||
m_animateds[command.m_index].m_model->name().c_str());
|
||||
Render(m_animateds[command.m_index].m_renderable, pass, history_origin,
|
||||
m_animateds[command.m_index].m_distance);
|
||||
pass.m_command_list_draw->endMarker();
|
||||
break;
|
||||
case RenderCommand::ObjectType_Dynamic:
|
||||
m_drawcall_counter = &m_drawcalls_dynamic;
|
||||
pass.m_command_list_draw->beginMarker(
|
||||
m_dynamics[command.m_index].m_dynamic->name().c_str());
|
||||
Render(m_dynamics[command.m_index].m_renderable, pass, history_origin,
|
||||
m_dynamics[command.m_index].m_distance);
|
||||
pass.m_command_list_draw->endMarker();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -989,7 +997,9 @@ void NvRenderer::RenderKabina(const RenderPass& pass) {
|
||||
default:
|
||||
if (!dynamic.m_renderable_kabina.m_render_in_deferred) return;
|
||||
}
|
||||
pass.m_command_list_draw->beginMarker("Render cab");
|
||||
Render(dynamic.m_renderable_kabina, pass, history_origin, dynamic.m_distance);
|
||||
pass.m_command_list_draw->endMarker();
|
||||
}
|
||||
|
||||
void NvRenderer::Render(const Renderable& renderable, const RenderPass& pass,
|
||||
@@ -1006,16 +1016,23 @@ void NvRenderer::Render(const Renderable& renderable, const RenderPass& pass,
|
||||
nvrhi::GraphicsState gfx_state;
|
||||
nvrhi::DrawArguments draw_arguments{};
|
||||
bool indexed;
|
||||
bool refractive;
|
||||
float alpha_threshold;
|
||||
if (!BindGeometry(item.m_geometry, pass, gfx_state, draw_arguments,
|
||||
indexed))
|
||||
return;
|
||||
continue;
|
||||
if (!BindMaterial(item.m_material, DrawType::Model, pass, gfx_state,
|
||||
alpha_threshold))
|
||||
return;
|
||||
alpha_threshold, &refractive))
|
||||
continue;
|
||||
|
||||
BindConstants(pass, gfx_state);
|
||||
|
||||
pass.m_command_list_draw->beginMarker(item.m_name.data());
|
||||
|
||||
if(refractive && pass.m_type == RenderPassType::Forward) {
|
||||
m_gbuffer_blit->UpdateSceneColorForRefraction(pass.m_command_list_draw);
|
||||
}
|
||||
|
||||
pass.m_command_list_draw->setGraphicsState(gfx_state);
|
||||
|
||||
auto transform = item.m_transform;
|
||||
@@ -1034,11 +1051,14 @@ void NvRenderer::Render(const Renderable& renderable, const RenderPass& pass,
|
||||
else
|
||||
pass.m_command_list_draw->draw(draw_arguments);
|
||||
m_drawcall_counter->Draw(draw_arguments);
|
||||
|
||||
pass.m_command_list_draw->endMarker();
|
||||
}
|
||||
}
|
||||
|
||||
void NvRenderer::Animate(const glm::dvec3& origin, double radius,
|
||||
uint64_t frame) {
|
||||
Timer::subsystem.gfx_animate.start();
|
||||
{
|
||||
auto motion_scope = m_motion_cache->SetInstance(nullptr);
|
||||
auto& motion_cache = m_motion_cache->Get(nullptr);
|
||||
@@ -1077,6 +1097,7 @@ void NvRenderer::Animate(const glm::dvec3& origin, double radius,
|
||||
if (!instance.m_animatable && instance.m_was_once_animated) return;
|
||||
Animate(instance, origin, frame);
|
||||
});
|
||||
Timer::subsystem.gfx_animate.stop();
|
||||
}
|
||||
|
||||
void NvRenderer::GatherSpotLights(const RenderPass& pass) {
|
||||
|
||||
246
betterRenderer/renderer/source/windshield_rain.cpp
Normal file
246
betterRenderer/renderer/source/windshield_rain.cpp
Normal 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);
|
||||
}
|
||||
46
betterRenderer/renderer/source/windshield_rain.h
Normal file
46
betterRenderer/renderer/source/windshield_rain.h
Normal 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;
|
||||
};
|
||||
@@ -54,6 +54,7 @@ SamplerState g_samplerPointClamp : register( s0 );
|
||||
// Engine-specific normal map loader
|
||||
lpfloat3 LoadNormal( int2 pos )
|
||||
{
|
||||
return (float3)0.;
|
||||
#if 0
|
||||
// special decoding for external normals stored in 11_11_10 unorm - modify appropriately to support your own encoding
|
||||
uint packedInput = g_srcNormalmap.Load( int3(pos, 0) ).x;
|
||||
|
||||
@@ -111,11 +111,10 @@ float3 XeGTAO_ComputeViewspacePosition( const float2 screenPos, const float view
|
||||
|
||||
float XeGTAO_ScreenSpaceToViewSpaceDepth( const float screenDepth, const GTAOConstants consts )
|
||||
{
|
||||
float depthLinearizeMul = consts.DepthUnpackConsts.x;
|
||||
float depthLinearizeAdd = consts.DepthUnpackConsts.y;
|
||||
// Optimised version of "-cameraClipNear / (cameraClipFar - projDepth * (cameraClipFar - cameraClipNear)) * cameraClipFar"
|
||||
//return 2500. / (.1 - screenDepth * (.1 - 2500.)) * .1;
|
||||
return depthLinearizeMul / (depthLinearizeAdd - screenDepth);
|
||||
float depthLinearizeMul = consts.DepthUnpackConsts.x;
|
||||
float depthLinearizeAdd = consts.DepthUnpackConsts.y;
|
||||
// Optimised version of "-cameraClipNear / (cameraClipFar - projDepth * (cameraClipFar - cameraClipNear)) * cameraClipFar"
|
||||
return depthLinearizeMul / (depthLinearizeAdd - screenDepth);
|
||||
}
|
||||
|
||||
lpfloat4 XeGTAO_CalculateEdges( const lpfloat centerZ, const lpfloat leftZ, const lpfloat rightZ, const lpfloat topZ, const lpfloat bottomZ )
|
||||
|
||||
15
betterRenderer/shaders/cs_downsample_depth.hlsl
Normal file
15
betterRenderer/shaders/cs_downsample_depth.hlsl
Normal file
@@ -0,0 +1,15 @@
|
||||
Texture2D<float> g_DepthTexture : register(t0);
|
||||
RWTexture2D<float> g_Output : register(u0);
|
||||
sampler depth_sampler : register(s0);
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void main(uint3 PixCoord : SV_DispatchThreadID) {
|
||||
uint2 dimensions;
|
||||
g_Output.GetDimensions(dimensions.x, dimensions.y);
|
||||
|
||||
float2 co = float2(PixCoord.xy) / float2(dimensions);
|
||||
|
||||
float4 depths = g_DepthTexture.GatherRed(depth_sampler, co);
|
||||
g_Output[PixCoord.xy] = min(min(depths.x, depths.y), min(depths.z, depths.w));
|
||||
}
|
||||
|
||||
@@ -7,6 +7,12 @@ struct VertexInput {
|
||||
float4 m_Tangent : Tangent;
|
||||
};
|
||||
|
||||
#ifdef PREPASS
|
||||
struct VertexOutput {
|
||||
float2 m_TexCoord : TexCoord;
|
||||
float4 m_PositionSV : SV_Position;
|
||||
};
|
||||
#else
|
||||
struct VertexOutput {
|
||||
float3 m_Position : Position;
|
||||
float3 m_Normal : Normal;
|
||||
@@ -16,6 +22,7 @@ struct VertexOutput {
|
||||
float4 m_PositionCS : PositionCS;
|
||||
float4 m_HistoryPositionCS : HistoryPositionCS;
|
||||
};
|
||||
#endif
|
||||
|
||||
cbuffer VertexConstants : register(b0) {
|
||||
float4x4 g_JitteredProjection;
|
||||
@@ -25,18 +32,27 @@ cbuffer VertexConstants : register(b0) {
|
||||
|
||||
#include "manul/draw_constants.hlsli"
|
||||
|
||||
#ifdef NO_JITTER
|
||||
#define PROJECTION g_Projection
|
||||
#else
|
||||
#define PROJECTION g_JitteredProjection
|
||||
#endif
|
||||
|
||||
VertexOutput main(in VertexInput vs_in) {
|
||||
VertexOutput result;
|
||||
float4x3 model_view = GetModelView();
|
||||
float4x3 model_view_history = GetModelViewHistory();
|
||||
result.m_Position = mul(float4(vs_in.m_Position, 1.), model_view).xyz;
|
||||
result.m_Normal = mul(float4(vs_in.m_Normal, 0.), model_view).xyz;
|
||||
float3 view_space_position = mul(float4(vs_in.m_Position, 1.), model_view).xyz;
|
||||
result.m_TexCoord = vs_in.m_TexCoord;
|
||||
result.m_PositionSV = mul(PROJECTION, float4(view_space_position, 1.));
|
||||
#ifndef PREPASS
|
||||
result.m_Normal = mul(float4(vs_in.m_Normal, 0.), model_view).xyz;
|
||||
result.m_Position = view_space_position;
|
||||
result.m_Tangent.xyz = mul(float4(vs_in.m_Tangent.xyz, 0.), model_view).xyz;
|
||||
result.m_Tangent.w = vs_in.m_Tangent.w;
|
||||
result.m_PositionSV = mul(g_JitteredProjection, float4(result.m_Position, 1.));
|
||||
result.m_PositionCS = mul(g_Projection, float4(result.m_Position, 1.));
|
||||
float3 history_position = mul(float4(vs_in.m_Position, 1.), model_view_history);
|
||||
result.m_HistoryPositionCS = mul(g_ProjectionHistory, float4(history_position, 1.));
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,12 @@ struct VertexInput {
|
||||
float4 m_InstanceTransform[3] : InstanceTransform;
|
||||
};
|
||||
|
||||
#ifdef PREPASS
|
||||
struct VertexOutput {
|
||||
float2 m_TexCoord : TexCoord;
|
||||
float4 m_PositionSV : SV_Position;
|
||||
};
|
||||
#else
|
||||
struct VertexOutput {
|
||||
float3 m_Position : Position;
|
||||
float3 m_Normal : Normal;
|
||||
@@ -17,6 +23,7 @@ struct VertexOutput {
|
||||
float4 m_PositionCS : PositionCS;
|
||||
float4 m_HistoryPositionCS : HistoryPositionCS;
|
||||
};
|
||||
#endif
|
||||
|
||||
cbuffer VertexConstants : register(b0) {
|
||||
float4x4 g_JitteredProjection;
|
||||
@@ -32,14 +39,17 @@ VertexOutput main(in VertexInput vs_in) {
|
||||
float4x3 model_view_history = GetModelViewHistory();
|
||||
float4x4 instance_transform = transpose(float4x4(vs_in.m_InstanceTransform[0], vs_in.m_InstanceTransform[1], vs_in.m_InstanceTransform[2], float4(0., 0., 0., 1.)));
|
||||
float3 position = mul(float4(vs_in.m_Position, 1.), instance_transform).xyz;
|
||||
result.m_Position = mul(float4(position, 1.), model_view).xyz;
|
||||
result.m_Normal = mul(mul(float4(vs_in.m_Normal, 0.), instance_transform), model_view);
|
||||
float3 view_space_position = mul(float4(position, 1.), model_view).xyz;
|
||||
result.m_PositionSV = mul(g_JitteredProjection, float4(view_space_position, 1.));
|
||||
result.m_TexCoord = vs_in.m_TexCoord;
|
||||
#ifndef PREPASS
|
||||
result.m_Position = view_space_position;
|
||||
result.m_Normal = mul(mul(float4(vs_in.m_Normal, 0.), instance_transform), model_view);
|
||||
result.m_Tangent.xyz = mul(mul(float4(vs_in.m_Tangent.xyz, 0.), instance_transform), model_view);
|
||||
result.m_Tangent.w = vs_in.m_Tangent.w;
|
||||
result.m_PositionSV = mul(g_JitteredProjection, float4(result.m_Position, 1.));
|
||||
result.m_PositionCS = mul(g_Projection, float4(result.m_Position, 1.));
|
||||
float3 history_position = mul(float4(position, 1.), model_view_history).xyz;
|
||||
result.m_HistoryPositionCS = mul(g_ProjectionHistory, float4(history_position, 1.));
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#define ALPHA_MASK_HLSLI
|
||||
|
||||
void AlphaMask(in float alpha) {
|
||||
#if (PASS & FORWARD_LIGHTING) || defined (SHADOW)
|
||||
if(g_DrawConstants.m_AlphaThreshold >= 0. ? (alpha < g_DrawConstants.m_AlphaThreshold) : (alpha >= -g_DrawConstants.m_AlphaThreshold)) discard;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
#include "math.hlsli"
|
||||
|
||||
#include "lighting_functions.hlsli"
|
||||
|
||||
#include "color_transform.hlsli"
|
||||
|
||||
#include "manul/gbuffer_ssao.hlsli"
|
||||
|
||||
struct ViewConstants {
|
||||
float4x4 m_inverse_model_view;
|
||||
float4x4 m_inverse_projection;
|
||||
};
|
||||
|
||||
struct PushConstantsSpotLight {
|
||||
float3 m_origin;
|
||||
float m_radius_sqr;
|
||||
float3 m_direction;
|
||||
float m_cos_inner_cone;
|
||||
float3 m_color;
|
||||
float m_cos_outer_cone;
|
||||
};
|
||||
|
||||
cbuffer g_ViewConst : register(b0) { ViewConstants g_View; }
|
||||
|
||||
#ifdef SPIRV
|
||||
[[vk::push_constant]] ConstantBuffer<PushConstantsSpotLight> g_SpotLight;
|
||||
#else
|
||||
cbuffer g_SpotLightConst : register(b1) { PushConstantsSpotLight g_SpotLight; }
|
||||
#endif
|
||||
|
||||
RWTexture2D<float4> g_OutDiffuse : register(u0);
|
||||
|
||||
Texture2D<float> g_GbufferDepth : register(t0);
|
||||
Texture2D<float3> g_GbufferNormal : register(t1);
|
||||
Texture2D<float4> g_GbufferParams : register(t2);
|
||||
Texture2D<float3> g_GbufferColor : register(t3);
|
||||
|
||||
float2 PixelToCS(in float2 pixel, in float2 size) {
|
||||
return ((pixel + .5) / size - .5) * float2(2., -2.);
|
||||
}
|
||||
|
||||
float3 ReconstructPos(in float2 cs, in float depth) {
|
||||
float4 ndc = float4(cs, depth, 1.);
|
||||
ndc = mul(g_View.m_inverse_projection, ndc);
|
||||
return ndc.xyz / ndc.w;
|
||||
}
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void CS_Clear(uint3 PixCoord : SV_DispatchThreadID, uint3 GroupID : SV_GroupID, uint GroupIndex : SV_GroupIndex) {
|
||||
uint2 pixel = PixCoord.xy;
|
||||
g_OutDiffuse[pixel].rgb = 0.;
|
||||
}
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void CS_Spotlight(uint3 PixCoord : SV_DispatchThreadID, uint3 GroupID : SV_GroupID, uint GroupIndex : SV_GroupIndex) {
|
||||
uint2 gbuffer_dimensions;
|
||||
uint2 pixel = PixCoord.xy;
|
||||
|
||||
g_OutDiffuse.GetDimensions(gbuffer_dimensions.x, gbuffer_dimensions.y);
|
||||
float3 position = ReconstructPos(PixelToCS(PixCoord.xy, gbuffer_dimensions), g_GbufferDepth[pixel]);
|
||||
float3 view = mul((float3x3)g_View.m_inverse_model_view, position);
|
||||
|
||||
float3 L_offset = g_SpotLight.m_origin - view;
|
||||
float3 L = normalize(L_offset);
|
||||
if(dot(L_offset, L_offset) > g_SpotLight.m_radius_sqr) return;
|
||||
|
||||
float3 albedo = g_GbufferColor[pixel];
|
||||
float4 params = g_GbufferParams[pixel];
|
||||
float3 normal = UnpackNormalXYZ(g_GbufferNormal[pixel]);
|
||||
|
||||
SurfaceData surface_data;
|
||||
surface_data.m_Albedo = albedo;
|
||||
surface_data.m_Alpha = 1.;
|
||||
surface_data.m_Metalness = params.r;
|
||||
surface_data.m_Roughness = params.g;
|
||||
#ifdef GBUFFER_SSAO_HLSLI
|
||||
surface_data.m_DiffuseOcclusion = min(params.b, GetSSAO(pixel));
|
||||
#else
|
||||
surface_data.m_DiffuseOcclusion = params.b;
|
||||
#endif
|
||||
surface_data.m_Normal = mul((float3x3)g_View.m_inverse_model_view, normal);
|
||||
surface_data.m_View = -normalize(view);
|
||||
surface_data.m_Reflect = reflect(-surface_data.m_View, surface_data.m_Normal);
|
||||
surface_data.m_NdotV = max(dot(surface_data.m_Normal, surface_data.m_View), 0.);
|
||||
surface_data.m_SpecularF0 = float3(.04, .04, .04) * params.a * 2.;
|
||||
surface_data.m_SpecularF0 = lerp(surface_data.m_SpecularF0, surface_data.m_Albedo, surface_data.m_Metalness);
|
||||
surface_data.m_SpecularF = FresnelSchlickRoughness(surface_data.m_NdotV, surface_data.m_SpecularF0, surface_data.m_Roughness);
|
||||
surface_data.m_HorizonFading = 1.6;
|
||||
surface_data.m_SpecularOcclusion = ComputeSpecOcclusion(surface_data.m_NdotV, surface_data.m_DiffuseOcclusion, surface_data.m_Roughness);
|
||||
|
||||
float3 lit = float3(0., 0., 0.);
|
||||
|
||||
DirectionalLight directionalLight;
|
||||
directionalLight.m_LightVector = L;
|
||||
directionalLight.m_Color = max(REC709_to_XYZ(g_SpotLight.m_color), 0.);
|
||||
ApplyDirectionalLight(lit, directionalLight, surface_data, 1.);
|
||||
|
||||
|
||||
float cone = saturate((dot(L, -g_SpotLight.m_direction) - g_SpotLight.m_cos_inner_cone) / (g_SpotLight.m_cos_outer_cone - g_SpotLight.m_cos_inner_cone));
|
||||
float attenuation = 1. / dot(L_offset, L_offset) * (1. - cone);
|
||||
|
||||
g_OutDiffuse[pixel].rgb += lit * attenuation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#ifndef GBUFFER_SSAO_HLSLI
|
||||
#define GBUFFER_SSAO_HLSLI
|
||||
Texture2D<float> g_SSAO : register(t5);
|
||||
Texture2D<float4> g_SSAO : register(t5);
|
||||
|
||||
float4 R8G8B8A8_UNORM_to_FLOAT4( uint packedInput )
|
||||
{
|
||||
@@ -19,8 +19,11 @@ void DecodeVisibilityBentNormal( const uint packedValue, out float visibility, o
|
||||
visibility = decoded.w;
|
||||
}
|
||||
|
||||
float GetSSAO(in uint2 pixel_position) {
|
||||
return g_SSAO[pixel_position];
|
||||
float4 GetBentNormal(in uint2 pixel_position) {
|
||||
float4 bent_normal = g_SSAO[pixel_position];
|
||||
bent_normal.xyz = 2. * bent_normal.xyz - 1.;
|
||||
bent_normal.z *= -1.;
|
||||
return bent_normal;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,15 +39,21 @@ void ApplyMaterialLighting(out float4 lit, in MaterialData material)
|
||||
{
|
||||
// Camera-centric world position
|
||||
float3 view = mul((float3x3)g_InverseModelView, material.m_Position);
|
||||
|
||||
#ifdef GBUFFER_SSAO_HLSLI
|
||||
float4 bent_normal = GetBentNormal(pixel_position);
|
||||
bent_normal.a = min(material.m_MaterialParams.b, bent_normal.a);
|
||||
bent_normal.xyz = mul((float3x3)g_InverseModelView, bent_normal.xyz);
|
||||
#endif
|
||||
|
||||
// Convert material to surface data
|
||||
SurfaceData surface_data;
|
||||
surface_data.m_Albedo = clamp(material.m_MaterialAlbedoAlpha.rgb, .02, .9);
|
||||
surface_data.m_Albedo = saturate(material.m_MaterialAlbedoAlpha.rgb);
|
||||
surface_data.m_Alpha = material.m_MaterialAlbedoAlpha.a;
|
||||
surface_data.m_Metalness = material.m_MaterialParams.r;
|
||||
surface_data.m_Roughness = material.m_MaterialParams.g;
|
||||
#ifdef GBUFFER_SSAO_HLSLI
|
||||
surface_data.m_DiffuseOcclusion = min(material.m_MaterialParams.b, GetSSAO(pixel_position));
|
||||
surface_data.m_DiffuseOcclusion = bent_normal.a;
|
||||
#else
|
||||
surface_data.m_DiffuseOcclusion = material.m_MaterialParams.b;
|
||||
#endif
|
||||
@@ -59,7 +65,12 @@ void ApplyMaterialLighting(out float4 lit, in MaterialData material)
|
||||
surface_data.m_SpecularF0 = lerp(surface_data.m_SpecularF0, surface_data.m_Albedo, surface_data.m_Metalness);
|
||||
surface_data.m_SpecularF = FresnelSchlickRoughness(surface_data.m_NdotV, surface_data.m_SpecularF0, surface_data.m_Roughness);
|
||||
surface_data.m_HorizonFading = 1.6;
|
||||
#ifdef GBUFFER_SSAO_HLSLI
|
||||
float BNdotR = max(0., dot(surface_data.m_Reflect, bent_normal.xyz));
|
||||
surface_data.m_SpecularOcclusion = ComputeSpecOcclusion(BNdotR, surface_data.m_DiffuseOcclusion, surface_data.m_Roughness);
|
||||
#else
|
||||
surface_data.m_SpecularOcclusion = ComputeSpecOcclusion(surface_data.m_NdotV, surface_data.m_DiffuseOcclusion, surface_data.m_Roughness);
|
||||
#endif
|
||||
|
||||
lit.rgb = material.m_MaterialEmission * surface_data.m_Alpha;
|
||||
lit.a = 1. - (saturate((1. - surface_data.m_Alpha) * lerp(1. - dot(surface_data.m_SpecularF, 1./3.), 0., surface_data.m_Metalness)));
|
||||
|
||||
@@ -48,6 +48,7 @@ struct PixelInput {
|
||||
#include "sky.hlsli"
|
||||
|
||||
Texture2D<float> g_GbufferDepth : register(t12);
|
||||
Texture2D<float3> g_LitScene : register(t13);
|
||||
#endif
|
||||
|
||||
void MaterialPass(inout MaterialData material);
|
||||
@@ -61,12 +62,14 @@ PixelOutput main(in PixelInput ps_in) {
|
||||
material.m_Tangent = ps_in.m_Tangent.xyz;
|
||||
material.m_Bitangent = ps_in.m_Tangent.w * cross(ps_in.m_Normal, ps_in.m_Tangent.xyz);
|
||||
material.m_TexCoord = ps_in.m_TexCoord;
|
||||
material.m_ScreenCoord = uv;
|
||||
material.m_PixelCoord = ps_in.m_PositionSV.xy;
|
||||
material.m_PositionNDC = ps_in.m_PositionCS / ps_in.m_PositionCS.w;
|
||||
material.m_MaterialAlbedoAlpha = float4(1., 1., 1., 1.);
|
||||
material.m_MaterialEmission = float3(0., 0., 0.);
|
||||
material.m_MaterialParams = float4(0., .5, 1., .5); // Metalness.Roughness.Occlusion.Specular
|
||||
material.m_MaterialNormal = float3(0., 0., 1.);
|
||||
material.m_RefractionOffset = float2(0., 0.);
|
||||
MaterialPass(material);
|
||||
material.m_MaterialAlbedoAlpha.rgb = saturate(material.m_MaterialAlbedoAlpha.rgb);
|
||||
material.m_MaterialEmission = max(material.m_MaterialEmission, 0.);
|
||||
@@ -95,6 +98,12 @@ PixelOutput main(in PixelInput ps_in) {
|
||||
ps_out.m_Motion = (ps_in.m_HistoryPositionCS.xy / ps_in.m_HistoryPositionCS.w) - (ps_in.m_PositionCS.xy / ps_in.m_PositionCS.w);
|
||||
ps_out.m_Motion = ps_out.m_Motion * float2(.5, -.5);
|
||||
#endif
|
||||
|
||||
#if (PASS & FORWARD_LIGHTING) && defined(REFRACTION)
|
||||
float3 scene_color = g_LitScene.Sample(g_SkySampler, material.m_ScreenCoord + material.m_RefractionOffset * float2(1., -1.));
|
||||
ps_out.m_Color.rgb += (1. - ps_out.m_Color.a) * scene_color;
|
||||
ps_out.m_Color.a = 1.;
|
||||
#endif
|
||||
|
||||
return ps_out;
|
||||
}
|
||||
|
||||
@@ -9,12 +9,14 @@ struct MaterialData {
|
||||
float3 m_Bitangent;
|
||||
float3 m_Normal;
|
||||
float2 m_TexCoord;
|
||||
float2 m_ScreenCoord;
|
||||
uint2 m_PixelCoord;
|
||||
float4 m_PositionNDC;
|
||||
float4 m_MaterialAlbedoAlpha;
|
||||
float3 m_MaterialEmission;
|
||||
float4 m_MaterialParams; // Metalness.Roughness.Occlusion.Specular
|
||||
float3 m_MaterialNormal;
|
||||
float2 m_RefractionOffset;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
39
betterRenderer/shaders/manul/random.hlsli
Normal file
39
betterRenderer/shaders/manul/random.hlsli
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
uint Hash(uint s);
|
||||
uint Hash(uint2 s);
|
||||
uint Hash(uint3 s);
|
||||
uint Hash(float s);
|
||||
uint HashCombine(uint seed, uint value);
|
||||
|
||||
// Evolving Sub-Grid Turbulence for Smoke Animation
|
||||
// H. Schechter and R. Bridson
|
||||
uint Hash(uint s) {
|
||||
s ^= 2747636419u;
|
||||
s *= 2654435769u;
|
||||
s ^= s >> 16u;
|
||||
s *= 2654435769u;
|
||||
s ^= s >> 16u;
|
||||
s *= 2654435769u;
|
||||
return s;
|
||||
}
|
||||
|
||||
uint Hash(uint2 s) {
|
||||
return HashCombine(Hash(s.x), s.y);
|
||||
}
|
||||
|
||||
uint Hash(uint3 s) {
|
||||
return HashCombine(Hash(s.xy), s.z);
|
||||
}
|
||||
|
||||
uint HashCombine(uint seed, uint value) {
|
||||
return seed ^ (Hash(value) + 0x9e3779b9u + (seed<<6u) + (seed>>2u));
|
||||
}
|
||||
|
||||
uint Rand(inout uint seed) {
|
||||
seed = Hash(seed);
|
||||
return seed;
|
||||
}
|
||||
|
||||
float RandF(inout uint seed) {
|
||||
return float(Rand(seed)) * 2.3283064365386963e-10;
|
||||
}
|
||||
@@ -8,6 +8,11 @@ cbuffer DrawConstants : register(b2) {
|
||||
float g_Altitude;
|
||||
float3 g_LightColor;
|
||||
float g_Time;
|
||||
float4 g_RainParams;
|
||||
float4 g_WiperPos;
|
||||
float4 g_WiperTimerOut;
|
||||
float4 g_WiperTimerReturn;
|
||||
float g_VerticalFov;
|
||||
}
|
||||
|
||||
float2 PixelToCS(in float2 pixel, in float2 size) {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
templates:
|
||||
# Partially pre-filled containers to avoid excessive copypasta
|
||||
XeGTAO:
|
||||
# TODO Depth conversion is broken since converting to reversed depth buffer
|
||||
# after attempting to fix it, it is still broken but with hardcoded values
|
||||
source: XeGTAO/GTAO
|
||||
target: compute
|
||||
definitions: # TODO (mostly) move to shader file I guess
|
||||
@@ -14,6 +12,8 @@ templates:
|
||||
XE_GTAO_USE_HALF_FLOAT_PRECISION: 0
|
||||
VA_COMPILED_AS_SHADER_CODE: 1
|
||||
VA_SATURATE: saturate
|
||||
XE_GTAO_GENERATE_NORMALS_INPLACE: 1
|
||||
XE_GTAO_COMPUTE_BENT_NORMALS: 1
|
||||
envmap:
|
||||
source: envmap
|
||||
target: compute
|
||||
@@ -23,9 +23,6 @@ templates:
|
||||
bloom:
|
||||
source: manul/bloom
|
||||
target: compute
|
||||
gbuffer_lights:
|
||||
source: manul/gbuffer_lights
|
||||
target: compute
|
||||
shaders:
|
||||
materials:
|
||||
# Material shaders
|
||||
@@ -47,18 +44,6 @@ shaders:
|
||||
binding: 2
|
||||
hint: normalmap
|
||||
default: normalmap
|
||||
# paramx: # Metalness.Roughness.[UNUSED].Normal[X]
|
||||
# binding: 1
|
||||
# hint: linear
|
||||
# default: legacy_params
|
||||
# paramy: # Specular.Occlusion.[UNUSED].Normal[Y]
|
||||
# binding: 2
|
||||
# hint: linear
|
||||
# default: legacy_params
|
||||
# selfillum:
|
||||
# binding: 3
|
||||
# hint: color
|
||||
# default: black
|
||||
masked_shadow_texture: albedo
|
||||
source: ps_default_lit
|
||||
legacy:
|
||||
@@ -137,6 +122,29 @@ shaders:
|
||||
default: normalmap
|
||||
masked_shadow_texture: diffuse
|
||||
source: ps_legacy_water
|
||||
windshield_rain:
|
||||
textures:
|
||||
diffuse:
|
||||
binding: 0
|
||||
hint: color # so that texture will be marked as sRGB
|
||||
default: white
|
||||
raindropsatlas:
|
||||
binding: 1
|
||||
hint: color
|
||||
default: white
|
||||
no_anisotropy: true
|
||||
wipermask:
|
||||
binding: 2
|
||||
hint: color
|
||||
default: white
|
||||
no_filter: true
|
||||
rain:
|
||||
binding: 3
|
||||
hint: linear
|
||||
default: system/raindrops_buffer
|
||||
masked_shadow_texture: diffuse
|
||||
source: ps_windshield_rain
|
||||
refraction: true
|
||||
utility:
|
||||
# Everything that does not belong to scene graph rendering
|
||||
# ImGui shaders
|
||||
@@ -153,6 +161,20 @@ shaders:
|
||||
source: ps_shadow_masked
|
||||
target: pixel
|
||||
entrypoint: main
|
||||
prepass_masked:
|
||||
source: ps_shadow_masked
|
||||
target: pixel
|
||||
entrypoint: main
|
||||
definitions:
|
||||
PREPASS: 1
|
||||
windshield_rain_anim:
|
||||
source: ps_windshield_rain_anim
|
||||
target: pixel
|
||||
entrypoint: main
|
||||
max_depth_4x4:
|
||||
source: cs_downsample_depth
|
||||
target: compute
|
||||
entrypoint: main
|
||||
# Contact shadows
|
||||
# TODO Depth conversion is broken since converting to reversed depth buffer
|
||||
contact_shadows:
|
||||
@@ -169,6 +191,18 @@ shaders:
|
||||
source: default_vertex
|
||||
target: vertex
|
||||
entrypoint: main
|
||||
default_vertex_no_jitter:
|
||||
source: default_vertex
|
||||
target: vertex
|
||||
entrypoint: main
|
||||
definitions:
|
||||
NO_JITTER: 1
|
||||
default_prepass_vertex:
|
||||
source: default_vertex
|
||||
target: vertex
|
||||
entrypoint: main
|
||||
definitions:
|
||||
PREPASS: 1
|
||||
shadow_vertex:
|
||||
source: shadow_vertex
|
||||
target: vertex
|
||||
@@ -181,6 +215,12 @@ shaders:
|
||||
source: instanced_vertex
|
||||
target: vertex
|
||||
entrypoint: main
|
||||
instanced_prepass_vertex:
|
||||
source: instanced_vertex
|
||||
target: vertex
|
||||
entrypoint: main
|
||||
definitions:
|
||||
PREPASS: 1
|
||||
instanced_shadow_vertex:
|
||||
source: instanced_shadow_vertex
|
||||
target: vertex
|
||||
@@ -285,13 +325,6 @@ shaders:
|
||||
source: manul/line
|
||||
target: pixel
|
||||
entrypoint: pix_main
|
||||
# Deferred light primitives
|
||||
gbuffer_light_clear:
|
||||
use_template: gbuffer_lights
|
||||
entrypoint: CS_Clear
|
||||
gbuffer_light_spot:
|
||||
use_template: gbuffer_lights
|
||||
entrypoint: CS_Spotlight
|
||||
# Forward+ light culling
|
||||
forwardplus_compute_frustums:
|
||||
source: manul/forward_plus/forward_plus
|
||||
|
||||
@@ -3,8 +3,13 @@
|
||||
sampler diffuse_sampler : register(s0);
|
||||
Texture2D diffuse : register(t0);
|
||||
|
||||
#ifdef PREPASS
|
||||
#include "manul/draw_constants.hlsli"
|
||||
#else
|
||||
#include "manul/draw_constants_shadow.hlsli"
|
||||
#endif
|
||||
|
||||
#define SHADOW
|
||||
#include "manul/alpha_mask.hlsli"
|
||||
|
||||
struct VertexOutput {
|
||||
|
||||
83
betterRenderer/shaders/ps_windshield_rain.hlsl
Normal file
83
betterRenderer/shaders/ps_windshield_rain.hlsl
Normal file
@@ -0,0 +1,83 @@
|
||||
#include "manul/math.hlsli"
|
||||
#include "manul/material.hlsli"
|
||||
#include "manul/color_transform.hlsli"
|
||||
|
||||
sampler diffuse_sampler : register(s0);
|
||||
sampler raindrop_sampler : register(s1);
|
||||
sampler wipermask_sampler : register(s2);
|
||||
Texture2D<float4> diffuse : register(t0);
|
||||
Texture2D<float4> raindropsatlas : register(t1);
|
||||
Texture2D<float4> wipermask : register(t2);
|
||||
Texture2D<float> rain : register(t3);
|
||||
|
||||
// Project the surface gradient (dhdx, dhdy) onto the surface (n, dpdx, dpdy)
|
||||
float3 CalculateSurfaceGradient(float3 n, float3 dpdx, float3 dpdy, float dhdx, float dhdy)
|
||||
{
|
||||
float3 r1 = cross(dpdy, n);
|
||||
float3 r2 = cross(n, dpdx);
|
||||
|
||||
return (r1 * dhdx + r2 * dhdy) / dot(dpdx, r1);
|
||||
}
|
||||
|
||||
// Move the normal away from the surface normal in the opposite surface gradient direction
|
||||
float3 PerturbNormal(float3 n, float3 dpdx, float3 dpdy, float dhdx, float dhdy)
|
||||
{
|
||||
return normalize(n - CalculateSurfaceGradient(n, dpdx, dpdy, dhdx, dhdy));
|
||||
}
|
||||
|
||||
// Calculate the surface normal using screen-space partial derivatives of the height field
|
||||
float3 CalculateSurfaceNormal(float3 position, float3 normal, float2 gradient)
|
||||
{
|
||||
float3 dpdx = ddx(position);
|
||||
float3 dpdy = ddy(position);
|
||||
|
||||
float dhdx = gradient.x;
|
||||
float dhdy = gradient.y;
|
||||
|
||||
return PerturbNormal(normal, dpdx, dpdy, dhdx, dhdy);
|
||||
}
|
||||
|
||||
void MaterialPass(inout MaterialData material) {
|
||||
#if PASS & FORWARD_LIGHTING
|
||||
|
||||
MaterialData material_glass = material;
|
||||
float4 tex_color = diffuse.Sample(diffuse_sampler, material.m_TexCoord);
|
||||
uint2 size;
|
||||
rain.GetDimensions(size.x, size.y);
|
||||
float droplet_distance = rain.Sample(raindrop_sampler, material.m_ScreenCoord);
|
||||
float droplet_distance_x = rain.Sample(raindrop_sampler, material.m_ScreenCoord, int2(1, 0));
|
||||
float droplet_distance_y = rain.Sample(raindrop_sampler, material.m_ScreenCoord, int2(0, 1));
|
||||
float2 gradient = float2(droplet_distance_x - droplet_distance, droplet_distance_y - droplet_distance);
|
||||
material_glass.m_MaterialAlbedoAlpha.xyz = 0.;
|
||||
material_glass.m_MaterialNormal = material.m_Normal;
|
||||
material_glass.m_MaterialParams.g = .2;
|
||||
float3 normal = CalculateSurfaceNormal(material_glass.m_Position, material_glass.m_Normal, gradient * -.0075);
|
||||
material_glass.m_MaterialNormal = normal;
|
||||
float cosTheta = saturate(dot(-normalize(material_glass.m_Position), normal));
|
||||
material.m_MaterialAlbedoAlpha.a = lerp(.1, FresnelSchlickRoughness(cosTheta, .04, 0.), smoothstep(0., .15, droplet_distance));
|
||||
|
||||
float3 normal_world = mul((float3x3)g_InverseModelView, material_glass.m_MaterialNormal);
|
||||
|
||||
float4 glass_lit;
|
||||
ApplyMaterialLighting(glass_lit, material_glass, material_glass.m_PixelCoord);
|
||||
|
||||
material.m_MaterialEmission = glass_lit * smoothstep(0., .15, droplet_distance) * smoothstep(-1., 0., normal_world.y);
|
||||
|
||||
material.m_MaterialAlbedoAlpha.xyz = 0.;
|
||||
material.m_RefractionOffset = normal.xy * (.005 / (length(material.m_Position) * tan(.5 * g_VerticalFov))) * smoothstep(0., .15, droplet_distance);
|
||||
|
||||
float glass_opacity = FresnelSchlickRoughness(saturate(dot(-normalize(material.m_Position), material.m_Normal)), .2, 0.);
|
||||
material.m_MaterialEmission = lerp(material.m_MaterialEmission, 0., glass_opacity);
|
||||
material.m_MaterialAlbedoAlpha.a = lerp(material.m_MaterialAlbedoAlpha.a, 1., glass_opacity);
|
||||
material.m_MaterialParams.g = .05;
|
||||
material.m_MaterialNormal = material.m_Normal;
|
||||
|
||||
|
||||
{ // Overlay windshield texture with alpha
|
||||
material.m_MaterialAlbedoAlpha.xyz = lerp(material.m_MaterialAlbedoAlpha.xyz, tex_color.xyz, tex_color.a);
|
||||
material.m_MaterialAlbedoAlpha.a = lerp(material.m_MaterialAlbedoAlpha.a, 1., tex_color.a);
|
||||
material.m_MaterialEmission.xyz = lerp(material.m_MaterialEmission.xyz, 0., tex_color.a);
|
||||
material.m_MaterialParams.g = lerp(material.m_MaterialParams.g, float4(0., .5, 1., .5), tex_color.a);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
162
betterRenderer/shaders/ps_windshield_rain_anim.hlsl
Normal file
162
betterRenderer/shaders/ps_windshield_rain_anim.hlsl
Normal file
@@ -0,0 +1,162 @@
|
||||
#include "manul/draw_constants.hlsli"
|
||||
#include "manul/random.hlsli"
|
||||
#include "manul/view_data.hlsli"
|
||||
|
||||
struct PixelInput {
|
||||
float3 m_Position : Position;
|
||||
float3 m_Normal : Normal;
|
||||
float2 m_TexCoord : TexCoord;
|
||||
float4 m_Tangent : Tangent;
|
||||
float4 m_PositionSV : SV_Position;
|
||||
float4 m_PositionCS : PositionCS;
|
||||
};
|
||||
|
||||
sampler raindrop_sampler : register(s0);
|
||||
sampler wipermask_sampler : register(s1);
|
||||
Texture2D<float> raindropsatlas : register(t0);
|
||||
Texture2D<float4> wipermask : register(t1);
|
||||
|
||||
float getDropTex(float choice, float2 uv) {
|
||||
float2 offset;
|
||||
if (choice < .25) offset = float2(0.0, 0.0);
|
||||
else if (choice < .5) offset = float2(0.5, 0.0);
|
||||
else if (choice < .75) offset = float2(0.0, 0.5);
|
||||
else offset = float2(0.5, 0.5);
|
||||
return raindropsatlas.Sample(raindrop_sampler, offset + uv * 0.5);
|
||||
}
|
||||
|
||||
float GetMixFactor(in float2 co, out float side);
|
||||
|
||||
float main(in PixelInput input) : SV_Target0 {
|
||||
const float specular_intensity = 1.;
|
||||
const float wobble_strength = .002;
|
||||
const float wobble_speed = 30.;
|
||||
|
||||
//float4 tex_color = diffuse.Sample(diffuse_sampler, material.m_TexCoord);
|
||||
//if (tex_color.a < .01) discard;
|
||||
|
||||
float2 rainCoord = input.m_TexCoord;
|
||||
float gridSize = ceil(200.);
|
||||
|
||||
const float numDrops = 20000.;
|
||||
const float cycleDuration = 4.;
|
||||
|
||||
float squareMin = 1. / gridSize;
|
||||
float squareMax = 2.5 / gridSize;
|
||||
|
||||
float2 cell = floor(rainCoord * gridSize);
|
||||
|
||||
float3 dropLayer = 0.;
|
||||
float dropMaskSum = 0.;
|
||||
|
||||
float output = 0.;
|
||||
|
||||
// Grid of 9 droplets in immediate neighbourhood
|
||||
[unroll]
|
||||
for (int oy = -1; oy <= 1; ++oy) {
|
||||
|
||||
[unroll]
|
||||
for (int ox = -1; ox <= 1; ++ox) {
|
||||
|
||||
float2 neighborCell = cell + float2(ox, oy);
|
||||
float2 neighborCenter = (neighborCell + .5) / gridSize;
|
||||
|
||||
float side;
|
||||
float mixFactor = GetMixFactor(neighborCenter, side);
|
||||
|
||||
uint seed = Hash(uint3(neighborCell, side));
|
||||
|
||||
if(mixFactor < RandF(seed)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Show a percentage of droplets given by rain intensity param
|
||||
float activationSeed = RandF(seed);
|
||||
if (activationSeed > g_RainParams.x)
|
||||
continue; // kropla nieaktywna
|
||||
|
||||
// Randomly modulate droplet center & size
|
||||
float2 dropCenter = (neighborCell + float2(RandF(seed), RandF(seed))) / gridSize;
|
||||
float squareSize = lerp(squareMin, squareMax, RandF(seed));
|
||||
|
||||
float lifeTime = g_Time + RandF(seed) * cycleDuration;
|
||||
float phase = frac(lifeTime / cycleDuration);
|
||||
float active = saturate(1. - phase);
|
||||
|
||||
// Gravity influence (TODO add vehicle speed & wind here!)
|
||||
float gravityStart = .5;
|
||||
float gravityPhase = smoothstep(gravityStart, 1., phase);
|
||||
float dropMass = lerp(.3, 1.2, RandF(seed));
|
||||
float gravitySpeed = .15 * dropMass;
|
||||
float2 gravityOffset = float2(0., gravityPhase * gravitySpeed * phase);
|
||||
|
||||
// Random wobble
|
||||
bool hasWobble = (RandF(seed) < .10);
|
||||
float2 wobbleOffset = 0.;
|
||||
if (hasWobble && gravityPhase > 0.) {
|
||||
float intensity = sin(g_Time * wobble_speed + RandF(seed) * 100.) * wobble_strength * gravityPhase;
|
||||
wobbleOffset = float2(intensity, 0.);
|
||||
}
|
||||
|
||||
float2 slideOffset = gravityOffset + wobbleOffset;
|
||||
|
||||
// Flatten droplets influenced by gravity
|
||||
float flattenAmount = smoothstep(0.1, 0.5, gravityPhase);
|
||||
float flattenX = lerp(1.0, 0.4, flattenAmount);
|
||||
float stretchY = lerp(1.0, 1.6, flattenAmount);
|
||||
|
||||
// Droplet local position & mask
|
||||
float2 diff = (rainCoord + slideOffset) - dropCenter;
|
||||
diff.x *= 1.0 / flattenX;
|
||||
diff.y *= 1.0 / stretchY;
|
||||
float mask = smoothstep(squareSize * 0.5, squareSize * 0.45, max(abs(diff.x), abs(diff.y)));
|
||||
|
||||
if (mask > .001) {
|
||||
float2 localUV = (diff + squareSize * 0.5) / squareSize;
|
||||
float choice = RandF(seed);
|
||||
float dropTex = getDropTex(choice, localUV) * mask;
|
||||
output = max(output, dropTex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float GetMixFactor(in float2 co, out float side) {
|
||||
float4 movePhase = g_WiperPos;
|
||||
bool4 is_out = movePhase <= 1.;
|
||||
movePhase = select(is_out, movePhase, 2. - movePhase);
|
||||
|
||||
float4 mask = wipermask.Sample(wipermask_sampler, co);
|
||||
|
||||
float4 areaMask = step(.001, mask);
|
||||
|
||||
float4 maskVal = select(is_out, mask, 1. - mask);
|
||||
float4 wipeWidth = smoothstep(1., .9, movePhase) * .25;
|
||||
float4 cleaned = smoothstep(movePhase - wipeWidth, movePhase, maskVal) * areaMask;
|
||||
float4 side_v = step(maskVal, movePhase);
|
||||
cleaned *= side_v;
|
||||
side_v = select(is_out, 1. - side_v, side_v);
|
||||
|
||||
// "regeneration", raindrops gradually returning after wiper pass:
|
||||
float4 regenPhase = saturate((g_Time - lerp(g_WiperTimerOut, g_WiperTimerReturn, side_v) - .2) / g_RainParams.y);
|
||||
|
||||
side_v = lerp(0., 1. - side_v, areaMask);
|
||||
|
||||
float4 factor_v = lerp(1., regenPhase * (1. - cleaned), areaMask);
|
||||
|
||||
side = 0.;
|
||||
float out_factor = 1.;
|
||||
|
||||
// Find out the wiper blade that influences given grid cell the most
|
||||
[unroll]
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
bool is_candidate = factor_v[i] < out_factor;
|
||||
out_factor = select(is_candidate, factor_v[i], out_factor);
|
||||
side = select(is_candidate, side_v[i], side);
|
||||
}
|
||||
|
||||
return out_factor;
|
||||
}
|
||||
@@ -72,6 +72,10 @@ void gl::glsl_common_setup()
|
||||
mat4 lightview[MAX_CASCADES];
|
||||
vec3 cascade_end;
|
||||
float time;
|
||||
vec4 rain_params;
|
||||
vec4 wiper_pos;
|
||||
vec4 wiper_timer_out;
|
||||
vec4 wiper_timer_return;
|
||||
};
|
||||
|
||||
)STRING";
|
||||
|
||||
6
gl/ubo.h
6
gl/ubo.h
@@ -45,9 +45,13 @@ namespace gl
|
||||
glm::mat4 lightview[MAX_CASCADES];
|
||||
glm::vec3 cascade_end;
|
||||
float time;
|
||||
glm::vec4 rain_params;
|
||||
glm::vec4 wiper_pos;
|
||||
glm::vec4 wiper_timer_out;
|
||||
glm::vec4 wiper_timer_return;
|
||||
};
|
||||
|
||||
static_assert(sizeof(scene_ubs) == 336, "bad size of ubs");
|
||||
static_assert(sizeof(scene_ubs) == 400, "bad size of ubs");
|
||||
|
||||
const size_t MAX_PARAMS = 3;
|
||||
|
||||
|
||||
@@ -694,6 +694,46 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
|
||||
m_colorpass = m_renderpass; // cache pass data
|
||||
|
||||
scene_ubs.time = Timer::GetTime();
|
||||
{
|
||||
float percipitation_intensity = glm::saturate(Global.Overcast - 1.);
|
||||
scene_ubs.rain_params.x = percipitation_intensity; // % amount of droplets
|
||||
scene_ubs.rain_params.y = glm::mix(15., 1., percipitation_intensity); // Regeneration time
|
||||
if (TDynamicObject const *owner = Global.pCamera.m_owner; owner && !!owner->MoverParameters->CabActive)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i < owner->dWiperPos.size())
|
||||
{
|
||||
int index = owner->MoverParameters->CabActive > 0 ? i : static_cast<int>(owner->dWiperPos.size() - 1) - i;
|
||||
scene_ubs.wiper_pos[i] = owner->dWiperPos[index];
|
||||
if (owner->dWiperPos[index] > 0. && owner->wiperDirection[index])
|
||||
{
|
||||
scene_ubs.wiper_pos[i] += 1.;
|
||||
}
|
||||
if (owner->dWiperPos[index] < .025)
|
||||
{
|
||||
scene_ubs.wiper_timer_out[i] = scene_ubs.time;
|
||||
}
|
||||
if (owner->dWiperPos[index] > .975)
|
||||
{
|
||||
scene_ubs.wiper_timer_return[i] = scene_ubs.time;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scene_ubs.wiper_pos[i] = 0.;
|
||||
scene_ubs.wiper_timer_out[i] = -1000.;
|
||||
scene_ubs.wiper_timer_return[i] = -1000.;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scene_ubs.wiper_pos = glm::vec4{0.};
|
||||
scene_ubs.wiper_timer_out = glm::vec4{-1000.};
|
||||
scene_ubs.wiper_timer_return = glm::vec4{-1000.};
|
||||
}
|
||||
}
|
||||
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
|
||||
scene_ubs.inv_view = glm::inverse( glm::mat4{ glm::mat3{ m_colorpass.pass_camera.modelview() } } );
|
||||
scene_ubo->update(scene_ubs);
|
||||
|
||||
212
shaders/mat_rain_windscreen.frag
Normal file
212
shaders/mat_rain_windscreen.frag
Normal file
@@ -0,0 +1,212 @@
|
||||
// Windshield rain effects
|
||||
// by @lcddisplay; wiper movement @MichauSto
|
||||
|
||||
in vec3 f_normal;
|
||||
in vec2 f_coord;
|
||||
in vec4 f_pos;
|
||||
#include <common>
|
||||
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
#if MOTIONBLUR_ENABLED
|
||||
layout(location = 1) out vec4 out_motion;
|
||||
#endif
|
||||
|
||||
#texture(diffuse, 0, sRGB_A)
|
||||
#texture(raindropsatlas, 1, sRGB_A)
|
||||
#texture(wipermask, 2, sRGB_A)
|
||||
#param (color, 0, 0, 4, diffuse)
|
||||
#param (diffuse, 1, 0, 1, diffuse)
|
||||
#param (specular, 1, 1, 1, specular)
|
||||
#param (reflection, 1, 2, 1, zero)
|
||||
#param (glossiness, 1, 3, 1, glossiness)
|
||||
#param (raindrop_grid_size, 2, 0, 1, one)
|
||||
|
||||
#include <light_common.glsl>
|
||||
#include <apply_fog.glsl>
|
||||
#include <tonemapping.glsl>
|
||||
|
||||
uniform sampler2D diffuse;
|
||||
uniform sampler2D raindropsatlas;
|
||||
uniform sampler2D wipermask;
|
||||
|
||||
uniform float specular_intensity = 1.0;
|
||||
uniform float wobble_strength = 0.002;
|
||||
uniform float wobble_speed = 30.0;
|
||||
|
||||
float hash(vec2 p) {
|
||||
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
vec4 getDropTex(float choice, vec2 uv) {
|
||||
vec2 offset;
|
||||
if (choice < 0.25) offset = vec2(0.0, 0.0);
|
||||
else if (choice < 0.5) offset = vec2(0.5, 0.0);
|
||||
else if (choice < 0.75) offset = vec2(0.0, 0.5);
|
||||
else offset = vec2(0.5, 0.5);
|
||||
return texture(raindropsatlas, offset + uv * 0.5);
|
||||
}
|
||||
|
||||
float GetMixFactor(in vec2 co, out float side);
|
||||
|
||||
void main() {
|
||||
vec4 tex_color = texture(diffuse, f_coord);
|
||||
if (tex_color.a < 0.01) discard;
|
||||
|
||||
vec2 rainCoord = f_coord;
|
||||
|
||||
const float numDrops = 20000.0;
|
||||
const float cycleDuration = 4.0;
|
||||
const float squareMin = 0.0035;
|
||||
const float squareMax = 0.008;
|
||||
|
||||
float gridSize = ceil(param[2].x);
|
||||
vec2 cell = floor(rainCoord * gridSize);
|
||||
|
||||
vec3 dropLayer = vec3(0.0);
|
||||
float dropMaskSum = 0.0;
|
||||
|
||||
// Grid of 9 droplets in immediate neighbourhood
|
||||
for (int oy = -1; oy <= 1; oy++) {
|
||||
for (int ox = -1; ox <= 1; ox++) {
|
||||
|
||||
vec2 neighborCell = cell + vec2(ox, oy);
|
||||
vec2 neighborCenter = (neighborCell + .5) / gridSize;
|
||||
|
||||
float side;
|
||||
float mixFactor = GetMixFactor(neighborCenter, side);
|
||||
|
||||
if(mixFactor < hash(neighborCell + vec2(mix(0., .2137, side), 0.))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float i = neighborCell.x + neighborCell.y * gridSize;
|
||||
|
||||
// Show a percentage of droplets given by rain intensity param
|
||||
float activationSeed = hash(vec2(i, 0.333 + side));
|
||||
if (activationSeed > rain_params.x)
|
||||
continue; // kropla nieaktywna
|
||||
|
||||
// Randomly modulate droplet center & size
|
||||
vec2 dropCenter = (neighborCell + vec2(hash(vec2(i, 0.12 + side)), hash(vec2(i, 0.34 + side)))) / gridSize;
|
||||
float squareSize = mix(squareMin, squareMax, hash(vec2(i, 0.56 + side)));
|
||||
|
||||
float lifeTime = time + hash(vec2(i, 0.78 + side)) * cycleDuration;
|
||||
float phase = fract(lifeTime / cycleDuration);
|
||||
float active = clamp(1.0 - phase, 0.0, 1.0);
|
||||
|
||||
// Gravity influence (TODO add vehicle speed & wind here!)
|
||||
float gravityStart = 0.5;
|
||||
float gravityPhase = smoothstep(gravityStart, 1.0, phase);
|
||||
float dropMass = mix(0.3, 1.2, hash(vec2(i, 0.21 + side)));
|
||||
float gravitySpeed = 0.15 * dropMass;
|
||||
vec2 gravityOffset = vec2(0.0, gravityPhase * gravitySpeed * phase);
|
||||
|
||||
// Random wobble
|
||||
bool hasWobble = (hash(vec2(i, 0.91 + side)) < 0.10);
|
||||
vec2 wobbleOffset = vec2(0.0);
|
||||
if (hasWobble && gravityPhase > 0.0) {
|
||||
float intensity = sin(time * wobble_speed + i) * wobble_strength * gravityPhase;
|
||||
wobbleOffset = vec2(intensity, 0.0);
|
||||
}
|
||||
|
||||
vec2 slideOffset = gravityOffset + wobbleOffset;
|
||||
|
||||
// Flatten droplets influenced by gravity
|
||||
float flattenAmount = smoothstep(0.1, 0.5, gravityPhase);
|
||||
float flattenX = mix(1.0, 0.4, flattenAmount);
|
||||
float stretchY = mix(1.0, 1.6, flattenAmount);
|
||||
|
||||
// Droplet local position & mask
|
||||
vec2 diff = (rainCoord + slideOffset) - dropCenter;
|
||||
diff.x *= 1.0 / flattenX;
|
||||
diff.y *= 1.0 / stretchY;
|
||||
float mask = smoothstep(squareSize * 0.5, squareSize * 0.45, max(abs(diff.x), abs(diff.y)));
|
||||
|
||||
if (mask > 0.001) {
|
||||
vec2 localUV = (diff + squareSize * 0.5) / squareSize;
|
||||
float choice = hash(vec2(i, 0.99 + side));
|
||||
vec4 dropTex = getDropTex(choice, localUV);
|
||||
float sharpAlpha = smoothstep(0.3, 0.9, dropTex.a);
|
||||
|
||||
float ambLum = clamp(dot(ambient, vec3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);
|
||||
float sunFactor = pow(clamp(ambLum * 6.0, 0.0, 1.0), 0.5);
|
||||
float dynBright = mix(0.0, 1.0, sunFactor);
|
||||
|
||||
float colorLuma = length(dropTex.rgb);
|
||||
float alphaRange = smoothstep(0.1, 0.3, colorLuma);
|
||||
float blackAlpha = mix(0.25, 0.85, alphaRange);
|
||||
|
||||
float sparkle = 0.0;
|
||||
if (hasWobble) {
|
||||
sparkle = pow(abs(sin(f_coord.x * 8.0 + time * 2.0 + hash(vec2(i, 0.9 + side)) * 6.2831)), 40.0)
|
||||
* mix(0.2, 1.0, sunFactor);
|
||||
}
|
||||
|
||||
vec3 specularColor = vec3(1.0) * specular_intensity * sparkle;
|
||||
vec3 dropLit = dropTex.rgb * dynBright + specularColor * sharpAlpha;
|
||||
|
||||
dropLayer += dropLit * sharpAlpha * active * blackAlpha * mask;
|
||||
dropMaskSum += sharpAlpha * active * blackAlpha * mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
vec3 finalMix = dropLayer;
|
||||
float alphaOut = clamp(dropMaskSum, 0.0, 1.0);
|
||||
out_color = vec4(finalMix, alphaOut);
|
||||
|
||||
{ // Overlay windshield texture with alpha
|
||||
vec3 fragcolor = ambient;
|
||||
vec3 fragnormal = normalize(f_normal);
|
||||
float reflectivity = param[1].z;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
glossiness = abs(param[1].w);
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
vec4 color = vec4(fragcolor, tex_color.a * alpha_mult);
|
||||
|
||||
out_color.xyz = apply_fog(mix(out_color.xyz, color.xyz, color.a));
|
||||
out_color.a = mix(out_color.a, 1., color.a);
|
||||
}
|
||||
|
||||
#if MOTIONBLUR_ENABLED
|
||||
out_motion = vec4(0.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
float GetMixFactor(in vec2 co, out float side) {
|
||||
vec4 movePhase = wiper_pos;
|
||||
bvec4 is_out = lessThanEqual(movePhase, vec4(1.));
|
||||
movePhase = mix(vec4(2.) - movePhase, movePhase, is_out);
|
||||
|
||||
vec4 mask = texture(wipermask, co);
|
||||
|
||||
vec4 areaMask = step(.001, mask);
|
||||
|
||||
vec4 maskVal = mix(1. - mask, mask, is_out);
|
||||
vec4 wipeWidth = smoothstep(1., .9, movePhase) * .25;
|
||||
vec4 cleaned = smoothstep(movePhase - wipeWidth, movePhase, maskVal) * areaMask;
|
||||
vec4 side_v = step(maskVal, movePhase);
|
||||
cleaned *= side_v;
|
||||
side_v = mix(side_v, vec4(1.) - side_v, is_out);
|
||||
|
||||
// "regeneration", raindrops gradually returning after wiper pass:
|
||||
vec4 regenPhase = clamp((vec4(time) - mix(wiper_timer_out, wiper_timer_return, side_v) - vec4(.2)) / vec4(rain_params.y), vec4(0.), vec4(1.));
|
||||
|
||||
side_v = mix(vec4(0.), vec4(1.) - side_v, areaMask);
|
||||
|
||||
vec4 factor_v = mix(vec4(1.), regenPhase * (vec4(1.) - cleaned), areaMask);
|
||||
|
||||
side = 0.;
|
||||
float out_factor = 1.;
|
||||
|
||||
// Find out the wiper blade that influences given grid cell the most
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
bool is_candidate = factor_v[i] < out_factor;
|
||||
out_factor = mix(out_factor, factor_v[i], is_candidate);
|
||||
side = mix(side, side_v[i], is_candidate);
|
||||
}
|
||||
|
||||
return out_factor;
|
||||
}
|
||||
@@ -3,19 +3,55 @@ in vec2 f_coords;
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
#texture (color_tex, 0, RGB)
|
||||
|
||||
uniform sampler2D iChannel0;
|
||||
|
||||
void main()
|
||||
{
|
||||
float amount = 0.001;
|
||||
|
||||
vec2 uv = f_coords;
|
||||
vec3 col;
|
||||
col.r = texture( iChannel0, vec2(uv.x+amount,uv.y) ).r;
|
||||
col.g = texture( iChannel0, uv ).g;
|
||||
col.b = texture( iChannel0, vec2(uv.x-amount,uv.y) ).b;
|
||||
vec2 barrelDistortion(vec2 f_coords, float amt) {
|
||||
vec2 cc = f_coords - 0.5;
|
||||
float dist = dot(cc, cc);
|
||||
return f_coords + cc * dist * amt;
|
||||
}
|
||||
|
||||
col *= (1.0 - amount * 0.5);
|
||||
|
||||
out_color = vec4(col,1.0);
|
||||
}
|
||||
float sat( float t )
|
||||
{
|
||||
return clamp( t, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
float linterp( float t ) {
|
||||
return sat( 1.0 - abs( 1.0*t - 1.0 ) );
|
||||
}
|
||||
|
||||
float remap( float t, float a, float b ) {
|
||||
return sat( (t - a) / (b - a) );
|
||||
}
|
||||
|
||||
vec4 spectrum_offset( float t ) {
|
||||
vec4 ret;
|
||||
float lo = step(t,0.5);
|
||||
float hi = 1.0-lo;
|
||||
float w = linterp( remap( t, 1.0/6.0, 5.0/6.0 ) );
|
||||
ret = vec4(lo,1.0,hi, 1.) * vec4(1.0-w, w, 1.0-w, 1.);
|
||||
|
||||
return pow( ret, vec4(1.0/2.2) );
|
||||
}
|
||||
|
||||
const float max_distort = 0.05;
|
||||
const int num_iter = 10;
|
||||
const float reci_num_iter_f = 1.0 / float(num_iter);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uv=f_coords.xy;
|
||||
|
||||
vec4 sumcol = vec4(0.0);
|
||||
vec4 sumw = vec4(0.0);
|
||||
for ( int i=0; i<num_iter;++i )
|
||||
{
|
||||
float t = float(i) * reci_num_iter_f;
|
||||
vec4 w = spectrum_offset( t );
|
||||
sumw += w;
|
||||
sumcol += w * texture( iChannel0, barrelDistortion(uv, .6 * max_distort*t ) );
|
||||
}
|
||||
|
||||
out_color = sumcol / sumw;
|
||||
}
|
||||
|
||||
39
shaders/random.glsl
Normal file
39
shaders/random.glsl
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
uint Hash(uint s);
|
||||
uint Hash(uvec2 s);
|
||||
uint Hash(uvec3 s);
|
||||
uint Hash(float s);
|
||||
uint HashCombine(uint seed, uint value);
|
||||
|
||||
// Evolving Sub-Grid Turbulence for Smoke Animation
|
||||
// H. Schechter and R. Bridson
|
||||
uint Hash(uint s) {
|
||||
s ^= 2747636419u;
|
||||
s *= 2654435769u;
|
||||
s ^= s >> 16u;
|
||||
s *= 2654435769u;
|
||||
s ^= s >> 16u;
|
||||
s *= 2654435769u;
|
||||
return s;
|
||||
}
|
||||
|
||||
uint Hash(uvec2 s) {
|
||||
return HashCombine(Hash(s.x), s.y);
|
||||
}
|
||||
|
||||
uint Hash(uvec3 s) {
|
||||
return HashCombine(Hash(s.xy), s.z);
|
||||
}
|
||||
|
||||
uint HashCombine(uint seed, uint value) {
|
||||
return seed ^ (Hash(value) + 0x9e3779b9u + (seed<<6u) + (seed>>2u));
|
||||
}
|
||||
|
||||
uint Rand(inout uint seed) {
|
||||
seed = Hash(seed);
|
||||
return seed;
|
||||
}
|
||||
|
||||
float RandF(inout uint seed) {
|
||||
return float(Rand(seed)) * 2.3283064365386963e-10;
|
||||
}
|
||||
@@ -33,6 +33,8 @@ void perfgraph_panel::render_contents() {
|
||||
stopwatch = &Timer::subsystem.gfx_swap;
|
||||
else if (current_timer == gfx_gui)
|
||||
stopwatch = &Timer::subsystem.gfx_gui;
|
||||
else if (current_timer == gfx_animate)
|
||||
stopwatch = &Timer::subsystem.gfx_animate;
|
||||
else if (current_timer == sim_total)
|
||||
stopwatch = &Timer::subsystem.sim_total;
|
||||
else if (current_timer == sim_dynamics)
|
||||
|
||||
@@ -12,6 +12,7 @@ class perfgraph_panel : public ui_panel
|
||||
gfx_reflections,
|
||||
gfx_swap,
|
||||
gfx_gui,
|
||||
gfx_animate,
|
||||
sim_total,
|
||||
sim_dynamics,
|
||||
sim_events,
|
||||
@@ -31,6 +32,7 @@ class perfgraph_panel : public ui_panel
|
||||
"gfx_reflections",
|
||||
"gfx_swap",
|
||||
"gfx_gui",
|
||||
"gfx_animate",
|
||||
"sim_total",
|
||||
"sim_dynamics",
|
||||
"sim_events",
|
||||
|
||||
Reference in New Issue
Block a user