From a895844c821e34107792ba3dd81a76aa2f5b07c8 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Tue, 9 Mar 2021 13:02:53 +1100 Subject: Renaming RendererSceneRenderForward to RendererSceneRenderForwardClustered so we can introduce RendererSceneRenderForwardMobile --- .../renderer_rd/renderer_compositor_rd.cpp | 2 +- .../rendering/renderer_rd/renderer_compositor_rd.h | 4 +- .../renderer_rd/renderer_scene_render_forward.cpp | 3674 -------------------- .../renderer_rd/renderer_scene_render_forward.h | 771 ---- .../renderer_scene_render_forward_clustered.cpp | 3674 ++++++++++++++++++++ .../renderer_scene_render_forward_clustered.h | 771 ++++ servers/rendering/renderer_rd/shaders/SCsub | 2 +- .../renderer_rd/shaders/scene_forward.glsl | 3293 ------------------ .../shaders/scene_forward_clustered.glsl | 3293 ++++++++++++++++++ .../shaders/scene_forward_clustered_inc.glsl | 352 ++ .../renderer_rd/shaders/scene_forward_inc.glsl | 352 -- 11 files changed, 8094 insertions(+), 8094 deletions(-) delete mode 100644 servers/rendering/renderer_rd/renderer_scene_render_forward.cpp delete mode 100644 servers/rendering/renderer_rd/renderer_scene_render_forward.h create mode 100644 servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp create mode 100644 servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h delete mode 100644 servers/rendering/renderer_rd/shaders/scene_forward.glsl create mode 100644 servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl create mode 100644 servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl delete mode 100644 servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index be2552bd32..d5ac05d1d1 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -175,5 +175,5 @@ RendererCompositorRD::RendererCompositorRD() { storage = memnew(RendererStorageRD); canvas = memnew(RendererCanvasRenderRD(storage)); - scene = memnew(RendererSceneRenderForward(storage)); + scene = memnew(RendererSceneRenderForwardClustered(storage)); } diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index cb85fc79e0..67a843452b 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -35,14 +35,14 @@ #include "core/templates/thread_work_pool.h" #include "servers/rendering/renderer_compositor.h" #include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h" -#include "servers/rendering/renderer_rd/renderer_scene_render_forward.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h" class RendererCompositorRD : public RendererCompositor { protected: RendererCanvasRenderRD *canvas; RendererStorageRD *storage; - RendererSceneRenderForward *scene; + RendererSceneRenderRD *scene; RID copy_viewports_rd_shader; RID copy_viewports_rd_pipeline; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp deleted file mode 100644 index 874389f7e9..0000000000 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp +++ /dev/null @@ -1,3674 +0,0 @@ -/*************************************************************************/ -/* renderer_scene_render_forward.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "renderer_scene_render_forward.h" -#include "core/config/project_settings.h" -#include "servers/rendering/rendering_device.h" -#include "servers/rendering/rendering_server_default.h" - -/* SCENE SHADER */ -void RendererSceneRenderForward::ShaderData::set_code(const String &p_code) { - //compile - - code = p_code; - valid = false; - ubo_size = 0; - uniforms.clear(); - uses_screen_texture = false; - - if (code == String()) { - return; //just invalid, but no error - } - - ShaderCompilerRD::GeneratedCode gen_code; - - int blend_mode = BLEND_MODE_MIX; - int depth_testi = DEPTH_TEST_ENABLED; - int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; - int cull = CULL_BACK; - - uses_point_size = false; - uses_alpha = false; - uses_blend_alpha = false; - uses_depth_pre_pass = false; - uses_discard = false; - uses_roughness = false; - uses_normal = false; - bool wireframe = false; - - unshaded = false; - uses_vertex = false; - uses_sss = false; - uses_transmittance = false; - uses_screen_texture = false; - uses_depth_texture = false; - uses_normal_texture = false; - uses_time = false; - writes_modelview_or_projection = false; - uses_world_coordinates = false; - - int depth_drawi = DEPTH_DRAW_OPAQUE; - - ShaderCompilerRD::IdentifierActions actions; - - actions.render_mode_values["blend_add"] = Pair(&blend_mode, BLEND_MODE_ADD); - actions.render_mode_values["blend_mix"] = Pair(&blend_mode, BLEND_MODE_MIX); - actions.render_mode_values["blend_sub"] = Pair(&blend_mode, BLEND_MODE_SUB); - actions.render_mode_values["blend_mul"] = Pair(&blend_mode, BLEND_MODE_MUL); - - actions.render_mode_values["alpha_to_coverage"] = Pair(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); - actions.render_mode_values["alpha_to_coverage_and_one"] = Pair(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); - - actions.render_mode_values["depth_draw_never"] = Pair(&depth_drawi, DEPTH_DRAW_DISABLED); - actions.render_mode_values["depth_draw_opaque"] = Pair(&depth_drawi, DEPTH_DRAW_OPAQUE); - actions.render_mode_values["depth_draw_always"] = Pair(&depth_drawi, DEPTH_DRAW_ALWAYS); - - actions.render_mode_values["depth_test_disabled"] = Pair(&depth_testi, DEPTH_TEST_DISABLED); - - actions.render_mode_values["cull_disabled"] = Pair(&cull, CULL_DISABLED); - actions.render_mode_values["cull_front"] = Pair(&cull, CULL_FRONT); - actions.render_mode_values["cull_back"] = Pair(&cull, CULL_BACK); - - actions.render_mode_flags["unshaded"] = &unshaded; - actions.render_mode_flags["wireframe"] = &wireframe; - - actions.usage_flag_pointers["ALPHA"] = &uses_alpha; - actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass; - - actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; - actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; - - actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; - actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; - actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture; - actions.usage_flag_pointers["DISCARD"] = &uses_discard; - actions.usage_flag_pointers["TIME"] = &uses_time; - actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; - actions.usage_flag_pointers["NORMAL"] = &uses_normal; - actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal; - - actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; - actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; - - actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection; - actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection; - actions.write_flag_pointers["VERTEX"] = &uses_vertex; - - actions.uniforms = &uniforms; - - RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; - - Error err = scene_singleton->shader.compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code); - - ERR_FAIL_COND(err != OK); - - if (version.is_null()) { - version = scene_singleton->shader.scene_shader.version_create(); - } - - depth_draw = DepthDraw(depth_drawi); - depth_test = DepthTest(depth_testi); - -#if 0 - print_line("**compiling shader:"); - print_line("**defines:\n"); - for (int i = 0; i < gen_code.defines.size(); i++) { - print_line(gen_code.defines[i]); - } - print_line("\n**uniforms:\n" + gen_code.uniforms); - print_line("\n**vertex_globals:\n" + gen_code.vertex_global); - print_line("\n**vertex_code:\n" + gen_code.vertex); - print_line("\n**fragment_globals:\n" + gen_code.fragment_global); - print_line("\n**fragment_code:\n" + gen_code.fragment); - print_line("\n**light_code:\n" + gen_code.light); -#endif - scene_singleton->shader.scene_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines); - ERR_FAIL_COND(!scene_singleton->shader.scene_shader.version_is_valid(version)); - - ubo_size = gen_code.uniform_total_size; - ubo_offsets = gen_code.uniform_offsets; - texture_uniforms = gen_code.texture_uniforms; - - //blend modes - - // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage - if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) { - blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE; - } - - RD::PipelineColorBlendState::Attachment blend_attachment; - - switch (blend_mode) { - case BLEND_MODE_MIX: { - blend_attachment.enable_blend = true; - blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; - blend_attachment.color_blend_op = RD::BLEND_OP_ADD; - blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; - blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - - } break; - case BLEND_MODE_ADD: { - blend_attachment.enable_blend = true; - blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; - blend_attachment.color_blend_op = RD::BLEND_OP_ADD; - blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; - blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; - uses_blend_alpha = true; //force alpha used because of blend - - } break; - case BLEND_MODE_SUB: { - blend_attachment.enable_blend = true; - blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT; - blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT; - blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; - blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; - uses_blend_alpha = true; //force alpha used because of blend - - } break; - case BLEND_MODE_MUL: { - blend_attachment.enable_blend = true; - blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; - blend_attachment.color_blend_op = RD::BLEND_OP_ADD; - blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR; - blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO; - blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA; - blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; - uses_blend_alpha = true; //force alpha used because of blend - } break; - case BLEND_MODE_ALPHA_TO_COVERAGE: { - blend_attachment.enable_blend = true; - blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; - blend_attachment.color_blend_op = RD::BLEND_OP_ADD; - blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; - blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; - blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; - } - } - - RD::PipelineColorBlendState blend_state_blend; - blend_state_blend.attachments.push_back(blend_attachment); - RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1); - RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2); - RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1); - RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2); - - //update pipelines - - RD::PipelineDepthStencilState depth_stencil_state; - - if (depth_test != DEPTH_TEST_DISABLED) { - depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; - depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; - } - - for (int i = 0; i < CULL_VARIANT_MAX; i++) { - RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = { - { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK }, - { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT }, - { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED } - }; - - RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull]; - - for (int j = 0; j < RS::PRIMITIVE_MAX; j++) { - RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = { - RD::RENDER_PRIMITIVE_POINTS, - RD::RENDER_PRIMITIVE_LINES, - RD::RENDER_PRIMITIVE_LINESTRIPS, - RD::RENDER_PRIMITIVE_TRIANGLES, - RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, - }; - - RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; - - for (int k = 0; k < SHADER_VERSION_MAX; k++) { - if (!static_cast(singleton)->shader.scene_shader.is_variant_enabled(k)) { - continue; - } - RD::PipelineRasterizationState raster_state; - raster_state.cull_mode = cull_mode_rd; - raster_state.wireframe = wireframe; - - RD::PipelineColorBlendState blend_state; - RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; - RD::PipelineMultisampleState multisample_state; - - if (uses_alpha || uses_blend_alpha) { - // only allow these flags to go through if we have some form of msaa - if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { - multisample_state.enable_alpha_to_coverage = true; - } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { - multisample_state.enable_alpha_to_coverage = true; - multisample_state.enable_alpha_to_one = true; - } - - if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { - blend_state = blend_state_blend; - if (depth_draw == DEPTH_DRAW_OPAQUE) { - depth_stencil.enable_depth_write = false; //alpha does not draw depth - } - } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) { - if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { - //none, blend state contains nothing - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { - blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way - } else { - blend_state = blend_state_opaque; //writes to normal and roughness in opaque way - } - } else { - pipelines[i][j][k].clear(); - continue; // do not use this version (will error if using it is attempted) - } - } else { - if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { - blend_state = blend_state_opaque; - } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { - //none, leave empty - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { - blend_state = blend_state_depth_normal_roughness; - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) { - blend_state = blend_state_depth_normal_roughness_giprobe; - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { - blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) { - blend_state = RD::PipelineColorBlendState(); //no color targets for SDF - } else { - //specular write - blend_state = blend_state_opaque_specular; - depth_stencil.enable_depth_test = false; - depth_stencil.enable_depth_write = false; - } - } - - RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k); - pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0); - } - } - } - - valid = true; -} - -void RendererSceneRenderForward::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { - if (!p_texture.is_valid()) { - default_texture_params.erase(p_name); - } else { - default_texture_params[p_name] = p_texture; - } -} - -void RendererSceneRenderForward::ShaderData::get_param_list(List *p_param_list) const { - Map order; - - for (Map::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { - continue; - } - - if (E->get().texture_order >= 0) { - order[E->get().texture_order + 100000] = E->key(); - } else { - order[E->get().order] = E->key(); - } - } - - for (Map::Element *E = order.front(); E; E = E->next()) { - PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); - pi.name = E->get(); - p_param_list->push_back(pi); - } -} - -void RendererSceneRenderForward::ShaderData::get_instance_param_list(List *p_param_list) const { - for (Map::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { - continue; - } - - RendererStorage::InstanceShaderParam p; - p.info = ShaderLanguage::uniform_to_property_info(E->get()); - p.info.name = E->key(); //supply name - p.index = E->get().instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); - p_param_list->push_back(p); - } -} - -bool RendererSceneRenderForward::ShaderData::is_param_texture(const StringName &p_param) const { - if (!uniforms.has(p_param)) { - return false; - } - - return uniforms[p_param].texture_order >= 0; -} - -bool RendererSceneRenderForward::ShaderData::is_animated() const { - return false; -} - -bool RendererSceneRenderForward::ShaderData::casts_shadows() const { - return false; -} - -Variant RendererSceneRenderForward::ShaderData::get_default_parameter(const StringName &p_parameter) const { - if (uniforms.has(p_parameter)) { - ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; - Vector default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); - } - return Variant(); -} - -RS::ShaderNativeSourceCode RendererSceneRenderForward::ShaderData::get_native_source_code() const { - RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; - - return scene_singleton->shader.scene_shader.version_get_native_source_code(version); -} - -RendererSceneRenderForward::ShaderData::ShaderData() { - valid = false; - uses_screen_texture = false; -} - -RendererSceneRenderForward::ShaderData::~ShaderData() { - RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; - ERR_FAIL_COND(!scene_singleton); - //pipeline variants will clear themselves if shader is gone - if (version.is_valid()) { - scene_singleton->shader.scene_shader.version_free(version); - } -} - -RendererStorageRD::ShaderData *RendererSceneRenderForward::_create_shader_func() { - ShaderData *shader_data = memnew(ShaderData); - return shader_data; -} - -void RendererSceneRenderForward::MaterialData::set_render_priority(int p_priority) { - priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits -} - -void RendererSceneRenderForward::MaterialData::set_next_pass(RID p_pass) { - next_pass = p_pass; -} - -void RendererSceneRenderForward::MaterialData::update_parameters(const Map &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; - - if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { - p_uniform_dirty = true; - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - uniform_buffer = RID(); - } - - ubo_data.resize(shader_data->ubo_size); - if (ubo_data.size()) { - uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); - memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear - } - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - //check whether buffer changed - if (p_uniform_dirty && ubo_data.size()) { - update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); - RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER); - } - - uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); - - if ((uint32_t)texture_cache.size() != tex_uniform_count) { - texture_cache.resize(tex_uniform_count); - p_textures_dirty = true; - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); - } - - if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { - // This material does not require an uniform set, so don't create it. - return; - } - - if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - //no reason to update uniform set, only UBO (or nothing) was needed to update - return; - } - - Vector uniforms; - - { - if (shader_data->ubo_size) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.ids.push_back(uniform_buffer); - uniforms.push_back(u); - } - - const RID *textures = texture_cache.ptrw(); - for (uint32_t i = 0; i < tex_uniform_count; i++) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1 + i; - u.ids.push_back(textures[i]); - uniforms.push_back(u); - } - } - - uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET); -} - -RendererSceneRenderForward::MaterialData::~MaterialData() { - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - } - - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - } -} - -RendererStorageRD::MaterialData *RendererSceneRenderForward::_create_material_func(ShaderData *p_shader) { - MaterialData *material_data = memnew(MaterialData); - material_data->shader_data = p_shader; - material_data->last_frame = false; - //update will happen later anyway so do nothing. - return material_data; -} - -RendererSceneRenderForward::RenderBufferDataForward::~RenderBufferDataForward() { - clear(); -} - -void RendererSceneRenderForward::RenderBufferDataForward::ensure_specular() { - if (!specular.is_valid()) { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.width = width; - tf.height = height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - if (msaa != RS::VIEWPORT_MSAA_DISABLED) { - tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; - } else { - tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - } - - specular = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - if (msaa == RS::VIEWPORT_MSAA_DISABLED) { - { - Vector fb; - fb.push_back(color); - fb.push_back(specular); - fb.push_back(depth); - - color_specular_fb = RD::get_singleton()->framebuffer_create(fb); - } - { - Vector fb; - fb.push_back(specular); - - specular_only_fb = RD::get_singleton()->framebuffer_create(fb); - } - - } else { - tf.samples = texture_samples; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; - specular_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - { - Vector fb; - fb.push_back(color_msaa); - fb.push_back(specular_msaa); - fb.push_back(depth_msaa); - - color_specular_fb = RD::get_singleton()->framebuffer_create(fb); - } - { - Vector fb; - fb.push_back(specular_msaa); - - specular_only_fb = RD::get_singleton()->framebuffer_create(fb); - } - } - } -} - -void RendererSceneRenderForward::RenderBufferDataForward::ensure_giprobe() { - if (!giprobe_buffer.is_valid()) { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R8G8_UINT; - tf.width = width; - tf.height = height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; - - if (msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::TextureFormat tf_aa = tf; - tf_aa.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tf_aa.samples = texture_samples; - giprobe_buffer_msaa = RD::get_singleton()->texture_create(tf_aa, RD::TextureView()); - } else { - tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - } - - tf.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT; - - giprobe_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - Vector fb; - if (msaa != RS::VIEWPORT_MSAA_DISABLED) { - fb.push_back(depth_msaa); - fb.push_back(normal_roughness_buffer_msaa); - fb.push_back(giprobe_buffer_msaa); - } else { - fb.push_back(depth); - fb.push_back(normal_roughness_buffer); - fb.push_back(giprobe_buffer); - } - - depth_normal_roughness_giprobe_fb = RD::get_singleton()->framebuffer_create(fb); - } -} - -void RendererSceneRenderForward::RenderBufferDataForward::clear() { - if (giprobe_buffer != RID()) { - RD::get_singleton()->free(giprobe_buffer); - giprobe_buffer = RID(); - - if (giprobe_buffer_msaa.is_valid()) { - RD::get_singleton()->free(giprobe_buffer_msaa); - giprobe_buffer_msaa = RID(); - } - - depth_normal_roughness_giprobe_fb = RID(); - } - - if (color_msaa.is_valid()) { - RD::get_singleton()->free(color_msaa); - color_msaa = RID(); - } - - if (depth_msaa.is_valid()) { - RD::get_singleton()->free(depth_msaa); - depth_msaa = RID(); - } - - if (specular.is_valid()) { - if (specular_msaa.is_valid()) { - RD::get_singleton()->free(specular_msaa); - specular_msaa = RID(); - } - RD::get_singleton()->free(specular); - specular = RID(); - } - - color = RID(); - depth = RID(); - color_specular_fb = RID(); - specular_only_fb = RID(); - color_fb = RID(); - depth_fb = RID(); - - if (normal_roughness_buffer.is_valid()) { - RD::get_singleton()->free(normal_roughness_buffer); - if (normal_roughness_buffer_msaa.is_valid()) { - RD::get_singleton()->free(normal_roughness_buffer_msaa); - normal_roughness_buffer_msaa = RID(); - } - normal_roughness_buffer = RID(); - depth_normal_roughness_fb = RID(); - } - - if (!render_sdfgi_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_sdfgi_uniform_set)) { - RD::get_singleton()->free(render_sdfgi_uniform_set); - } -} - -void RendererSceneRenderForward::RenderBufferDataForward::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { - clear(); - - msaa = p_msaa; - - width = p_width; - height = p_height; - - color = p_color_buffer; - depth = p_depth_buffer; - - if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) { - { - Vector fb; - fb.push_back(p_color_buffer); - fb.push_back(depth); - - color_fb = RD::get_singleton()->framebuffer_create(fb); - } - { - Vector fb; - fb.push_back(depth); - - depth_fb = RD::get_singleton()->framebuffer_create(fb); - } - } else { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.width = p_width; - tf.height = p_height; - tf.texture_type = RD::TEXTURE_TYPE_2D; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - - RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = { - RD::TEXTURE_SAMPLES_1, - RD::TEXTURE_SAMPLES_2, - RD::TEXTURE_SAMPLES_4, - RD::TEXTURE_SAMPLES_8, - RD::TEXTURE_SAMPLES_16 - }; - - texture_samples = ts[p_msaa]; - tf.samples = texture_samples; - - color_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; - tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - - depth_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - { - Vector fb; - fb.push_back(color_msaa); - fb.push_back(depth_msaa); - - color_fb = RD::get_singleton()->framebuffer_create(fb); - } - { - Vector fb; - fb.push_back(depth_msaa); - - depth_fb = RD::get_singleton()->framebuffer_create(fb); - } - } -} - -void RendererSceneRenderForward::_allocate_normal_roughness_texture(RenderBufferDataForward *rb) { - if (rb->normal_roughness_buffer.is_valid()) { - return; - } - - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; - tf.width = rb->width; - tf.height = rb->height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - - if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { - tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - } else { - tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - } - - rb->normal_roughness_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) { - Vector fb; - fb.push_back(rb->depth); - fb.push_back(rb->normal_roughness_buffer); - rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); - } else { - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - tf.samples = rb->texture_samples; - rb->normal_roughness_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - Vector fb; - fb.push_back(rb->depth_msaa); - fb.push_back(rb->normal_roughness_buffer_msaa); - rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); - } - - _render_buffers_clear_uniform_set(rb); -} - -RendererSceneRenderRD::RenderBufferData *RendererSceneRenderForward::_create_render_buffer_data() { - return memnew(RenderBufferDataForward); -} - -bool RendererSceneRenderForward::free(RID p_rid) { - if (RendererSceneRenderRD::free(p_rid)) { - return true; - } - return false; -} - -/// RENDERING /// - -template -void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { - RD::DrawListID draw_list = p_draw_list; - RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; - - //global scope bindings - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET); - - RID prev_material_uniform_set; - - RID prev_vertex_array_rd; - RID prev_index_array_rd; - RID prev_pipeline_rd; - RID prev_xforms_uniform_set; - - bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP); - - SceneState::PushConstant push_constant; - - if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) { - push_constant.uv_offset = Math::make_half_float(p_params->uv_offset.y) << 16; - push_constant.uv_offset |= Math::make_half_float(p_params->uv_offset.x); - } else { - push_constant.uv_offset = 0; - } - - for (uint32_t i = p_from_element; i < p_to_element; i++) { - const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i]; - const RenderElementInfo &element_info = p_params->element_info[i]; - - push_constant.base_index = i + p_params->element_offset; - - RID material_uniform_set; - ShaderData *shader; - void *mesh_surface; - - if (shadow_pass || p_params->pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too - material_uniform_set = surf->material_uniform_set_shadow; - shader = surf->shader_shadow; - mesh_surface = surf->surface_shadow; - - } else { - material_uniform_set = surf->material_uniform_set; - shader = surf->shader; - mesh_surface = surf->surface; - } - - if (!mesh_surface) { - continue; - } - - //find cull variant - ShaderData::CullVariant cull_variant; - - if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || p_params->pass_mode == PASS_MODE_SDF || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) { - cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED; - } else { - bool mirror = surf->owner->mirror; - if (p_params->reverse_cull) { - mirror = !mirror; - } - cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL; - } - - RS::PrimitiveType primitive = surf->primitive; - RID xforms_uniform_set = surf->owner->transforms_uniform_set; - - ShaderVersion shader_version = SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized. - - switch (p_params->pass_mode) { - case PASS_MODE_COLOR: - case PASS_MODE_COLOR_TRANSPARENT: { - if (element_info.uses_lightmap) { - shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS; - } else if (element_info.uses_forward_gi) { - shader_version = SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI; - } else { - shader_version = SHADER_VERSION_COLOR_PASS; - } - } break; - case PASS_MODE_COLOR_SPECULAR: { - if (element_info.uses_lightmap) { - shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR; - } else { - shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; - } - } break; - case PASS_MODE_SHADOW: - case PASS_MODE_DEPTH: { - shader_version = SHADER_VERSION_DEPTH_PASS; - } break; - case PASS_MODE_SHADOW_DP: { - shader_version = SHADER_VERSION_DEPTH_PASS_DP; - } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { - shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS; - } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { - shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE; - } break; - case PASS_MODE_DEPTH_MATERIAL: { - shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL; - } break; - case PASS_MODE_SDF: { - shader_version = SHADER_VERSION_DEPTH_PASS_WITH_SDF; - } break; - } - - PipelineCacheRD *pipeline = nullptr; - - pipeline = &shader->pipelines[cull_variant][primitive][shader_version]; - - RD::VertexFormatID vertex_format = -1; - RID vertex_array_rd; - RID index_array_rd; - - //skeleton and blend shape - if (surf->owner->mesh_instance.is_valid()) { - storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); - } else { - storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); - } - - index_array_rd = storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index); - - if (prev_vertex_array_rd != vertex_array_rd) { - RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd); - prev_vertex_array_rd = vertex_array_rd; - } - - if (prev_index_array_rd != index_array_rd) { - if (index_array_rd.is_valid()) { - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array_rd); - } - prev_index_array_rd = index_array_rd; - } - - RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe); - - if (pipeline_rd != prev_pipeline_rd) { - // checking with prev shader does not make so much sense, as - // the pipeline may still be different. - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd); - prev_pipeline_rd = pipeline_rd; - } - - if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, TRANSFORMS_UNIFORM_SET); - prev_xforms_uniform_set = xforms_uniform_set; - } - - if (material_uniform_set != prev_material_uniform_set) { - //update uniform set - if (material_uniform_set.is_valid()) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET); - } - - prev_material_uniform_set = material_uniform_set; - } - - RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant)); - - uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : element_info.repeat; - RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count); - i += element_info.repeat - 1; //skip equal elements - } -} - -void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { - //use template for faster performance (pass mode comparisons are inlined) - - switch (p_params->pass_mode) { - case PASS_MODE_COLOR: { - _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); - } break; - case PASS_MODE_COLOR_SPECULAR: { - _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); - } break; - case PASS_MODE_COLOR_TRANSPARENT: { - _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); - } break; - case PASS_MODE_SHADOW: { - _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); - } break; - case PASS_MODE_SHADOW_DP: { - _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); - } break; - case PASS_MODE_DEPTH: { - _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); - } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { - _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); - } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { - _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); - } break; - case PASS_MODE_DEPTH_MATERIAL: { - _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); - } break; - case PASS_MODE_SDF: { - _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); - } break; - } -} - -void RendererSceneRenderForward::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) { - uint32_t render_total = p_params->element_count; - uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); - uint32_t render_from = p_thread * render_total / total_threads; - uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads); - _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to); -} - -void RendererSceneRenderForward::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector &p_storage_textures) { - RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer); - p_params->framebuffer_format = fb_format; - - if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time - //multi threaded - thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); - RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); - RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RendererSceneRenderForward::_render_list_thread_function, p_params); - RD::get_singleton()->draw_list_end(p_params->barrier); - } else { - //single threaded - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); - _render_list(draw_list, fb_format, p_params, 0, p_params->element_count); - RD::get_singleton()->draw_list_end(p_params->barrier); - } -} - -void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) { - //CameraMatrix projection = p_cam_projection; - //projection.flip_y(); // Vulkan and modern APIs use Y-Down - CameraMatrix correction; - correction.set_depth_correction(p_flip_y); - CameraMatrix projection = correction * p_cam_projection; - - //store camera into ubo - RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix); - RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); - RendererStorageRD::store_transform(p_cam_transform, scene_state.ubo.camera_matrix); - RendererStorageRD::store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); - - scene_state.ubo.z_far = p_zfar; - scene_state.ubo.z_near = p_znear; - - scene_state.ubo.pancake_shadows = p_pancake_shadows; - - RendererStorageRD::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); - RendererStorageRD::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); - RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); - RendererStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); - - scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get(); - scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get(); - scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get(); - scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get(); - - Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size); - scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x; - scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y; - - scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_cluster_size); - scene_state.ubo.max_cluster_element_count_div_32 = p_max_cluster_elements / 32; - { - uint32_t cluster_screen_width = (p_screen_size.width - 1) / p_cluster_size + 1; - uint32_t cluster_screen_height = (p_screen_size.height - 1) / p_cluster_size + 1; - scene_state.ubo.cluster_type_size = cluster_screen_width * cluster_screen_height * (scene_state.ubo.max_cluster_element_count_div_32 + 32); - scene_state.ubo.cluster_width = cluster_screen_width; - } - - if (p_shadow_atlas.is_valid()) { - Vector2 sas = shadow_atlas_get_size(p_shadow_atlas); - scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x; - scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y; - } - { - Vector2 dss = directional_shadow_get_size(); - scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x; - scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y; - } - //time global variables - scene_state.ubo.time = time; - - scene_state.ubo.gi_upscale_for_msaa = false; - scene_state.ubo.volumetric_fog_enabled = false; - scene_state.ubo.fog_enabled = false; - - if (p_render_buffers.is_valid()) { - RenderBufferDataForward *render_buffers = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); - if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) { - scene_state.ubo.gi_upscale_for_msaa = true; - } - - if (render_buffers_has_volumetric_fog(p_render_buffers)) { - scene_state.ubo.volumetric_fog_enabled = true; - float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers); - if (fog_end > 0.0) { - scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end; - } else { - scene_state.ubo.volumetric_fog_inv_length = 1.0; - } - - float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup - if (fog_detail_spread > 0.0) { - scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread; - } else { - scene_state.ubo.volumetric_fog_detail_spread = 1.0; - } - } - } -#if 0 - if (p_render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_buffers)) { - scene_state.ubo.sdfgi_cascade_count = render_buffers_get_sdfgi_cascade_count(p_render_buffers); - scene_state.ubo.sdfgi_probe_axis_size = render_buffers_get_sdfgi_cascade_probe_count(p_render_buffers); - scene_state.ubo.sdfgi_cascade_probe_size[0] = scene_state.ubo.sdfgi_probe_axis_size - 1; //float version for performance - scene_state.ubo.sdfgi_cascade_probe_size[1] = scene_state.ubo.sdfgi_probe_axis_size - 1; - scene_state.ubo.sdfgi_cascade_probe_size[2] = scene_state.ubo.sdfgi_probe_axis_size - 1; - - float csize = render_buffers_get_sdfgi_cascade_size(p_render_buffers); - scene_state.ubo.sdfgi_probe_to_uvw = 1.0 / float(scene_state.ubo.sdfgi_cascade_probe_size[0]); - float occ_bias = 0.0; - scene_state.ubo.sdfgi_occlusion_bias = occ_bias / csize; - scene_state.ubo.sdfgi_use_occlusion = render_buffers_is_sdfgi_using_occlusion(p_render_buffers); - scene_state.ubo.sdfgi_energy = render_buffers_get_sdfgi_energy(p_render_buffers); - - float cascade_voxel_size = (csize / scene_state.ubo.sdfgi_cascade_probe_size[0]); - float occlusion_clamp = (cascade_voxel_size - 0.5) / cascade_voxel_size; - scene_state.ubo.sdfgi_occlusion_clamp[0] = occlusion_clamp; - scene_state.ubo.sdfgi_occlusion_clamp[1] = occlusion_clamp; - scene_state.ubo.sdfgi_occlusion_clamp[2] = occlusion_clamp; - scene_state.ubo.sdfgi_normal_bias = (render_buffers_get_sdfgi_normal_bias(p_render_buffers) / csize) * scene_state.ubo.sdfgi_cascade_probe_size[0]; - - //vec2 tex_pixel_size = 1.0 / vec2(ivec2( (OCT_SIZE+2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE+2) * params.probe_axis_size ) ); - //vec3 probe_uv_offset = (ivec3(OCT_SIZE+2,OCT_SIZE+2,(OCT_SIZE+2) * params.probe_axis_size)) * tex_pixel_size.xyx; - - uint32_t oct_size = gi.sdfgi_get_lightprobe_octahedron_size(); - - scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size * scene_state.ubo.sdfgi_probe_axis_size); - scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size); - scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[2] = 1.0; - - scene_state.ubo.sdfgi_probe_uv_offset[0] = float(oct_size + 2) * scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[0]; - scene_state.ubo.sdfgi_probe_uv_offset[1] = float(oct_size + 2) * scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[1]; - scene_state.ubo.sdfgi_probe_uv_offset[2] = float((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size) * scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[0]; - - scene_state.ubo.sdfgi_occlusion_renormalize[0] = 0.5; - scene_state.ubo.sdfgi_occlusion_renormalize[1] = 1.0; - scene_state.ubo.sdfgi_occlusion_renormalize[2] = 1.0 / float(scene_state.ubo.sdfgi_cascade_count); - - for (uint32_t i = 0; i < scene_state.ubo.sdfgi_cascade_count; i++) { - SceneState::UBO::SDFGICascade &c = scene_state.ubo.sdfgi_cascades[i]; - Vector3 pos = render_buffers_get_sdfgi_cascade_offset(p_render_buffers, i); - pos -= p_cam_transform.origin; //make pos local to camera, to reduce numerical error - c.position[0] = pos.x; - c.position[1] = pos.y; - c.position[2] = pos.z; - c.to_probe = 1.0 / render_buffers_get_sdfgi_cascade_probe_size(p_render_buffers, i); - - Vector3i probe_ofs = render_buffers_get_sdfgi_cascade_probe_offset(p_render_buffers, i); - c.probe_world_offset[0] = probe_ofs.x; - c.probe_world_offset[1] = probe_ofs.y; - c.probe_world_offset[2] = probe_ofs.z; - } - } -#endif - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { - scene_state.ubo.use_ambient_light = true; - scene_state.ubo.ambient_light_color_energy[0] = 1; - scene_state.ubo.ambient_light_color_energy[1] = 1; - scene_state.ubo.ambient_light_color_energy[2] = 1; - scene_state.ubo.ambient_light_color_energy[3] = 1.0; - scene_state.ubo.use_ambient_cubemap = false; - scene_state.ubo.use_reflection_cubemap = false; - scene_state.ubo.ssao_enabled = false; - - } else if (is_environment(p_environment)) { - RS::EnvironmentBG env_bg = environment_get_background(p_environment); - RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_environment); - - float bg_energy = environment_get_bg_energy(p_environment); - scene_state.ubo.ambient_light_color_energy[3] = bg_energy; - - scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_environment); - - //ambient - if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) { - Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_environment); - color = color.to_linear(); - - scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy; - scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy; - scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy; - scene_state.ubo.use_ambient_light = true; - scene_state.ubo.use_ambient_cubemap = false; - } else { - float energy = environment_get_ambient_light_energy(p_environment); - Color color = environment_get_ambient_light_color(p_environment); - color = color.to_linear(); - scene_state.ubo.ambient_light_color_energy[0] = color.r * energy; - scene_state.ubo.ambient_light_color_energy[1] = color.g * energy; - scene_state.ubo.ambient_light_color_energy[2] = color.b * energy; - - Basis sky_transform = environment_get_sky_orientation(p_environment); - sky_transform = sky_transform.inverse() * p_cam_transform.basis; - RendererStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); - - scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY; - scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR; - } - - //specular - RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_environment); - if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) { - scene_state.ubo.use_reflection_cubemap = true; - } else { - scene_state.ubo.use_reflection_cubemap = false; - } - - scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_is_ssao_enabled(p_environment); - scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_environment); - scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_environment); - - Color ao_color = environment_get_ao_color(p_environment).to_linear(); - scene_state.ubo.ao_color[0] = ao_color.r; - scene_state.ubo.ao_color[1] = ao_color.g; - scene_state.ubo.ao_color[2] = ao_color.b; - scene_state.ubo.ao_color[3] = ao_color.a; - - scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment); - scene_state.ubo.fog_density = environment_get_fog_density(p_environment); - scene_state.ubo.fog_height = environment_get_fog_height(p_environment); - scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_environment); - if (scene_state.ubo.fog_height_density >= 0.0001) { - scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density; - } - scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment); - - Color fog_color = environment_get_fog_light_color(p_environment).to_linear(); - float fog_energy = environment_get_fog_light_energy(p_environment); - - scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; - scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy; - scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; - - scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment); - - } else { - if (p_reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) { - scene_state.ubo.use_ambient_light = false; - } else { - scene_state.ubo.use_ambient_light = true; - Color clear_color = p_default_bg_color; - clear_color = clear_color.to_linear(); - scene_state.ubo.ambient_light_color_energy[0] = clear_color.r; - scene_state.ubo.ambient_light_color_energy[1] = clear_color.g; - scene_state.ubo.ambient_light_color_energy[2] = clear_color.b; - scene_state.ubo.ambient_light_color_energy[3] = 1.0; - } - - scene_state.ubo.use_ambient_cubemap = false; - scene_state.ubo.use_reflection_cubemap = false; - scene_state.ubo.ssao_enabled = false; - } - - scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active(); - scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount(); - scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit(); - - if (p_index >= (int)scene_state.uniform_buffers.size()) { - uint32_t from = scene_state.uniform_buffers.size(); - scene_state.uniform_buffers.resize(p_index + 1); - render_pass_uniform_sets.resize(p_index + 1); - for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) { - scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); - } - } - RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER); -} - -void RendererSceneRenderForward::_update_instance_data_buffer(RenderListType p_render_list) { - if (scene_state.instance_data[p_render_list].size() > 0) { - if (scene_state.instance_buffer[p_render_list] == RID() || scene_state.instance_buffer_size[p_render_list] < scene_state.instance_data[p_render_list].size()) { - if (scene_state.instance_buffer[p_render_list] != RID()) { - RD::get_singleton()->free(scene_state.instance_buffer[p_render_list]); - } - uint32_t new_size = nearest_power_of_2_templated(MAX(uint64_t(INSTANCE_DATA_BUFFER_MIN_SIZE), scene_state.instance_data[p_render_list].size())); - scene_state.instance_buffer[p_render_list] = RD::get_singleton()->storage_buffer_create(new_size * sizeof(SceneState::InstanceData)); - scene_state.instance_buffer_size[p_render_list] = new_size; - } - RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER); - } -} -void RendererSceneRenderForward::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { - RenderList *rl = &render_list[p_render_list]; - uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size(); - - scene_state.instance_data[p_render_list].resize(p_offset + element_total); - rl->element_info.resize(p_offset + element_total); - - uint32_t repeats = 0; - GeometryInstanceSurfaceDataCache *prev_surface = nullptr; - for (uint32_t i = 0; i < element_total; i++) { - GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset]; - GeometryInstanceForward *inst = surface->owner; - - SceneState::InstanceData &instance_data = scene_state.instance_data[p_render_list][i + p_offset]; - - if (inst->store_transform_cache) { - RendererStorageRD::store_transform(inst->transform, instance_data.transform); - } else { - RendererStorageRD::store_transform(Transform(), instance_data.transform); - } - - instance_data.flags = inst->flags_cache; - instance_data.gi_offset = inst->gi_offset_cache; - instance_data.layer_mask = inst->layer_mask; - instance_data.instance_uniforms_ofs = uint32_t(inst->shader_parameters_offset); - instance_data.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x; - instance_data.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y; - instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x; - instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y; - - bool cant_repeat = instance_data.flags & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid(); - - if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2) { - //this element is the same as the previous one, count repeats to draw it using instancing - repeats++; - } else { - if (repeats > 0) { - for (uint32_t j = 1; j <= repeats; j++) { - rl->element_info[p_offset + i - j].repeat = j; - } - } - repeats = 1; - } - - RenderElementInfo &element_info = rl->element_info[p_offset + i]; - - element_info.lod_index = surface->sort.lod_index; - element_info.uses_forward_gi = surface->sort.uses_forward_gi; - element_info.uses_lightmap = surface->sort.uses_lightmap; - - if (cant_repeat) { - prev_surface = nullptr; - } else { - prev_surface = surface; - } - } - - if (repeats > 0) { - for (uint32_t j = 1; j <= repeats; j++) { - rl->element_info[p_offset + element_total - j].repeat = j; - } - } - - if (p_update_buffer) { - _update_instance_data_buffer(p_render_list); - } -} - -void RendererSceneRenderForward::_fill_render_list(RenderListType p_render_list, const PagedArray &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_append) { - if (p_render_list == RENDER_LIST_OPAQUE) { - scene_state.used_sss = false; - scene_state.used_screen_texture = false; - scene_state.used_normal_texture = false; - scene_state.used_depth_texture = false; - } - uint32_t lightmap_captures_used = 0; - - Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); - near_plane.d += p_cam_projection.get_z_near(); - float z_max = p_cam_projection.get_z_far() - p_cam_projection.get_z_near(); - - RenderList *rl = &render_list[p_render_list]; - _update_dirty_geometry_instances(); - - if (!p_append) { - rl->clear(); - if (p_render_list == RENDER_LIST_OPAQUE) { - render_list[RENDER_LIST_ALPHA].clear(); //opaque fills alpha too - } - } - - //fill list - - for (int i = 0; i < (int)p_instances.size(); i++) { - GeometryInstanceForward *inst = static_cast(p_instances[i]); - - Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal); - inst->depth = near_plane.distance_to(support_min); - uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15); - - uint32_t flags = inst->base_flags; //fill flags if appropriate - - bool uses_lightmap = false; - bool uses_gi = false; - - if (p_render_list == RENDER_LIST_OPAQUE) { - //setup GI - - if (inst->lightmap_instance.is_valid()) { - int32_t lightmap_cull_index = -1; - for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) { - if (scene_state.lightmap_ids[j] == inst->lightmap_instance) { - lightmap_cull_index = j; - break; - } - } - if (lightmap_cull_index >= 0) { - inst->gi_offset_cache = inst->lightmap_slice_index << 16; - inst->gi_offset_cache |= lightmap_cull_index; - flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP; - if (scene_state.lightmap_has_sh[lightmap_cull_index]) { - flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP; - } - uses_lightmap = true; - } else { - inst->gi_offset_cache = 0xFFFFFFFF; - } - - } else if (inst->lightmap_sh) { - if (lightmap_captures_used < scene_state.max_lightmap_captures) { - const Color *src_capture = inst->lightmap_sh->sh; - LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used]; - for (int j = 0; j < 9; j++) { - lcd.sh[j * 4 + 0] = src_capture[j].r; - lcd.sh[j * 4 + 1] = src_capture[j].g; - lcd.sh[j * 4 + 2] = src_capture[j].b; - lcd.sh[j * 4 + 3] = src_capture[j].a; - } - flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE; - inst->gi_offset_cache = lightmap_captures_used; - lightmap_captures_used++; - uses_lightmap = true; - } - - } else if (!low_end) { - if (p_using_opaque_gi) { - flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; - } - - if (inst->gi_probes[0].is_valid()) { - uint32_t probe0_index = 0xFFFF; - uint32_t probe1_index = 0xFFFF; - - for (uint32_t j = 0; j < scene_state.giprobes_used; j++) { - if (scene_state.giprobe_ids[j] == inst->gi_probes[0]) { - probe0_index = j; - } else if (scene_state.giprobe_ids[j] == inst->gi_probes[1]) { - probe1_index = j; - } - } - - if (probe0_index == 0xFFFF && probe1_index != 0xFFFF) { - //0 must always exist if a probe exists - SWAP(probe0_index, probe1_index); - } - - inst->gi_offset_cache = probe0_index | (probe1_index << 16); - flags |= INSTANCE_DATA_FLAG_USE_GIPROBE; - uses_gi = true; - } else { - if (p_using_sdfgi && inst->can_sdfgi) { - flags |= INSTANCE_DATA_FLAG_USE_SDFGI; - uses_gi = true; - } - inst->gi_offset_cache = 0xFFFFFFFF; - } - } - } - inst->flags_cache = flags; - - GeometryInstanceSurfaceDataCache *surf = inst->surface_caches; - - while (surf) { - surf->sort.uses_forward_gi = 0; - surf->sort.uses_lightmap = 0; - - // LOD - - if (p_screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) { - //lod - Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_lod_plane.normal); - Vector3 lod_support_max = inst->transformed_aabb.get_support(p_lod_plane.normal); - - float distance_min = p_lod_plane.distance_to(lod_support_min); - float distance_max = p_lod_plane.distance_to(lod_support_max); - - float distance = 0.0; - - if (distance_min * distance_max < 0.0) { - //crossing plane - distance = 0.0; - } else if (distance_min >= 0.0) { - distance = distance_min; - } else if (distance_max <= 0.0) { - distance = -distance_max; - } - - surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_lod_distance_multiplier, p_screen_lod_threshold); - } else { - surf->sort.lod_index = 0; - } - - // ADD Element - if (p_pass_mode == PASS_MODE_COLOR) { - if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { - rl->add_element(surf); - } - if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) { - render_list[RENDER_LIST_ALPHA].add_element(surf); - if (uses_gi) { - surf->sort.uses_forward_gi = 1; - } - } - - if (uses_lightmap) { - surf->sort.uses_lightmap = 1; - } - - if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) { - scene_state.used_sss = true; - } - if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) { - scene_state.used_screen_texture = true; - } - if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE) { - scene_state.used_normal_texture = true; - } - if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) { - scene_state.used_depth_texture = true; - } - - } else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) { - if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) { - rl->add_element(surf); - } - } else { - if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { - rl->add_element(surf); - } - } - - surf->sort.depth_layer = depth_layer; - - surf = surf->next; - } - } - - if (p_render_list == RENDER_LIST_OPAQUE && lightmap_captures_used) { - RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures, RD::BARRIER_MASK_RASTER); - } -} - -void RendererSceneRenderForward::_setup_giprobes(const PagedArray &p_giprobes) { - scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES)); - for (uint32_t i = 0; i < scene_state.giprobes_used; i++) { - scene_state.giprobe_ids[i] = p_giprobes[i]; - } -} - -void RendererSceneRenderForward::_setup_lightmaps(const PagedArray &p_lightmaps, const Transform &p_cam_transform) { - scene_state.lightmaps_used = 0; - for (int i = 0; i < (int)p_lightmaps.size(); i++) { - if (i >= (int)scene_state.max_lightmaps) { - break; - } - - RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]); - - Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis; - to_lm = to_lm.inverse().transposed(); //will transform normals - RendererStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform); - scene_state.lightmap_ids[i] = p_lightmaps[i]; - scene_state.lightmap_has_sh[i] = storage->lightmap_uses_spherical_harmonics(lightmap); - - scene_state.lightmaps_used++; - } - if (scene_state.lightmaps_used > 0) { - RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER); - } -} - -void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, const PagedArray &p_gi_probes, const PagedArray &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) { - RenderBufferDataForward *render_buffer = nullptr; - if (p_render_buffer.is_valid()) { - render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer); - } - RendererSceneEnvironmentRD *env = get_environment(p_environment); - - //first of all, make a new render pass - //fill up ubo - - RENDER_TIMESTAMP("Setup 3D Scene"); - - float lod_distance_multiplier = p_cam_projection.get_lod_multiplier(); - Plane lod_camera_plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); - - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { - p_screen_lod_threshold = 0.0; - } - - //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size; - - Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); - scene_state.ubo.viewport_size[0] = vp_he.x; - scene_state.ubo.viewport_size[1] = vp_he.y; - scene_state.ubo.directional_light_count = 0; - - Size2i screen_size; - RID opaque_framebuffer; - RID opaque_specular_framebuffer; - RID depth_framebuffer; - RID alpha_framebuffer; - - PassMode depth_pass_mode = PASS_MODE_DEPTH; - Vector depth_pass_clear; - bool using_separate_specular = false; - bool using_ssr = false; - bool using_sdfgi = false; - bool using_giprobe = false; - - if (render_buffer) { - screen_size.x = render_buffer->width; - screen_size.y = render_buffer->height; - - opaque_framebuffer = render_buffer->color_fb; - - if (!low_end && p_gi_probes.size() > 0) { - using_giprobe = true; - } - - if (!p_environment.is_valid() && using_giprobe) { - depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE; - - } else if (p_environment.is_valid() && (environment_is_ssr_enabled(p_environment) || environment_is_sdfgi_enabled(p_environment) || using_giprobe)) { - if (environment_is_sdfgi_enabled(p_environment)) { - depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also giprobe - using_sdfgi = true; - } else { - depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; - } - - if (environment_is_ssr_enabled(p_environment)) { - render_buffer->ensure_specular(); - using_separate_specular = true; - using_ssr = true; - opaque_specular_framebuffer = render_buffer->color_specular_fb; - } - - } else if (p_environment.is_valid() && (environment_is_ssao_enabled(p_environment) || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) { - depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS; - } - - switch (depth_pass_mode) { - case PASS_MODE_DEPTH: { - depth_framebuffer = render_buffer->depth_fb; - } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { - _allocate_normal_roughness_texture(render_buffer); - depth_framebuffer = render_buffer->depth_normal_roughness_fb; - depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0)); - } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { - _allocate_normal_roughness_texture(render_buffer); - render_buffer->ensure_giprobe(); - depth_framebuffer = render_buffer->depth_normal_roughness_giprobe_fb; - depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0)); - depth_pass_clear.push_back(Color(0, 0, 0, 0)); - } break; - default: { - }; - } - - alpha_framebuffer = opaque_framebuffer; - } else if (p_reflection_probe.is_valid()) { - uint32_t resolution = reflection_probe_instance_get_resolution(p_reflection_probe); - screen_size.x = resolution; - screen_size.y = resolution; - - opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass); - depth_framebuffer = reflection_probe_instance_get_depth_framebuffer(p_reflection_probe, p_reflection_probe_pass); - alpha_framebuffer = opaque_framebuffer; - - if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) { - p_environment = RID(); //no environment on interiors - } - } else { - ERR_FAIL(); //bug? - } - - RD::get_singleton()->draw_command_begin_label("Render Setup"); - - _setup_lightmaps(p_lightmaps, p_cam_transform); - _setup_giprobes(p_gi_probes); - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); - - _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example) - - _fill_render_list(RENDER_LIST_OPAQUE, p_instances, PASS_MODE_COLOR, p_cam_projection, p_cam_transform, using_sdfgi, using_sdfgi || using_giprobe, lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); - render_list[RENDER_LIST_OPAQUE].sort_by_key(); - render_list[RENDER_LIST_ALPHA].sort_by_depth(); - _fill_instance_data(RENDER_LIST_OPAQUE); - _fill_instance_data(RENDER_LIST_ALPHA); - - RD::get_singleton()->draw_command_end_label(); - - bool using_sss = !low_end && render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; - - if (using_sss) { - using_separate_specular = true; - render_buffer->ensure_specular(); - using_separate_specular = true; - opaque_specular_framebuffer = render_buffer->color_specular_fb; - } - RID radiance_texture; - bool draw_sky = false; - bool draw_sky_fog_only = false; - - Color clear_color; - bool keep_color = false; - - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { - clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black - } else if (is_environment(p_environment)) { - RS::EnvironmentBG bg_mode = environment_get_background(p_environment); - float bg_energy = environment_get_bg_energy(p_environment); - switch (bg_mode) { - case RS::ENV_BG_CLEAR_COLOR: { - clear_color = p_default_bg_color; - clear_color.r *= bg_energy; - clear_color.g *= bg_energy; - clear_color.b *= bg_energy; - if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) { - draw_sky_fog_only = true; - storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); - } - } break; - case RS::ENV_BG_COLOR: { - clear_color = environment_get_bg_color(p_environment); - clear_color.r *= bg_energy; - clear_color.g *= bg_energy; - clear_color.b *= bg_energy; - if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) { - draw_sky_fog_only = true; - storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); - } - } break; - case RS::ENV_BG_SKY: { - draw_sky = true; - } break; - case RS::ENV_BG_CANVAS: { - keep_color = true; - } break; - case RS::ENV_BG_KEEP: { - keep_color = true; - } break; - case RS::ENV_BG_CAMERA_FEED: { - } break; - default: { - } - } - // setup sky if used for ambient, reflections, or background - if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) { - RENDER_TIMESTAMP("Setup Sky"); - RD::get_singleton()->draw_command_begin_label("Setup Sky"); - CameraMatrix projection = p_cam_projection; - if (p_reflection_probe.is_valid()) { - CameraMatrix correction; - correction.set_depth_correction(true); - projection = correction * p_cam_projection; - } - - sky.setup(env, p_render_buffer, projection, p_cam_transform, screen_size, this); - - RID sky_rid = env->sky; - if (sky_rid.is_valid()) { - sky.update(env, projection, p_cam_transform, time); - radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid); - } else { - // do not try to draw sky if invalid - draw_sky = false; - } - RD::get_singleton()->draw_command_end_label(); - } - } else { - clear_color = p_default_bg_color; - } - - bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION; - bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES; - bool depth_pre_pass = !low_end && depth_framebuffer.is_valid(); - - bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment); - bool continue_depth = false; - if (depth_pre_pass) { //depth pre pass - - bool needs_pre_resolve = _needs_post_prepass_render(using_sdfgi || using_giprobe); - if (needs_pre_resolve) { - RENDER_TIMESTAMP("GI + Render Depth Pre-Pass (parallel)"); - } else { - RENDER_TIMESTAMP("Render Depth Pre-Pass"); - } - if (needs_pre_resolve) { - //pre clear the depth framebuffer, as AMD (and maybe others?) use compute for it, and barrier other compute shaders. - RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, depth_pass_clear); - RD::get_singleton()->draw_list_end(); - //start compute processes here, so they run at the same time as depth pre-pass - _post_prepass_render(using_sdfgi || using_giprobe); - } - - RD::get_singleton()->draw_command_begin_label("Render Depth Pre-Pass"); - - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, RID(), RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); - - bool finish_depth = using_ssao || using_sdfgi || using_giprobe; - RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); - _render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector() : depth_pass_clear); - - RD::get_singleton()->draw_command_end_label(); - - if (needs_pre_resolve) { - _pre_resolve_render(using_sdfgi || using_giprobe); - } - - if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RENDER_TIMESTAMP("Resolve Depth Pre-Pass"); - RD::get_singleton()->draw_command_begin_label("Resolve Depth Pre-Pass"); - if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) { - if (needs_pre_resolve) { - RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, RD::BARRIER_MASK_COMPUTE); - } - static int texture_samples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 }; - storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_giprobe ? render_buffer->giprobe_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_giprobe ? render_buffer->giprobe_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]); - } else if (finish_depth) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); - } - RD::get_singleton()->draw_command_end_label(); - } - - continue_depth = !finish_depth; - } - - _pre_opaque_render(using_ssao, using_sdfgi || using_giprobe, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->giprobe_buffer : RID()); - - RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); - - scene_state.ubo.directional_light_count = _get_render_state_directional_light_count(); - - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), p_render_buffer.is_valid()); - - RENDER_TIMESTAMP("Render Opaque Pass"); - - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true); - - bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; - bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; - - { - bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes); - bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes); - - //regular forward for now - Vector c; - if (using_separate_specular) { - Color cc = clear_color.to_linear(); - cc.a = 0; //subsurf scatter must be 0 - c.push_back(cc); - c.push_back(Color(0, 0, 0, 0)); - } else { - c.push_back(clear_color.to_linear()); - } - - RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer; - RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); - _render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); - if (will_continue_color && using_separate_specular) { - // close the specular framebuffer, as it's no longer used - RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); - RD::get_singleton()->draw_list_end(); - } - } - - RD::get_singleton()->draw_command_end_label(); - - if (debug_giprobes) { - //debug giprobes - bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); - bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); - - CameraMatrix dc; - dc.set_depth_correction(true); - CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); - RD::get_singleton()->draw_command_begin_label("Debug GIProbes"); - for (int i = 0; i < (int)p_gi_probes.size(); i++) { - gi.debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); - } - RD::get_singleton()->draw_command_end_label(); - RD::get_singleton()->draw_list_end(); - } - - if (debug_sdfgi_probes) { - //debug giprobes - bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); - bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); - - CameraMatrix dc; - dc.set_depth_correction(true); - CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); - RD::get_singleton()->draw_command_begin_label("Debug SDFGI"); - _debug_sdfgi_probes(p_render_buffer, draw_list, opaque_framebuffer, cm); - RD::get_singleton()->draw_command_end_label(); - RD::get_singleton()->draw_list_end(); - } - - if (draw_sky || draw_sky_fog_only) { - RENDER_TIMESTAMP("Render Sky"); - - CameraMatrix projection = p_cam_projection; - if (p_reflection_probe.is_valid()) { - CameraMatrix correction; - correction.set_depth_correction(true); - projection = correction * p_cam_projection; - } - RD::get_singleton()->draw_command_begin_label("Draw Sky"); - sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_cam_transform, time); - RD::get_singleton()->draw_command_end_label(); - } - - if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); - if (using_separate_specular) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular); - } - } - - if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); - } - - if (using_separate_specular) { - if (using_sss) { - RENDER_TIMESTAMP("Sub Surface Scattering"); - RD::get_singleton()->draw_command_begin_label("Process Sub Surface Scattering"); - _process_sss(p_render_buffer, p_cam_projection); - RD::get_singleton()->draw_command_end_label(); - } - - if (using_ssr) { - RENDER_TIMESTAMP("Screen Space Reflection"); - RD::get_singleton()->draw_command_begin_label("Process Screen Space Reflections"); - _process_ssr(p_render_buffer, render_buffer->color_fb, render_buffer->normal_roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_environment, p_cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED); - RD::get_singleton()->draw_command_end_label(); - } else { - //just mix specular back - RENDER_TIMESTAMP("Merge Specular"); - storage->get_effects()->merge_specular(render_buffer->color_fb, render_buffer->specular, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED ? RID() : render_buffer->color, RID()); - } - } - - RENDER_TIMESTAMP("Render Transparent Pass"); - - RD::get_singleton()->draw_command_begin_label("Render Transparent Pass"); - - rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true); - - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); - - { - RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); - _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); - } - - RD::get_singleton()->draw_command_end_label(); - - RD::get_singleton()->draw_command_begin_label("Resolve"); - - if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); - } - - RD::get_singleton()->draw_command_end_label(); -} - -void RendererSceneRenderForward::_render_shadow_begin() { - scene_state.shadow_passes.clear(); - RD::get_singleton()->draw_command_begin_label("Shadow Setup"); - _update_render_base_uniform_set(); - - render_list[RENDER_LIST_SECONDARY].clear(); - scene_state.instance_data[RENDER_LIST_SECONDARY].clear(); -} -void RendererSceneRenderForward::_render_shadow_append(RID p_framebuffer, const PagedArray &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) { - uint32_t shadow_pass_index = scene_state.shadow_passes.size(); - - SceneState::ShadowPass shadow_pass; - - scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; - - _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), !p_flip_y, Color(), 0, p_zfar, false, p_use_pancake, shadow_pass_index); - - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { - p_screen_lod_threshold = 0.0; - } - - PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; - - uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size(); - _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_projection, p_transform, false, false, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, true); - uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from; - render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size); - _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false); - - { - //regular forward for now - bool flip_cull = p_use_dp_flip; - if (p_flip_y) { - flip_cull = !flip_cull; - } - - shadow_pass.element_from = render_list_from; - shadow_pass.element_count = render_list_size; - shadow_pass.flip_cull = flip_cull; - shadow_pass.pass_mode = pass_mode; - - shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete - shadow_pass.camera_plane = p_camera_plane; - shadow_pass.screen_lod_threshold = p_screen_lod_threshold; - shadow_pass.lod_distance_multiplier = p_lod_distance_multiplier; - - shadow_pass.framebuffer = p_framebuffer; - shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE); - shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE; - shadow_pass.rect = p_rect; - - scene_state.shadow_passes.push_back(shadow_pass); - } -} - -void RendererSceneRenderForward::_render_shadow_process() { - _update_instance_data_buffer(RENDER_LIST_SECONDARY); - //render shadows one after the other, so this can be done un-barriered and the driver can optimize (as well as allow us to run compute at the same time) - - for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { - //render passes need to be configured after instance buffer is done, since they need the latest version - SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; - shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray(), PagedArray(), false, i); - } - - RD::get_singleton()->draw_command_end_label(); -} -void RendererSceneRenderForward::_render_shadow_end(uint32_t p_barrier) { - RD::get_singleton()->draw_command_begin_label("Shadow Render"); - - for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { - SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; - RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, true, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER); - _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector(), 1.0, 0, shadow_pass.rect); - } - - if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) { - RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, p_barrier); - } - RD::get_singleton()->draw_command_end_label(); -} - -void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray &p_instances) { - RENDER_TIMESTAMP("Setup Render Collider Heightfield"); - - RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); - - _update_render_base_uniform_set(); - scene_state.ubo.dual_paraboloid_side = 0; - - _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false); - - PassMode pass_mode = PASS_MODE_SHADOW; - - _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform); - render_list[RENDER_LIST_SECONDARY].sort_by_key(); - _fill_instance_data(RENDER_LIST_SECONDARY); - - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); - - RENDER_TIMESTAMP("Render Collider Heightfield"); - - { - //regular forward for now - RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, true, rp_uniform_set); - _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); - } - RD::get_singleton()->draw_command_end_label(); -} - -void RendererSceneRenderForward::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) { - RENDER_TIMESTAMP("Setup Rendering Material"); - - RD::get_singleton()->draw_command_begin_label("Render Material"); - - _update_render_base_uniform_set(); - - scene_state.ubo.dual_paraboloid_side = 0; - scene_state.ubo.material_uv2_mode = false; - - _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); - - PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; - _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform); - render_list[RENDER_LIST_SECONDARY].sort_by_key(); - _fill_instance_data(RENDER_LIST_SECONDARY); - - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); - - RENDER_TIMESTAMP("Render Material"); - - { - RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set); - //regular forward for now - Vector clear; - clear.push_back(Color(0, 0, 0, 0)); - clear.push_back(Color(0, 0, 0, 0)); - clear.push_back(Color(0, 0, 0, 0)); - clear.push_back(Color(0, 0, 0, 0)); - clear.push_back(Color(0, 0, 0, 0)); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); - RD::get_singleton()->draw_list_end(); - } - - RD::get_singleton()->draw_command_end_label(); -} - -void RendererSceneRenderForward::_render_uv2(const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) { - RENDER_TIMESTAMP("Setup Rendering UV2"); - - RD::get_singleton()->draw_command_begin_label("Render UV2"); - - _update_render_base_uniform_set(); - - scene_state.ubo.dual_paraboloid_side = 0; - scene_state.ubo.material_uv2_mode = true; - - _setup_environment(RID(), RID(), CameraMatrix(), Transform(), RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); - - PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; - _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform()); - render_list[RENDER_LIST_SECONDARY].sort_by_key(); - _fill_instance_data(RENDER_LIST_SECONDARY); - - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); - - RENDER_TIMESTAMP("Render Material"); - - { - RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set, true); - //regular forward for now - Vector clear; - clear.push_back(Color(0, 0, 0, 0)); - clear.push_back(Color(0, 0, 0, 0)); - clear.push_back(Color(0, 0, 0, 0)); - clear.push_back(Color(0, 0, 0, 0)); - clear.push_back(Color(0, 0, 0, 0)); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); - - const int uv_offset_count = 9; - static const Vector2 uv_offsets[uv_offset_count] = { - Vector2(-1, 1), - Vector2(1, 1), - Vector2(1, -1), - Vector2(-1, -1), - Vector2(-1, 0), - Vector2(1, 0), - Vector2(0, -1), - Vector2(0, 1), - Vector2(0, 0), - - }; - - for (int i = 0; i < uv_offset_count; i++) { - Vector2 ofs = uv_offsets[i]; - ofs.x /= p_region.size.width; - ofs.y /= p_region.size.height; - render_list_params.uv_offset = ofs; - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative - } - render_list_params.uv_offset = Vector2(); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles - - RD::get_singleton()->draw_list_end(); - } - - RD::get_singleton()->draw_command_end_label(); -} - -void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) { - RENDER_TIMESTAMP("Render SDFGI"); - - RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel"); - - _update_render_base_uniform_set(); - - RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); - ERR_FAIL_COND(!render_buffer); - - PassMode pass_mode = PASS_MODE_SDF; - _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform()); - render_list[RENDER_LIST_SECONDARY].sort_by_key(); - _fill_instance_data(RENDER_LIST_SECONDARY); - - Vector3 half_extents = p_bounds.size * 0.5; - Vector3 center = p_bounds.position + half_extents; - - Vector sbs; - sbs.push_back(p_albedo_texture); - sbs.push_back(p_emission_texture); - sbs.push_back(p_emission_aniso_texture); - sbs.push_back(p_geom_facing_texture); - - //print_line("re-render " + p_from + " - " + p_size + " bounds " + p_bounds); - for (int i = 0; i < 3; i++) { - scene_state.ubo.sdf_offset[i] = p_from[i]; - scene_state.ubo.sdf_size[i] = p_size[i]; - } - - for (int i = 0; i < 3; i++) { - Vector3 axis; - axis[i] = 1.0; - Vector3 up, right; - int right_axis = (i + 1) % 3; - int up_axis = (i + 2) % 3; - up[up_axis] = 1.0; - right[right_axis] = 1.0; - - Size2i fb_size; - fb_size.x = p_size[right_axis]; - fb_size.y = p_size[up_axis]; - - Transform cam_xform; - cam_xform.origin = center + axis * half_extents; - cam_xform.basis.set_axis(0, right); - cam_xform.basis.set_axis(1, up); - cam_xform.basis.set_axis(2, axis); - - //print_line("pass: " + itos(i) + " xform " + cam_xform); - - float h_size = half_extents[right_axis]; - float v_size = half_extents[up_axis]; - float d_size = half_extents[i] * 2.0; - CameraMatrix camera_proj; - camera_proj.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size); - //print_line("pass: " + itos(i) + " cam hsize: " + rtos(h_size) + " vsize: " + rtos(v_size) + " dsize " + rtos(d_size)); - - Transform to_bounds; - to_bounds.origin = p_bounds.position; - to_bounds.basis.scale(p_bounds.size); - - RendererStorageRD::store_transform(to_bounds.affine_inverse() * cam_xform, scene_state.ubo.sdf_to_bounds); - - _setup_environment(RID(), RID(), camera_proj, cam_xform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); - - RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture); - - Map::Element *E = sdfgi_framebuffer_size_cache.find(fb_size); - if (!E) { - RID fb = RD::get_singleton()->framebuffer_create_empty(fb_size); - E = sdfgi_framebuffer_size_cache.insert(fb_size, fb); - } - - RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set, false); - _render_list_with_threads(&render_list_params, E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector(), 1.0, 0, Rect2(), sbs); - } - - RD::get_singleton()->draw_command_end_label(); -} - -void RendererSceneRenderForward::_base_uniforms_changed() { - if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { - RD::get_singleton()->free(render_base_uniform_set); - } - render_base_uniform_set = RID(); -} - -void RendererSceneRenderForward::_update_render_base_uniform_set() { - if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) { - if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { - RD::get_singleton()->free(render_base_uniform_set); - } - - lightmap_texture_array_version = storage->lightmap_array_get_version(); - - Vector uniforms; - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 1; - u.ids.resize(12); - RID *ids_ptr = u.ids.ptrw(); - ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 2; - u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; - u.ids.push_back(shadow_sampler); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 3; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(get_omni_light_buffer()); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 4; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(get_spot_light_buffer()); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 5; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(get_reflection_probe_buffer()); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 6; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(get_directional_light_buffer()); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 7; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(scene_state.lightmap_buffer); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 8; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(scene_state.lightmap_capture_buffer); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 9; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID decal_atlas = storage->decal_atlas_get_texture(); - u.ids.push_back(decal_atlas); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 10; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID decal_atlas = storage->decal_atlas_get_texture_srgb(); - u.ids.push_back(decal_atlas); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 11; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(get_decal_buffer()); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 12; - u.ids.push_back(storage->global_variables_get_storage_buffer()); - uniforms.push_back(u); - } - - if (!low_end) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 13; - u.ids.push_back(sdfgi_get_ubo()); - uniforms.push_back(u); - } - - render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, SCENE_UNIFORM_SET); - } -} - -RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray &p_gi_probes, const PagedArray &p_lightmaps, bool p_use_directional_shadow_atlas, int p_index) { - //there should always be enough uniform buffers for render passes, otherwise bugs - ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID()); - - RenderBufferDataForward *rb = nullptr; - if (p_render_buffers.is_valid()) { - rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); - } - - //default render buffer and scene state uniform set - - Vector uniforms; - - { - RD::Uniform u; - u.binding = 0; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(scene_state.uniform_buffers[p_index]); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 1; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - RID instance_buffer = scene_state.instance_buffer[p_render_list]; - if (instance_buffer == RID()) { - instance_buffer = default_vec4_xform_buffer; // any buffer will do since its not used - } - u.ids.push_back(instance_buffer); - uniforms.push_back(u); - } - { - RID radiance_texture; - if (p_radiance_texture.is_valid()) { - radiance_texture = p_radiance_texture; - } else { - radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); - } - RD::Uniform u; - u.binding = 2; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(radiance_texture); - uniforms.push_back(u); - } - - { - RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID(); - RD::Uniform u; - u.binding = 3; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - if (ref_texture.is_valid()) { - u.ids.push_back(ref_texture); - } else { - u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK)); - } - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 4; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture; - if (p_shadow_atlas.is_valid()) { - texture = shadow_atlas_get_texture(p_shadow_atlas); - } - if (!texture.is_valid()) { - texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); - } - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 5; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) { - u.ids.push_back(directional_shadow_get_texture()); - } else { - u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); - } - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 6; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.resize(scene_state.max_lightmaps); - RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); - for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { - if (i < p_lightmaps.size()) { - RID base = lightmap_instance_get_lightmap(p_lightmaps[i]); - RID texture = storage->lightmap_get_texture(base); - RID rd_texture = storage->texture_get_rd_texture(texture); - u.ids.write[i] = rd_texture; - } else { - u.ids.write[i] = default_tex; - } - } - - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 7; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.resize(MAX_GI_PROBES); - RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); - for (int i = 0; i < MAX_GI_PROBES; i++) { - if (i < (int)p_gi_probes.size()) { - RID tex = gi.gi_probe_instance_get_texture(p_gi_probes[i]); - if (!tex.is_valid()) { - tex = default_tex; - } - u.ids.write[i] = tex; - } else { - u.ids.write[i] = default_tex; - } - } - - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 8; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer; - u.ids.push_back(cb); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 9; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 10; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_buffers) : RID(); - RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); - u.ids.push_back(texture); - uniforms.push_back(u); - } - - if (!low_end) { - { - RD::Uniform u; - u.binding = 11; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb && rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_NORMAL); - u.ids.push_back(texture); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 12; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID aot = rb ? render_buffers_get_ao_texture(p_render_buffers) : RID(); - RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); - u.ids.push_back(texture); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 13; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID ambient_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_ambient_texture(p_render_buffers) : RID(); - RID texture = ambient_buffer.is_valid() ? ambient_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); - u.ids.push_back(texture); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 14; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID reflection_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_reflection_texture(p_render_buffers) : RID(); - RID texture = reflection_buffer.is_valid() ? reflection_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 15; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID t; - if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { - t = render_buffers_get_sdfgi_irradiance_probes(p_render_buffers); - } else { - t = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); - } - u.ids.push_back(t); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 16; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { - u.ids.push_back(render_buffers_get_sdfgi_occlusion_texture(p_render_buffers)); - } else { - u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); - } - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 17; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_buffers) : render_buffers_get_default_gi_probe_buffer()); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 18; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID vfog = RID(); - if (rb && render_buffers_has_volumetric_fog(p_render_buffers)) { - vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers); - if (vfog.is_null()) { - vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); - } - } else { - vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); - } - u.ids.push_back(vfog); - uniforms.push_back(u); - } - } - - if (p_index >= (int)render_pass_uniform_sets.size()) { - render_pass_uniform_sets.resize(p_index + 1); - } - - if (render_pass_uniform_sets[p_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[p_index])) { - RD::get_singleton()->free(render_pass_uniform_sets[p_index]); - } - - render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_PASS_UNIFORM_SET); - return render_pass_uniform_sets[p_index]; -} - -RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) { - if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { - RD::get_singleton()->free(sdfgi_pass_uniform_set); - } - - Vector uniforms; - - { - RD::Uniform u; - u.binding = 0; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(scene_state.uniform_buffers[0]); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 1; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(scene_state.instance_buffer[RENDER_LIST_SECONDARY]); - uniforms.push_back(u); - } - { - // No radiance texture. - RID radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); - RD::Uniform u; - u.binding = 2; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(radiance_texture); - uniforms.push_back(u); - } - - { - // No reflection atlas. - RID ref_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK); - RD::Uniform u; - u.binding = 3; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(ref_texture); - uniforms.push_back(u); - } - - { - // No shadow atlas. - RD::Uniform u; - u.binding = 4; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); - u.ids.push_back(texture); - uniforms.push_back(u); - } - - { - // No directional shadow atlas. - RD::Uniform u; - u.binding = 5; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); - u.ids.push_back(texture); - uniforms.push_back(u); - } - - { - // No Lightmaps - RD::Uniform u; - u.binding = 6; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.resize(scene_state.max_lightmaps); - RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); - for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { - u.ids.write[i] = default_tex; - } - - uniforms.push_back(u); - } - - { - // No GIProbes - RD::Uniform u; - u.binding = 7; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.resize(MAX_GI_PROBES); - RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); - for (int i = 0; i < MAX_GI_PROBES; i++) { - u.ids.write[i] = default_tex; - } - - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 8; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - RID cb = default_vec4_xform_buffer; - u.ids.push_back(cb); - uniforms.push_back(u); - } - - // actual sdfgi stuff - - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 9; - u.ids.push_back(p_albedo_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 10; - u.ids.push_back(p_emission_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 11; - u.ids.push_back(p_emission_aniso_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 12; - u.ids.push_back(p_geom_facing_texture); - uniforms.push_back(u); - } - - sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET); - return sdfgi_pass_uniform_set; -} - -void RendererSceneRenderForward::_render_buffers_clear_uniform_set(RenderBufferDataForward *rb) { -} - -void RendererSceneRenderForward::_render_buffers_uniform_set_changed(RID p_render_buffers) { - RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); - - _render_buffers_clear_uniform_set(rb); -} - -RID RendererSceneRenderForward::_render_buffers_get_normal_texture(RID p_render_buffers) { - RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); - - return rb->normal_roughness_buffer; -} - -RendererSceneRenderForward *RendererSceneRenderForward::singleton = nullptr; - -void RendererSceneRenderForward::set_time(double p_time, double p_step) { - time = p_time; - RendererSceneRenderRD::set_time(p_time, p_step); -} - -void RendererSceneRenderForward::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - if (ginstance->dirty_list_element.in_list()) { - return; - } - - //clear surface caches - GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; - - while (surf) { - GeometryInstanceSurfaceDataCache *next = surf->next; - geometry_instance_surface_alloc.free(surf); - surf = next; - } - - ginstance->surface_caches = nullptr; - - geometry_instance_dirty_list.add(&ginstance->dirty_list_element); -} - -void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) { - bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; - bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); - bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; - bool has_alpha = has_base_alpha || has_blend_alpha; - - uint32_t flags = 0; - - if (p_material->shader_data->uses_sss) { - flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING; - } - - if (p_material->shader_data->uses_screen_texture) { - flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE; - } - - if (p_material->shader_data->uses_depth_texture) { - flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE; - } - - if (p_material->shader_data->uses_normal_texture) { - flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE; - } - - if (ginstance->data->cast_double_sided_shaodows) { - flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS; - } - - if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) { - //material is only meant for alpha pass - flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; - if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED)) { - flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; - flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; - } - } else { - flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE; - flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; - flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; - } - - MaterialData *material_shadow = nullptr; - void *surface_shadow = nullptr; - if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { - flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; - material_shadow = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); - - RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh); - - if (shadow_mesh.is_valid()) { - surface_shadow = storage->mesh_get_surface(shadow_mesh, p_surface); - } - - } else { - material_shadow = p_material; - } - - GeometryInstanceSurfaceDataCache *sdcache = geometry_instance_surface_alloc.alloc(); - - sdcache->flags = flags; - - sdcache->shader = p_material->shader_data; - sdcache->material_uniform_set = p_material->uniform_set; - sdcache->surface = storage->mesh_get_surface(p_mesh, p_surface); - sdcache->primitive = storage->mesh_surface_get_primitive(sdcache->surface); - sdcache->surface_index = p_surface; - - if (ginstance->data->dirty_dependencies) { - storage->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker); - } - - //shadow - sdcache->shader_shadow = material_shadow->shader_data; - sdcache->material_uniform_set_shadow = material_shadow->uniform_set; - - sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface; - - sdcache->owner = ginstance; - - sdcache->next = ginstance->surface_caches; - ginstance->surface_caches = sdcache; - - //sortkey - - sdcache->sort.sort_key1 = 0; - sdcache->sort.sort_key2 = 0; - - sdcache->sort.surface_index = p_surface; - sdcache->sort.material_id_low = p_material_id & 0x3FFF; - sdcache->sort.material_id_hi = p_material_id >> 14; - sdcache->sort.shader_id = p_shader_id; - sdcache->sort.geometry_id = p_mesh.get_local_index(); //only meshes can repeat anyway - sdcache->sort.uses_forward_gi = ginstance->can_sdfgi; - sdcache->sort.priority = p_material->priority; -} - -void RendererSceneRenderForward::_geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) { - RID m_src; - - m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material; - - MaterialData *material = nullptr; - - if (m_src.is_valid()) { - material = (MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); - if (!material || !material->shader_data->valid) { - material = nullptr; - } - } - - if (material) { - if (ginstance->data->dirty_dependencies) { - storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker); - } - } else { - material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); - m_src = default_material; - } - - ERR_FAIL_COND(!material); - - _geometry_instance_add_surface_with_material(ginstance, p_surface, material, m_src.get_local_index(), storage->material_get_shader_id(m_src), p_mesh); - - while (material->next_pass.is_valid()) { - RID next_pass = material->next_pass; - material = (MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); - if (!material || !material->shader_data->valid) { - break; - } - if (ginstance->data->dirty_dependencies) { - storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker); - } - _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh); - } -} - -void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_geometry_instance) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - - if (ginstance->data->dirty_dependencies) { - ginstance->data->dependency_tracker.update_begin(); - } - - //add geometry for drawing - switch (ginstance->data->base_type) { - case RS::INSTANCE_MESH: { - const RID *materials = nullptr; - uint32_t surface_count; - RID mesh = ginstance->data->base; - - materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); - if (materials) { - //if no materials, no surfaces. - const RID *inst_materials = ginstance->data->surface_materials.ptr(); - uint32_t surf_mat_count = ginstance->data->surface_materials.size(); - - for (uint32_t j = 0; j < surface_count; j++) { - RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j]; - _geometry_instance_add_surface(ginstance, j, material, mesh); - } - } - - ginstance->instance_count = 1; - - } break; - - case RS::INSTANCE_MULTIMESH: { - RID mesh = storage->multimesh_get_mesh(ginstance->data->base); - if (mesh.is_valid()) { - const RID *materials = nullptr; - uint32_t surface_count; - - materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); - if (materials) { - for (uint32_t j = 0; j < surface_count; j++) { - _geometry_instance_add_surface(ginstance, j, materials[j], mesh); - } - } - - ginstance->instance_count = storage->multimesh_get_instances_to_draw(ginstance->data->base); - } - - } break; -#if 0 - case RS::INSTANCE_IMMEDIATE: { - RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); - ERR_CONTINUE(!immediate); - - _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); - - } break; -#endif - case RS::INSTANCE_PARTICLES: { - int draw_passes = storage->particles_get_draw_passes(ginstance->data->base); - - for (int j = 0; j < draw_passes; j++) { - RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j); - if (!mesh.is_valid()) - continue; - - const RID *materials = nullptr; - uint32_t surface_count; - - materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); - if (materials) { - for (uint32_t k = 0; k < surface_count; k++) { - _geometry_instance_add_surface(ginstance, k, materials[k], mesh); - } - } - } - - ginstance->instance_count = storage->particles_get_amount(ginstance->data->base); - - } break; - - default: { - } - } - - //Fill push constant - - bool store_transform = true; - - if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { - ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; - uint32_t stride; - if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) { - ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; - stride = 2; - } else { - stride = 3; - } - if (storage->multimesh_uses_colors(ginstance->data->base)) { - ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; - stride += 1; - } - if (storage->multimesh_uses_custom_data(ginstance->data->base)) { - ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; - stride += 1; - } - - ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); - ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); - - } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) { - ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; - uint32_t stride; - if (false) { // 2D particles - ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; - stride = 2; - } else { - stride = 3; - } - - ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; - stride += 1; - - ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; - stride += 1; - - ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); - - if (!storage->particles_is_using_local_coords(ginstance->data->base)) { - store_transform = false; - } - ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); - - } else if (ginstance->data->base_type == RS::INSTANCE_MESH) { - if (storage->skeleton_is_valid(ginstance->data->skeleton)) { - ginstance->base_flags |= INSTANCE_DATA_FLAG_SKELETON; - ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET); - if (ginstance->data->dirty_dependencies) { - storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker); - } - } - } - - ginstance->store_transform_cache = store_transform; - ginstance->can_sdfgi = false; - - if (!lightmap_instance_is_valid(ginstance->lightmap_instance) && !low_end) { - if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) { - ginstance->can_sdfgi = true; - } - } - - if (ginstance->data->dirty_dependencies) { - ginstance->data->dependency_tracker.update_end(); - ginstance->data->dirty_dependencies = false; - } - - ginstance->dirty_list_element.remove_from_list(); -} - -void RendererSceneRenderForward::_update_dirty_geometry_instances() { - while (geometry_instance_dirty_list.first()) { - _geometry_instance_update(geometry_instance_dirty_list.first()->self()); - } -} - -void RendererSceneRenderForward::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) { - switch (p_notification) { - case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: - case RendererStorage::DEPENDENCY_CHANGED_MESH: - case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: - case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: { - static_cast(singleton)->_geometry_instance_mark_dirty(static_cast(p_tracker->userdata)); - } break; - case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: { - GeometryInstanceForward *ginstance = static_cast(p_tracker->userdata); - if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { - ginstance->instance_count = static_cast(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base); - } - } break; - default: { - //rest of notifications of no interest - } break; - } -} -void RendererSceneRenderForward::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) { - static_cast(singleton)->_geometry_instance_mark_dirty(static_cast(p_tracker->userdata)); -} - -RendererSceneRender::GeometryInstance *RendererSceneRenderForward::geometry_instance_create(RID p_base) { - RS::InstanceType type = storage->get_base_type(p_base); - ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr); - - GeometryInstanceForward *ginstance = geometry_instance_alloc.alloc(); - ginstance->data = memnew(GeometryInstanceForward::Data); - - ginstance->data->base = p_base; - ginstance->data->base_type = type; - ginstance->data->dependency_tracker.userdata = ginstance; - ginstance->data->dependency_tracker.changed_callback = _geometry_instance_dependency_changed; - ginstance->data->dependency_tracker.deleted_callback = _geometry_instance_dependency_deleted; - - _geometry_instance_mark_dirty(ginstance); - - return ginstance; -} -void RendererSceneRenderForward::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->data->skeleton = p_skeleton; - _geometry_instance_mark_dirty(ginstance); - ginstance->data->dirty_dependencies = true; -} -void RendererSceneRenderForward::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->data->material_override = p_override; - _geometry_instance_mark_dirty(ginstance); - ginstance->data->dirty_dependencies = true; -} -void RendererSceneRenderForward::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_materials) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->data->surface_materials = p_materials; - _geometry_instance_mark_dirty(ginstance); - ginstance->data->dirty_dependencies = true; -} -void RendererSceneRenderForward::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->mesh_instance = p_mesh_instance; - _geometry_instance_mark_dirty(ginstance); -} -void RendererSceneRenderForward::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->transform = p_transform; - ginstance->mirror = p_transform.basis.determinant() < 0; - ginstance->data->aabb = p_aabb; - ginstance->transformed_aabb = p_transformed_aabb; - - Vector3 model_scale_vec = p_transform.basis.get_scale_abs(); - // handle non uniform scale here - - float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z)); - float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z)); - ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9; - - ginstance->lod_model_scale = max_scale; -} -void RendererSceneRenderForward::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->lod_bias = p_lod_bias; -} -void RendererSceneRenderForward::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->data->use_baked_light = p_enable; - _geometry_instance_mark_dirty(ginstance); -} -void RendererSceneRenderForward::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->data->use_dynamic_gi = p_enable; - _geometry_instance_mark_dirty(ginstance); -} -void RendererSceneRenderForward::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->lightmap_instance = p_lightmap_instance; - ginstance->lightmap_uv_scale = p_lightmap_uv_scale; - ginstance->lightmap_slice_index = p_lightmap_slice_index; - _geometry_instance_mark_dirty(ginstance); -} -void RendererSceneRenderForward::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - if (p_sh9) { - if (ginstance->lightmap_sh == nullptr) { - ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc(); - } - - copymem(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9); - } else { - if (ginstance->lightmap_sh != nullptr) { - geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); - ginstance->lightmap_sh = nullptr; - } - } - _geometry_instance_mark_dirty(ginstance); -} -void RendererSceneRenderForward::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->shader_parameters_offset = p_offset; - _geometry_instance_mark_dirty(ginstance); -} -void RendererSceneRenderForward::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - - ginstance->data->cast_double_sided_shaodows = p_enable; - _geometry_instance_mark_dirty(ginstance); -} - -void RendererSceneRenderForward::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - ginstance->layer_mask = p_layer_mask; -} - -void RendererSceneRenderForward::geometry_instance_free(GeometryInstance *p_geometry_instance) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - if (ginstance->lightmap_sh != nullptr) { - geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); - } - GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; - while (surf) { - GeometryInstanceSurfaceDataCache *next = surf->next; - geometry_instance_surface_alloc.free(surf); - surf = next; - } - memdelete(ginstance->data); - geometry_instance_alloc.free(ginstance); -} - -uint32_t RendererSceneRenderForward::geometry_instance_get_pair_mask() { - return (1 << RS::INSTANCE_GI_PROBE); -} -void RendererSceneRenderForward::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { -} -void RendererSceneRenderForward::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { -} -void RendererSceneRenderForward::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { -} - -Transform RendererSceneRenderForward::geometry_instance_get_transform(GeometryInstance *p_instance) { - GeometryInstanceForward *ginstance = static_cast(p_instance); - ERR_FAIL_COND_V(!ginstance, Transform()); - return ginstance->transform; -} -AABB RendererSceneRenderForward::geometry_instance_get_aabb(GeometryInstance *p_instance) { - GeometryInstanceForward *ginstance = static_cast(p_instance); - ERR_FAIL_COND_V(!ginstance, AABB()); - return ginstance->data->aabb; -} - -void RendererSceneRenderForward::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) { - GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); - ERR_FAIL_COND(!ginstance); - if (p_gi_probe_instance_count > 0) { - ginstance->gi_probes[0] = p_gi_probe_instances[0]; - } else { - ginstance->gi_probes[0] = RID(); - } - - if (p_gi_probe_instance_count > 1) { - ginstance->gi_probes[1] = p_gi_probe_instances[1]; - } else { - ginstance->gi_probes[1] = RID(); - } -} - -RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_storage) : - RendererSceneRenderRD(p_storage) { - singleton = this; - low_end = is_low_end(); - storage = p_storage; - - /* SCENE SHADER */ - - { - String defines; - if (low_end) { - defines += "\n#define LOW_END_MODE \n"; - } - - defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; - if (is_using_radiance_cubemap_array()) { - defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; - } - defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n"; - defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n"; - - { - //lightmaps - scene_state.max_lightmaps = low_end ? 2 : MAX_LIGHTMAPS; - defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n"; - defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n"; - - scene_state.lightmap_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapData) * scene_state.max_lightmaps); - } - { - //captures - scene_state.max_lightmap_captures = 2048; - scene_state.lightmap_captures = memnew_arr(LightmapCaptureData, scene_state.max_lightmap_captures); - scene_state.lightmap_capture_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapCaptureData) * scene_state.max_lightmap_captures); - } - { - defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n"; - } - - Vector shader_versions; - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n"); - shader_versions.push_back(""); - shader_versions.push_back("\n#define USE_FORWARD_GI\n"); - shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); - shader_versions.push_back("\n#define USE_LIGHTMAP\n"); - shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); - shader.scene_shader.initialize(shader_versions, defines); - - if (is_low_end()) { - //disable the high end versions - shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false); - shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false); - shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false); - shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false); - shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); - shader.scene_shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); - } - } - - storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs); - storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs); - - { - //shader compiler - ShaderCompilerRD::DefaultIdentifierActions actions; - - actions.renames["WORLD_MATRIX"] = "world_matrix"; - actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix"; - actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix"; - actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix"; - actions.renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix"; - actions.renames["MODELVIEW_MATRIX"] = "modelview"; - actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal"; - - actions.renames["VERTEX"] = "vertex"; - actions.renames["NORMAL"] = "normal"; - actions.renames["TANGENT"] = "tangent"; - actions.renames["BINORMAL"] = "binormal"; - actions.renames["POSITION"] = "position"; - actions.renames["UV"] = "uv_interp"; - actions.renames["UV2"] = "uv2_interp"; - actions.renames["COLOR"] = "color_interp"; - actions.renames["POINT_SIZE"] = "gl_PointSize"; - actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; - - actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold"; - actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale"; - actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge"; - actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate"; - - //builtins - - actions.renames["TIME"] = "scene_data.time"; - actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size"; - - actions.renames["FRAGCOORD"] = "gl_FragCoord"; - actions.renames["FRONT_FACING"] = "gl_FrontFacing"; - actions.renames["NORMAL_MAP"] = "normal_map"; - actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; - actions.renames["ALBEDO"] = "albedo"; - actions.renames["ALPHA"] = "alpha"; - actions.renames["METALLIC"] = "metallic"; - actions.renames["SPECULAR"] = "specular"; - actions.renames["ROUGHNESS"] = "roughness"; - actions.renames["RIM"] = "rim"; - actions.renames["RIM_TINT"] = "rim_tint"; - actions.renames["CLEARCOAT"] = "clearcoat"; - actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; - actions.renames["ANISOTROPY"] = "anisotropy"; - actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; - actions.renames["SSS_STRENGTH"] = "sss_strength"; - actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color"; - actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth"; - actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve"; - actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost"; - actions.renames["BACKLIGHT"] = "backlight"; - actions.renames["AO"] = "ao"; - actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; - actions.renames["EMISSION"] = "emission"; - actions.renames["POINT_COORD"] = "gl_PointCoord"; - actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; - actions.renames["SCREEN_UV"] = "screen_uv"; - actions.renames["SCREEN_TEXTURE"] = "color_buffer"; - actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; - actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; - actions.renames["DEPTH"] = "gl_FragDepth"; - actions.renames["OUTPUT_IS_SRGB"] = "true"; - actions.renames["FOG"] = "custom_fog"; - actions.renames["RADIANCE"] = "custom_radiance"; - actions.renames["IRRADIANCE"] = "custom_irradiance"; - actions.renames["BONE_INDICES"] = "bone_attrib"; - actions.renames["BONE_WEIGHTS"] = "weight_attrib"; - actions.renames["CUSTOM0"] = "custom0_attrib"; - actions.renames["CUSTOM1"] = "custom1_attrib"; - actions.renames["CUSTOM2"] = "custom2_attrib"; - actions.renames["CUSTOM3"] = "custom3_attrib"; - - //for light - actions.renames["VIEW"] = "view"; - actions.renames["LIGHT_COLOR"] = "light_color"; - actions.renames["LIGHT"] = "light"; - actions.renames["ATTENUATION"] = "attenuation"; - actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation"; - actions.renames["DIFFUSE_LIGHT"] = "diffuse_light"; - actions.renames["SPECULAR_LIGHT"] = "specular_light"; - - actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; - actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n"; - actions.usage_defines["BINORMAL"] = "@TANGENT"; - actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n"; - actions.usage_defines["RIM_TINT"] = "@RIM"; - actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n"; - actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; - actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n"; - actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; - actions.usage_defines["AO"] = "#define AO_USED\n"; - actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n"; - actions.usage_defines["UV"] = "#define UV_USED\n"; - actions.usage_defines["UV2"] = "#define UV2_USED\n"; - actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n"; - actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n"; - actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n"; - actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n"; - actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n"; - actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n"; - actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; - actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; - actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; - actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; - actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; - - actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n"; - actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n"; - actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n"; - actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE"; - - actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; - actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; - actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; - actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; - actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; - - actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - - actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n"; - actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n"; - actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n"; - - actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; - actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; - actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; - actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; - actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; - - bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley"); - - if (!force_lambert) { - actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; - } - - actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; - actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; - actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - - actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; - - bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); - - if (!force_blinn) { - actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; - } else { - actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; - } - - actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; - actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; - actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; - actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; - actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; - actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; - actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; - actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; - - actions.sampler_array_name = "material_samplers"; - actions.base_texture_binding_index = 1; - actions.texture_layout_set = MATERIAL_UNIFORM_SET; - actions.base_uniform_string = "material."; - actions.base_varying_index = 10; - - actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; - actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; - actions.global_buffer_array_variable = "global_variables.data"; - actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs"; - - shader.compiler.initialize(actions); - } - - { - //default material and shader - default_shader = storage->shader_allocate(); - storage->shader_initialize(default_shader); - storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n"); - default_material = storage->material_allocate(); - storage->material_initialize(default_material); - storage->material_set_shader(default_material, default_shader); - - MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); - default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); - if (!low_end) { - default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); - } - } - - { - overdraw_material_shader = storage->shader_allocate(); - storage->shader_initialize(overdraw_material_shader); - storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); - overdraw_material = storage->material_allocate(); - storage->material_initialize(overdraw_material); - storage->material_set_shader(overdraw_material, overdraw_material_shader); - - wireframe_material_shader = storage->shader_allocate(); - storage->shader_initialize(wireframe_material_shader); - storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }"); - wireframe_material = storage->material_allocate(); - storage->material_initialize(wireframe_material); - storage->material_set_shader(wireframe_material, wireframe_material_shader); - } - - { - default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256); - Vector uniforms; - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(default_vec4_xform_buffer); - u.binding = 0; - uniforms.push_back(u); - - default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, TRANSFORMS_UNIFORM_SET); - } - { - RD::SamplerState sampler; - sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; - sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; - sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; - shadow_sampler = RD::get_singleton()->sampler_create(sampler); - } - - render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances"); -} - -RendererSceneRenderForward::~RendererSceneRenderForward() { - directional_shadow_atlas_set_size(0); - - //clear base uniform set if still valid - for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) { - if (render_pass_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[i])) { - RD::get_singleton()->free(render_pass_uniform_sets[i]); - } - } - - if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { - RD::get_singleton()->free(sdfgi_pass_uniform_set); - } - - RD::get_singleton()->free(default_vec4_xform_buffer); - RD::get_singleton()->free(shadow_sampler); - - storage->free(wireframe_material_shader); - storage->free(overdraw_material_shader); - storage->free(default_shader); - - storage->free(wireframe_material); - storage->free(overdraw_material); - storage->free(default_material); - - { - for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) { - RD::get_singleton()->free(scene_state.uniform_buffers[i]); - } - RD::get_singleton()->free(scene_state.lightmap_buffer); - RD::get_singleton()->free(scene_state.lightmap_capture_buffer); - for (uint32_t i = 0; i < RENDER_LIST_MAX; i++) { - if (scene_state.instance_buffer[i] != RID()) { - RD::get_singleton()->free(scene_state.instance_buffer[i]); - } - } - memdelete_arr(scene_state.lightmap_captures); - } - - while (sdfgi_framebuffer_size_cache.front()) { - RD::get_singleton()->free(sdfgi_framebuffer_size_cache.front()->get()); - sdfgi_framebuffer_size_cache.erase(sdfgi_framebuffer_size_cache.front()); - } -} diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.h b/servers/rendering/renderer_rd/renderer_scene_render_forward.h deleted file mode 100644 index af78c50fda..0000000000 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.h +++ /dev/null @@ -1,771 +0,0 @@ -/*************************************************************************/ -/* renderer_scene_render_forward.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_H -#define RENDERING_SERVER_SCENE_RENDER_FORWARD_H - -#include "core/templates/paged_allocator.h" -#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" -#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" -#include "servers/rendering/renderer_rd/renderer_storage_rd.h" -#include "servers/rendering/renderer_rd/shaders/scene_forward.glsl.gen.h" - -class RendererSceneRenderForward : public RendererSceneRenderRD { - enum { - SCENE_UNIFORM_SET = 0, - RENDER_PASS_UNIFORM_SET = 1, - TRANSFORMS_UNIFORM_SET = 2, - MATERIAL_UNIFORM_SET = 3 - }; - - enum { - SDFGI_MAX_CASCADES = 8, - MAX_GI_PROBES = 8, - MAX_LIGHTMAPS = 8, - MAX_GI_PROBES_PER_INSTANCE = 2, - INSTANCE_DATA_BUFFER_MIN_SIZE = 4096 - }; - - enum RenderListType { - RENDER_LIST_OPAQUE, //used for opaque objects - RENDER_LIST_ALPHA, //used for transparent objects - RENDER_LIST_SECONDARY, //used for shadows and other objects - RENDER_LIST_MAX - - }; - - /* Scene Shader */ - - enum ShaderVersion { - SHADER_VERSION_DEPTH_PASS, - SHADER_VERSION_DEPTH_PASS_DP, - SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, - SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, - SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, - SHADER_VERSION_DEPTH_PASS_WITH_SDF, - SHADER_VERSION_COLOR_PASS, - SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, - SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, - SHADER_VERSION_LIGHTMAP_COLOR_PASS, - SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, - SHADER_VERSION_MAX - }; - - struct { - SceneForwardShaderRD scene_shader; - ShaderCompilerRD compiler; - } shader; - - RendererStorageRD *storage; - - /* Material */ - - struct ShaderData : public RendererStorageRD::ShaderData { - enum BlendMode { //used internally - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - BLEND_MODE_ALPHA_TO_COVERAGE - }; - - enum DepthDraw { - DEPTH_DRAW_DISABLED, - DEPTH_DRAW_OPAQUE, - DEPTH_DRAW_ALWAYS - }; - - enum DepthTest { - DEPTH_TEST_DISABLED, - DEPTH_TEST_ENABLED - }; - - enum Cull { - CULL_DISABLED, - CULL_FRONT, - CULL_BACK - }; - - enum CullVariant { - CULL_VARIANT_NORMAL, - CULL_VARIANT_REVERSED, - CULL_VARIANT_DOUBLE_SIDED, - CULL_VARIANT_MAX - - }; - - enum AlphaAntiAliasing { - ALPHA_ANTIALIASING_OFF, - ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, - ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE - }; - - bool valid; - RID version; - uint32_t vertex_input_mask; - PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; - - String path; - - Map uniforms; - Vector texture_uniforms; - - Vector ubo_offsets; - uint32_t ubo_size; - - String code; - Map default_texture_params; - - DepthDraw depth_draw; - DepthTest depth_test; - - bool uses_point_size; - bool uses_alpha; - bool uses_blend_alpha; - bool uses_alpha_clip; - bool uses_depth_pre_pass; - bool uses_discard; - bool uses_roughness; - bool uses_normal; - - bool unshaded; - bool uses_vertex; - bool uses_sss; - bool uses_transmittance; - bool uses_screen_texture; - bool uses_depth_texture; - bool uses_normal_texture; - bool uses_time; - bool writes_modelview_or_projection; - bool uses_world_coordinates; - - uint64_t last_pass = 0; - uint32_t index = 0; - - virtual void set_code(const String &p_Code); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture); - virtual void get_param_list(List *p_param_list) const; - void get_instance_param_list(List *p_param_list) const; - - virtual bool is_param_texture(const StringName &p_param) const; - virtual bool is_animated() const; - virtual bool casts_shadows() const; - virtual Variant get_default_parameter(const StringName &p_parameter) const; - virtual RS::ShaderNativeSourceCode get_native_source_code() const; - - ShaderData(); - virtual ~ShaderData(); - }; - - RendererStorageRD::ShaderData *_create_shader_func(); - static RendererStorageRD::ShaderData *_create_shader_funcs() { - return static_cast(singleton)->_create_shader_func(); - } - - struct MaterialData : public RendererStorageRD::MaterialData { - uint64_t last_frame; - ShaderData *shader_data; - RID uniform_buffer; - RID uniform_set; - Vector texture_cache; - Vector ubo_data; - uint64_t last_pass = 0; - uint32_t index = 0; - RID next_pass; - uint8_t priority; - virtual void set_render_priority(int p_priority); - virtual void set_next_pass(RID p_pass); - virtual void update_parameters(const Map &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); - virtual ~MaterialData(); - }; - - RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); - static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) { - return static_cast(singleton)->_create_material_func(static_cast(p_shader)); - } - - /* Framebuffer */ - - struct RenderBufferDataForward : public RenderBufferData { - //for rendering, may be MSAAd - - RID color; - RID depth; - RID specular; - RID normal_roughness_buffer; - RID giprobe_buffer; - - RS::ViewportMSAA msaa; - RD::TextureSamples texture_samples; - - RID color_msaa; - RID depth_msaa; - RID specular_msaa; - RID normal_roughness_buffer_msaa; - RID roughness_buffer_msaa; - RID giprobe_buffer_msaa; - - RID depth_fb; - RID depth_normal_roughness_fb; - RID depth_normal_roughness_giprobe_fb; - RID color_fb; - RID color_specular_fb; - RID specular_only_fb; - int width, height; - - RID render_sdfgi_uniform_set; - void ensure_specular(); - void ensure_giprobe(); - void clear(); - virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); - - ~RenderBufferDataForward(); - }; - - virtual RenderBufferData *_create_render_buffer_data(); - void _allocate_normal_roughness_texture(RenderBufferDataForward *rb); - - RID shadow_sampler; - RID render_base_uniform_set; - LocalVector render_pass_uniform_sets; - RID sdfgi_pass_uniform_set; - - uint64_t lightmap_texture_array_version = 0xFFFFFFFF; - - virtual void _base_uniforms_changed(); - void _render_buffers_clear_uniform_set(RenderBufferDataForward *rb); - virtual void _render_buffers_uniform_set_changed(RID p_render_buffers); - virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); - - void _update_render_base_uniform_set(); - RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); - RID _setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray &p_gi_probes, const PagedArray &p_lightmaps, bool p_use_directional_shadow_atlas = false, int p_index = 0); - - enum PassMode { - PASS_MODE_COLOR, - PASS_MODE_COLOR_SPECULAR, - PASS_MODE_COLOR_TRANSPARENT, - PASS_MODE_SHADOW, - PASS_MODE_SHADOW_DP, - PASS_MODE_DEPTH, - PASS_MODE_DEPTH_NORMAL_ROUGHNESS, - PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE, - PASS_MODE_DEPTH_MATERIAL, - PASS_MODE_SDF, - }; - - struct GeometryInstanceSurfaceDataCache; - struct RenderElementInfo; - - struct RenderListParameters { - GeometryInstanceSurfaceDataCache **elements = nullptr; - RenderElementInfo *element_info = nullptr; - int element_count = 0; - bool reverse_cull = false; - PassMode pass_mode = PASS_MODE_COLOR; - bool no_gi = false; - RID render_pass_uniform_set; - bool force_wireframe = false; - Vector2 uv_offset; - Plane lod_plane; - float lod_distance_multiplier = 0.0; - float screen_lod_threshold = 0.0; - RD::FramebufferFormatID framebuffer_format = 0; - uint32_t element_offset = 0; - uint32_t barrier = RD::BARRIER_MASK_ALL; - - RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) { - elements = p_elements; - element_info = p_element_info; - element_count = p_element_count; - reverse_cull = p_reverse_cull; - pass_mode = p_pass_mode; - no_gi = p_no_gi; - render_pass_uniform_set = p_render_pass_uniform_set; - force_wireframe = p_force_wireframe; - uv_offset = p_uv_offset; - lod_plane = p_lod_plane; - lod_distance_multiplier = p_lod_distance_multiplier; - screen_lod_threshold = p_screen_lod_threshold; - element_offset = p_element_offset; - barrier = p_barrier; - } - }; - - struct LightmapData { - float normal_xform[12]; - }; - - struct LightmapCaptureData { - float sh[9 * 4]; - }; - - enum { - INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, - INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, - INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, - INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, - INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, - INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11, - INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, - INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, - INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, - INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, - INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16, - INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7, - INSTANCE_DATA_FLAG_SKELETON = 1 << 19, - }; - - struct SceneState { - struct UBO { - float projection_matrix[16]; - float inv_projection_matrix[16]; - - float camera_matrix[16]; - float inv_camera_matrix[16]; - - float viewport_size[2]; - float screen_pixel_size[2]; - - uint32_t cluster_shift; - uint32_t cluster_width; - uint32_t cluster_type_size; - uint32_t max_cluster_element_count_div_32; - - float directional_penumbra_shadow_kernel[128]; //32 vec4s - float directional_soft_shadow_kernel[128]; - float penumbra_shadow_kernel[128]; - float soft_shadow_kernel[128]; - - uint32_t directional_penumbra_shadow_samples; - uint32_t directional_soft_shadow_samples; - uint32_t penumbra_shadow_samples; - uint32_t soft_shadow_samples; - - float ambient_light_color_energy[4]; - - float ambient_color_sky_mix; - uint32_t use_ambient_light; - uint32_t use_ambient_cubemap; - uint32_t use_reflection_cubemap; - - float radiance_inverse_xform[12]; - - float shadow_atlas_pixel_size[2]; - float directional_shadow_pixel_size[2]; - - uint32_t directional_light_count; - float dual_paraboloid_side; - float z_far; - float z_near; - - uint32_t ssao_enabled; - float ssao_light_affect; - float ssao_ao_affect; - uint32_t roughness_limiter_enabled; - - float roughness_limiter_amount; - float roughness_limiter_limit; - uint32_t roughness_limiter_pad[2]; - - float ao_color[4]; - - float sdf_to_bounds[16]; - - int32_t sdf_offset[3]; - uint32_t material_uv2_mode; - - int32_t sdf_size[3]; - uint32_t gi_upscale_for_msaa; - - uint32_t volumetric_fog_enabled; - float volumetric_fog_inv_length; - float volumetric_fog_detail_spread; - uint32_t volumetric_fog_pad; - - // Fog - uint32_t fog_enabled; - float fog_density; - float fog_height; - float fog_height_density; - - float fog_light_color[3]; - float fog_sun_scatter; - - float fog_aerial_perspective; - - float time; - float reflection_multiplier; - - uint32_t pancake_shadows; - }; - - struct PushConstant { - uint32_t base_index; // - uint32_t uv_offset; //packed - uint32_t pad[2]; - }; - - struct InstanceData { - float transform[16]; - uint32_t flags; - uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables - uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index) - uint32_t layer_mask; - float lightmap_uv_scale[4]; - }; - - UBO ubo; - - LocalVector uniform_buffers; - - LightmapData lightmaps[MAX_LIGHTMAPS]; - RID lightmap_ids[MAX_LIGHTMAPS]; - bool lightmap_has_sh[MAX_LIGHTMAPS]; - uint32_t lightmaps_used = 0; - uint32_t max_lightmaps; - RID lightmap_buffer; - - RID instance_buffer[RENDER_LIST_MAX]; - uint32_t instance_buffer_size[RENDER_LIST_MAX] = { 0, 0, 0 }; - LocalVector instance_data[RENDER_LIST_MAX]; - - LightmapCaptureData *lightmap_captures; - uint32_t max_lightmap_captures; - RID lightmap_capture_buffer; - - RID giprobe_ids[MAX_GI_PROBES]; - uint32_t giprobes_used = 0; - - bool used_screen_texture = false; - bool used_normal_texture = false; - bool used_depth_texture = false; - bool used_sss = false; - - struct ShadowPass { - uint32_t element_from; - uint32_t element_count; - bool flip_cull; - PassMode pass_mode; - - RID rp_uniform_set; - Plane camera_plane; - float lod_distance_multiplier; - float screen_lod_threshold; - - RID framebuffer; - RD::InitialAction initial_depth_action; - RD::FinalAction final_depth_action; - Rect2i rect; - }; - - LocalVector shadow_passes; - - } scene_state; - - static RendererSceneRenderForward *singleton; - - double time; - RID default_shader; - RID default_material; - RID overdraw_material_shader; - RID overdraw_material; - RID wireframe_material_shader; - RID wireframe_material; - RID default_shader_rd; - RID default_shader_sdfgi_rd; - - RID default_vec4_xform_buffer; - RID default_vec4_xform_uniform_set; - - void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0); - void _setup_giprobes(const PagedArray &p_giprobes); - void _setup_lightmaps(const PagedArray &p_lightmaps, const Transform &p_cam_transform); - - struct RenderElementInfo { - uint32_t repeat : 22; - uint32_t uses_lightmap : 1; - uint32_t uses_forward_gi : 1; - uint32_t lod_index : 8; - }; - - template - _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); - - void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); - - LocalVector thread_draw_lists; - void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params); - void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); - - uint32_t render_list_thread_threshold = 500; - - void _update_instance_data_buffer(RenderListType p_render_list); - void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); - void _fill_render_list(RenderListType p_render_list, const PagedArray &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, const Plane &p_lod_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, bool p_append = false); - - Map sdfgi_framebuffer_size_cache; - - struct GeometryInstanceData; - struct GeometryInstanceForward; - - struct GeometryInstanceLightmapSH { - Color sh[9]; - }; - - // Cached data for drawing surfaces - struct GeometryInstanceSurfaceDataCache { - enum { - FLAG_PASS_DEPTH = 1, - FLAG_PASS_OPAQUE = 2, - FLAG_PASS_ALPHA = 4, - FLAG_PASS_SHADOW = 8, - FLAG_USES_SHARED_SHADOW_MATERIAL = 128, - FLAG_USES_SUBSURFACE_SCATTERING = 2048, - FLAG_USES_SCREEN_TEXTURE = 4096, - FLAG_USES_DEPTH_TEXTURE = 8192, - FLAG_USES_NORMAL_TEXTURE = 16384, - FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768, - }; - - union { - struct { - uint64_t lod_index : 8; - uint64_t surface_index : 10; - uint64_t geometry_id : 32; - uint64_t material_id_low : 14; - - uint64_t material_id_hi : 18; - uint64_t shader_id : 32; - uint64_t uses_forward_gi : 1; - uint64_t uses_lightmap : 1; - uint64_t depth_layer : 4; - uint64_t priority : 8; - }; - struct { - uint64_t sort_key1; - uint64_t sort_key2; - }; - } sort; - - RS::PrimitiveType primitive = RS::PRIMITIVE_MAX; - uint32_t flags = 0; - uint32_t surface_index = 0; - - void *surface = nullptr; - RID material_uniform_set; - ShaderData *shader = nullptr; - - void *surface_shadow = nullptr; - RID material_uniform_set_shadow; - ShaderData *shader_shadow = nullptr; - - GeometryInstanceSurfaceDataCache *next = nullptr; - GeometryInstanceForward *owner = nullptr; - }; - - struct GeometryInstanceForward : public GeometryInstance { - //used during rendering - bool mirror = false; - bool non_uniform_scale = false; - float lod_bias = 0.0; - float lod_model_scale = 1.0; - AABB transformed_aabb; //needed for LOD - float depth = 0; - uint32_t gi_offset_cache = 0; - uint32_t flags_cache = 0; - bool store_transform_cache = true; - int32_t shader_parameters_offset = -1; - uint32_t lightmap_slice_index; - Rect2 lightmap_uv_scale; - uint32_t layer_mask = 1; - RID transforms_uniform_set; - uint32_t instance_count = 0; - RID mesh_instance; - bool can_sdfgi = false; - //used during setup - uint32_t base_flags = 0; - Transform transform; - RID gi_probes[MAX_GI_PROBES_PER_INSTANCE]; - RID lightmap_instance; - GeometryInstanceLightmapSH *lightmap_sh = nullptr; - GeometryInstanceSurfaceDataCache *surface_caches = nullptr; - SelfList dirty_list_element; - - struct Data { - //data used less often goes into regular heap - RID base; - RS::InstanceType base_type; - - RID skeleton; - Vector surface_materials; - RID material_override; - AABB aabb; - - bool use_dynamic_gi = false; - bool use_baked_light = false; - bool cast_double_sided_shaodows = false; - bool mirror = false; - bool dirty_dependencies = false; - - RendererStorage::DependencyTracker dependency_tracker; - }; - - Data *data = nullptr; - - GeometryInstanceForward() : - dirty_list_element(this) {} - }; - - static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker); - static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker); - - SelfList::List geometry_instance_dirty_list; - - PagedAllocator geometry_instance_alloc; - PagedAllocator geometry_instance_surface_alloc; - PagedAllocator geometry_instance_lightmap_sh; - - void _geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh); - void _geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh); - void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance); - void _geometry_instance_update(GeometryInstance *p_geometry_instance); - void _update_dirty_geometry_instances(); - - bool low_end = false; - - /* Render List */ - - struct RenderList { - LocalVector elements; - LocalVector element_info; - - void clear() { - elements.clear(); - element_info.clear(); - } - - //should eventually be replaced by radix - - struct SortByKey { - _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { - return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2); - } - }; - - void sort_by_key() { - SortArray sorter; - sorter.sort(elements.ptr(), elements.size()); - } - - void sort_by_key_range(uint32_t p_from, uint32_t p_size) { - SortArray sorter; - sorter.sort(elements.ptr() + p_from, p_size); - } - - struct SortByDepth { - _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { - return (A->owner->depth < B->owner->depth); - } - }; - - void sort_by_depth() { //used for shadows - - SortArray sorter; - sorter.sort(elements.ptr(), elements.size()); - } - - struct SortByReverseDepthAndPriority { - _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { - return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority); - } - }; - - void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha - - SortArray sorter; - sorter.sort(elements.ptr(), elements.size()); - } - - _FORCE_INLINE_ void add_element(GeometryInstanceSurfaceDataCache *p_element) { - elements.push_back(p_element); - } - }; - - RenderList render_list[RENDER_LIST_MAX]; - -protected: - virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, const PagedArray &p_gi_probes, const PagedArray &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_lod_threshold); - - virtual void _render_shadow_begin(); - virtual void _render_shadow_append(RID p_framebuffer, const PagedArray &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true); - virtual void _render_shadow_process(); - virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL); - - virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region); - virtual void _render_uv2(const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region); - virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); - virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray &p_instances); - -public: - virtual GeometryInstance *geometry_instance_create(RID p_base); - virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton); - virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override); - virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_materials); - virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance); - virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb); - virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask); - virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias); - virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable); - virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable); - virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index); - virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9); - virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset); - virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable); - - virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance); - virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance); - - virtual void geometry_instance_free(GeometryInstance *p_geometry_instance); - - virtual uint32_t geometry_instance_get_pair_mask(); - virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count); - virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count); - virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count); - virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count); - - virtual void set_time(double p_time, double p_step); - - virtual bool free(RID p_rid); - - RendererSceneRenderForward(RendererStorageRD *p_storage); - ~RendererSceneRenderForward(); -}; -#endif // RASTERIZER_SCENE_HIGHEND_RD_H diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp new file mode 100644 index 0000000000..6ffecc9f35 --- /dev/null +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp @@ -0,0 +1,3674 @@ +/*************************************************************************/ +/* renderer_scene_render_forward_clustered.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_scene_render_forward_clustered.h" +#include "core/config/project_settings.h" +#include "servers/rendering/rendering_device.h" +#include "servers/rendering/rendering_server_default.h" + +/* SCENE SHADER */ +void RendererSceneRenderForwardClustered::ShaderData::set_code(const String &p_code) { + //compile + + code = p_code; + valid = false; + ubo_size = 0; + uniforms.clear(); + uses_screen_texture = false; + + if (code == String()) { + return; //just invalid, but no error + } + + ShaderCompilerRD::GeneratedCode gen_code; + + int blend_mode = BLEND_MODE_MIX; + int depth_testi = DEPTH_TEST_ENABLED; + int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; + int cull = CULL_BACK; + + uses_point_size = false; + uses_alpha = false; + uses_blend_alpha = false; + uses_depth_pre_pass = false; + uses_discard = false; + uses_roughness = false; + uses_normal = false; + bool wireframe = false; + + unshaded = false; + uses_vertex = false; + uses_sss = false; + uses_transmittance = false; + uses_screen_texture = false; + uses_depth_texture = false; + uses_normal_texture = false; + uses_time = false; + writes_modelview_or_projection = false; + uses_world_coordinates = false; + + int depth_drawi = DEPTH_DRAW_OPAQUE; + + ShaderCompilerRD::IdentifierActions actions; + + actions.render_mode_values["blend_add"] = Pair(&blend_mode, BLEND_MODE_ADD); + actions.render_mode_values["blend_mix"] = Pair(&blend_mode, BLEND_MODE_MIX); + actions.render_mode_values["blend_sub"] = Pair(&blend_mode, BLEND_MODE_SUB); + actions.render_mode_values["blend_mul"] = Pair(&blend_mode, BLEND_MODE_MUL); + + actions.render_mode_values["alpha_to_coverage"] = Pair(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); + actions.render_mode_values["alpha_to_coverage_and_one"] = Pair(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); + + actions.render_mode_values["depth_draw_never"] = Pair(&depth_drawi, DEPTH_DRAW_DISABLED); + actions.render_mode_values["depth_draw_opaque"] = Pair(&depth_drawi, DEPTH_DRAW_OPAQUE); + actions.render_mode_values["depth_draw_always"] = Pair(&depth_drawi, DEPTH_DRAW_ALWAYS); + + actions.render_mode_values["depth_test_disabled"] = Pair(&depth_testi, DEPTH_TEST_DISABLED); + + actions.render_mode_values["cull_disabled"] = Pair(&cull, CULL_DISABLED); + actions.render_mode_values["cull_front"] = Pair(&cull, CULL_FRONT); + actions.render_mode_values["cull_back"] = Pair(&cull, CULL_BACK); + + actions.render_mode_flags["unshaded"] = &unshaded; + actions.render_mode_flags["wireframe"] = &wireframe; + + actions.usage_flag_pointers["ALPHA"] = &uses_alpha; + actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass; + + actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; + actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance; + + actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; + actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; + actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture; + actions.usage_flag_pointers["DISCARD"] = &uses_discard; + actions.usage_flag_pointers["TIME"] = &uses_time; + actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; + actions.usage_flag_pointers["NORMAL"] = &uses_normal; + actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal; + + actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; + actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; + + actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection; + actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection; + actions.write_flag_pointers["VERTEX"] = &uses_vertex; + + actions.uniforms = &uniforms; + + RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton; + + Error err = scene_singleton->shader.compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code); + + ERR_FAIL_COND(err != OK); + + if (version.is_null()) { + version = scene_singleton->shader.scene_shader.version_create(); + } + + depth_draw = DepthDraw(depth_drawi); + depth_test = DepthTest(depth_testi); + +#if 0 + print_line("**compiling shader:"); + print_line("**defines:\n"); + for (int i = 0; i < gen_code.defines.size(); i++) { + print_line(gen_code.defines[i]); + } + print_line("\n**uniforms:\n" + gen_code.uniforms); + print_line("\n**vertex_globals:\n" + gen_code.vertex_global); + print_line("\n**vertex_code:\n" + gen_code.vertex); + print_line("\n**fragment_globals:\n" + gen_code.fragment_global); + print_line("\n**fragment_code:\n" + gen_code.fragment); + print_line("\n**light_code:\n" + gen_code.light); +#endif + scene_singleton->shader.scene_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines); + ERR_FAIL_COND(!scene_singleton->shader.scene_shader.version_is_valid(version)); + + ubo_size = gen_code.uniform_total_size; + ubo_offsets = gen_code.uniform_offsets; + texture_uniforms = gen_code.texture_uniforms; + + //blend modes + + // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage + if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) { + blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE; + } + + RD::PipelineColorBlendState::Attachment blend_attachment; + + switch (blend_mode) { + case BLEND_MODE_MIX: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + } break; + case BLEND_MODE_ADD: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + uses_blend_alpha = true; //force alpha used because of blend + + } break; + case BLEND_MODE_SUB: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT; + blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + uses_blend_alpha = true; //force alpha used because of blend + + } break; + case BLEND_MODE_MUL: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; + uses_blend_alpha = true; //force alpha used because of blend + } break; + case BLEND_MODE_ALPHA_TO_COVERAGE: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; + } + } + + RD::PipelineColorBlendState blend_state_blend; + blend_state_blend.attachments.push_back(blend_attachment); + RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1); + RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2); + RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1); + RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2); + + //update pipelines + + RD::PipelineDepthStencilState depth_stencil_state; + + if (depth_test != DEPTH_TEST_DISABLED) { + depth_stencil_state.enable_depth_test = true; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; + } + + for (int i = 0; i < CULL_VARIANT_MAX; i++) { + RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = { + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK }, + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT }, + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED } + }; + + RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull]; + + for (int j = 0; j < RS::PRIMITIVE_MAX; j++) { + RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = { + RD::RENDER_PRIMITIVE_POINTS, + RD::RENDER_PRIMITIVE_LINES, + RD::RENDER_PRIMITIVE_LINESTRIPS, + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, + }; + + RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; + + for (int k = 0; k < SHADER_VERSION_MAX; k++) { + if (!static_cast(singleton)->shader.scene_shader.is_variant_enabled(k)) { + continue; + } + RD::PipelineRasterizationState raster_state; + raster_state.cull_mode = cull_mode_rd; + raster_state.wireframe = wireframe; + + RD::PipelineColorBlendState blend_state; + RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; + RD::PipelineMultisampleState multisample_state; + + if (uses_alpha || uses_blend_alpha) { + // only allow these flags to go through if we have some form of msaa + if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { + multisample_state.enable_alpha_to_coverage = true; + } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { + multisample_state.enable_alpha_to_coverage = true; + multisample_state.enable_alpha_to_one = true; + } + + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + blend_state = blend_state_blend; + if (depth_draw == DEPTH_DRAW_OPAQUE) { + depth_stencil.enable_depth_write = false; //alpha does not draw depth + } + } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) { + if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { + //none, blend state contains nothing + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way + } else { + blend_state = blend_state_opaque; //writes to normal and roughness in opaque way + } + } else { + pipelines[i][j][k].clear(); + continue; // do not use this version (will error if using it is attempted) + } + } else { + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + blend_state = blend_state_opaque; + } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { + //none, leave empty + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { + blend_state = blend_state_depth_normal_roughness; + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) { + blend_state = blend_state_depth_normal_roughness_giprobe; + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) { + blend_state = RD::PipelineColorBlendState(); //no color targets for SDF + } else { + //specular write + blend_state = blend_state_opaque_specular; + depth_stencil.enable_depth_test = false; + depth_stencil.enable_depth_write = false; + } + } + + RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k); + pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0); + } + } + } + + valid = true; +} + +void RendererSceneRenderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { + if (!p_texture.is_valid()) { + default_texture_params.erase(p_name); + } else { + default_texture_params[p_name] = p_texture; + } +} + +void RendererSceneRenderForwardClustered::ShaderData::get_param_list(List *p_param_list) const { + Map order; + + for (Map::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { + continue; + } + + if (E->get().texture_order >= 0) { + order[E->get().texture_order + 100000] = E->key(); + } else { + order[E->get().order] = E->key(); + } + } + + for (Map::Element *E = order.front(); E; E = E->next()) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); + pi.name = E->get(); + p_param_list->push_back(pi); + } +} + +void RendererSceneRenderForwardClustered::ShaderData::get_instance_param_list(List *p_param_list) const { + for (Map::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + RendererStorage::InstanceShaderParam p; + p.info = ShaderLanguage::uniform_to_property_info(E->get()); + p.info.name = E->key(); //supply name + p.index = E->get().instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p_param_list->push_back(p); + } +} + +bool RendererSceneRenderForwardClustered::ShaderData::is_param_texture(const StringName &p_param) const { + if (!uniforms.has(p_param)) { + return false; + } + + return uniforms[p_param].texture_order >= 0; +} + +bool RendererSceneRenderForwardClustered::ShaderData::is_animated() const { + return false; +} + +bool RendererSceneRenderForwardClustered::ShaderData::casts_shadows() const { + return false; +} + +Variant RendererSceneRenderForwardClustered::ShaderData::get_default_parameter(const StringName &p_parameter) const { + if (uniforms.has(p_parameter)) { + ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; + Vector default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + } + return Variant(); +} + +RS::ShaderNativeSourceCode RendererSceneRenderForwardClustered::ShaderData::get_native_source_code() const { + RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton; + + return scene_singleton->shader.scene_shader.version_get_native_source_code(version); +} + +RendererSceneRenderForwardClustered::ShaderData::ShaderData() { + valid = false; + uses_screen_texture = false; +} + +RendererSceneRenderForwardClustered::ShaderData::~ShaderData() { + RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton; + ERR_FAIL_COND(!scene_singleton); + //pipeline variants will clear themselves if shader is gone + if (version.is_valid()) { + scene_singleton->shader.scene_shader.version_free(version); + } +} + +RendererStorageRD::ShaderData *RendererSceneRenderForwardClustered::_create_shader_func() { + ShaderData *shader_data = memnew(ShaderData); + return shader_data; +} + +void RendererSceneRenderForwardClustered::MaterialData::set_render_priority(int p_priority) { + priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits +} + +void RendererSceneRenderForwardClustered::MaterialData::set_next_pass(RID p_pass) { + next_pass = p_pass; +} + +void RendererSceneRenderForwardClustered::MaterialData::update_parameters(const Map &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton; + + if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { + p_uniform_dirty = true; + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + uniform_buffer = RID(); + } + + ubo_data.resize(shader_data->ubo_size); + if (ubo_data.size()) { + uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); + memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear + } + + //clear previous uniform set + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + uniform_set = RID(); + } + } + + //check whether buffer changed + if (p_uniform_dirty && ubo_data.size()) { + update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); + RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER); + } + + uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); + + if ((uint32_t)texture_cache.size() != tex_uniform_count) { + texture_cache.resize(tex_uniform_count); + p_textures_dirty = true; + + //clear previous uniform set + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + uniform_set = RID(); + } + } + + if (p_textures_dirty && tex_uniform_count) { + update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); + } + + if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { + // This material does not require an uniform set, so don't create it. + return; + } + + if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + //no reason to update uniform set, only UBO (or nothing) was needed to update + return; + } + + Vector uniforms; + + { + if (shader_data->ubo_size) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 0; + u.ids.push_back(uniform_buffer); + uniforms.push_back(u); + } + + const RID *textures = texture_cache.ptrw(); + for (uint32_t i = 0; i < tex_uniform_count; i++) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1 + i; + u.ids.push_back(textures[i]); + uniforms.push_back(u); + } + } + + uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET); +} + +RendererSceneRenderForwardClustered::MaterialData::~MaterialData() { + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + } + + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + } +} + +RendererStorageRD::MaterialData *RendererSceneRenderForwardClustered::_create_material_func(ShaderData *p_shader) { + MaterialData *material_data = memnew(MaterialData); + material_data->shader_data = p_shader; + material_data->last_frame = false; + //update will happen later anyway so do nothing. + return material_data; +} + +RendererSceneRenderForwardClustered::RenderBufferDataForward::~RenderBufferDataForward() { + clear(); +} + +void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_specular() { + if (!specular.is_valid()) { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = width; + tf.height = height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + if (msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } + + specular = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + if (msaa == RS::VIEWPORT_MSAA_DISABLED) { + { + Vector fb; + fb.push_back(color); + fb.push_back(specular); + fb.push_back(depth); + + color_specular_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector fb; + fb.push_back(specular); + + specular_only_fb = RD::get_singleton()->framebuffer_create(fb); + } + + } else { + tf.samples = texture_samples; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + specular_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + { + Vector fb; + fb.push_back(color_msaa); + fb.push_back(specular_msaa); + fb.push_back(depth_msaa); + + color_specular_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector fb; + fb.push_back(specular_msaa); + + specular_only_fb = RD::get_singleton()->framebuffer_create(fb); + } + } + } +} + +void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_giprobe() { + if (!giprobe_buffer.is_valid()) { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8G8_UINT; + tf.width = width; + tf.height = height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; + + if (msaa != RS::VIEWPORT_MSAA_DISABLED) { + RD::TextureFormat tf_aa = tf; + tf_aa.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf_aa.samples = texture_samples; + giprobe_buffer_msaa = RD::get_singleton()->texture_create(tf_aa, RD::TextureView()); + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } + + tf.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT; + + giprobe_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Vector fb; + if (msaa != RS::VIEWPORT_MSAA_DISABLED) { + fb.push_back(depth_msaa); + fb.push_back(normal_roughness_buffer_msaa); + fb.push_back(giprobe_buffer_msaa); + } else { + fb.push_back(depth); + fb.push_back(normal_roughness_buffer); + fb.push_back(giprobe_buffer); + } + + depth_normal_roughness_giprobe_fb = RD::get_singleton()->framebuffer_create(fb); + } +} + +void RendererSceneRenderForwardClustered::RenderBufferDataForward::clear() { + if (giprobe_buffer != RID()) { + RD::get_singleton()->free(giprobe_buffer); + giprobe_buffer = RID(); + + if (giprobe_buffer_msaa.is_valid()) { + RD::get_singleton()->free(giprobe_buffer_msaa); + giprobe_buffer_msaa = RID(); + } + + depth_normal_roughness_giprobe_fb = RID(); + } + + if (color_msaa.is_valid()) { + RD::get_singleton()->free(color_msaa); + color_msaa = RID(); + } + + if (depth_msaa.is_valid()) { + RD::get_singleton()->free(depth_msaa); + depth_msaa = RID(); + } + + if (specular.is_valid()) { + if (specular_msaa.is_valid()) { + RD::get_singleton()->free(specular_msaa); + specular_msaa = RID(); + } + RD::get_singleton()->free(specular); + specular = RID(); + } + + color = RID(); + depth = RID(); + color_specular_fb = RID(); + specular_only_fb = RID(); + color_fb = RID(); + depth_fb = RID(); + + if (normal_roughness_buffer.is_valid()) { + RD::get_singleton()->free(normal_roughness_buffer); + if (normal_roughness_buffer_msaa.is_valid()) { + RD::get_singleton()->free(normal_roughness_buffer_msaa); + normal_roughness_buffer_msaa = RID(); + } + normal_roughness_buffer = RID(); + depth_normal_roughness_fb = RID(); + } + + if (!render_sdfgi_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_sdfgi_uniform_set)) { + RD::get_singleton()->free(render_sdfgi_uniform_set); + } +} + +void RendererSceneRenderForwardClustered::RenderBufferDataForward::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { + clear(); + + msaa = p_msaa; + + width = p_width; + height = p_height; + + color = p_color_buffer; + depth = p_depth_buffer; + + if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) { + { + Vector fb; + fb.push_back(p_color_buffer); + fb.push_back(depth); + + color_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector fb; + fb.push_back(depth); + + depth_fb = RD::get_singleton()->framebuffer_create(fb); + } + } else { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = p_width; + tf.height = p_height; + tf.texture_type = RD::TEXTURE_TYPE_2D; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = { + RD::TEXTURE_SAMPLES_1, + RD::TEXTURE_SAMPLES_2, + RD::TEXTURE_SAMPLES_4, + RD::TEXTURE_SAMPLES_8, + RD::TEXTURE_SAMPLES_16 + }; + + texture_samples = ts[p_msaa]; + tf.samples = texture_samples; + + color_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + depth_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + { + Vector fb; + fb.push_back(color_msaa); + fb.push_back(depth_msaa); + + color_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector fb; + fb.push_back(depth_msaa); + + depth_fb = RD::get_singleton()->framebuffer_create(fb); + } + } +} + +void RendererSceneRenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferDataForward *rb) { + if (rb->normal_roughness_buffer.is_valid()) { + return; + } + + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + tf.width = rb->width; + tf.height = rb->height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + + if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } + + rb->normal_roughness_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) { + Vector fb; + fb.push_back(rb->depth); + fb.push_back(rb->normal_roughness_buffer); + rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); + } else { + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + tf.samples = rb->texture_samples; + rb->normal_roughness_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Vector fb; + fb.push_back(rb->depth_msaa); + fb.push_back(rb->normal_roughness_buffer_msaa); + rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); + } + + _render_buffers_clear_uniform_set(rb); +} + +RendererSceneRenderRD::RenderBufferData *RendererSceneRenderForwardClustered::_create_render_buffer_data() { + return memnew(RenderBufferDataForward); +} + +bool RendererSceneRenderForwardClustered::free(RID p_rid) { + if (RendererSceneRenderRD::free(p_rid)) { + return true; + } + return false; +} + +/// RENDERING /// + +template +void RendererSceneRenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { + RD::DrawListID draw_list = p_draw_list; + RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; + + //global scope bindings + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET); + + RID prev_material_uniform_set; + + RID prev_vertex_array_rd; + RID prev_index_array_rd; + RID prev_pipeline_rd; + RID prev_xforms_uniform_set; + + bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP); + + SceneState::PushConstant push_constant; + + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) { + push_constant.uv_offset = Math::make_half_float(p_params->uv_offset.y) << 16; + push_constant.uv_offset |= Math::make_half_float(p_params->uv_offset.x); + } else { + push_constant.uv_offset = 0; + } + + for (uint32_t i = p_from_element; i < p_to_element; i++) { + const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i]; + const RenderElementInfo &element_info = p_params->element_info[i]; + + push_constant.base_index = i + p_params->element_offset; + + RID material_uniform_set; + ShaderData *shader; + void *mesh_surface; + + if (shadow_pass || p_params->pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too + material_uniform_set = surf->material_uniform_set_shadow; + shader = surf->shader_shadow; + mesh_surface = surf->surface_shadow; + + } else { + material_uniform_set = surf->material_uniform_set; + shader = surf->shader; + mesh_surface = surf->surface; + } + + if (!mesh_surface) { + continue; + } + + //find cull variant + ShaderData::CullVariant cull_variant; + + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || p_params->pass_mode == PASS_MODE_SDF || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) { + cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED; + } else { + bool mirror = surf->owner->mirror; + if (p_params->reverse_cull) { + mirror = !mirror; + } + cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL; + } + + RS::PrimitiveType primitive = surf->primitive; + RID xforms_uniform_set = surf->owner->transforms_uniform_set; + + ShaderVersion shader_version = SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized. + + switch (p_params->pass_mode) { + case PASS_MODE_COLOR: + case PASS_MODE_COLOR_TRANSPARENT: { + if (element_info.uses_lightmap) { + shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS; + } else if (element_info.uses_forward_gi) { + shader_version = SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI; + } else { + shader_version = SHADER_VERSION_COLOR_PASS; + } + } break; + case PASS_MODE_COLOR_SPECULAR: { + if (element_info.uses_lightmap) { + shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR; + } else { + shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; + } + } break; + case PASS_MODE_SHADOW: + case PASS_MODE_DEPTH: { + shader_version = SHADER_VERSION_DEPTH_PASS; + } break; + case PASS_MODE_SHADOW_DP: { + shader_version = SHADER_VERSION_DEPTH_PASS_DP; + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { + shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS; + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { + shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE; + } break; + case PASS_MODE_DEPTH_MATERIAL: { + shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL; + } break; + case PASS_MODE_SDF: { + shader_version = SHADER_VERSION_DEPTH_PASS_WITH_SDF; + } break; + } + + PipelineCacheRD *pipeline = nullptr; + + pipeline = &shader->pipelines[cull_variant][primitive][shader_version]; + + RD::VertexFormatID vertex_format = -1; + RID vertex_array_rd; + RID index_array_rd; + + //skeleton and blend shape + if (surf->owner->mesh_instance.is_valid()) { + storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); + } else { + storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); + } + + index_array_rd = storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index); + + if (prev_vertex_array_rd != vertex_array_rd) { + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd); + prev_vertex_array_rd = vertex_array_rd; + } + + if (prev_index_array_rd != index_array_rd) { + if (index_array_rd.is_valid()) { + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array_rd); + } + prev_index_array_rd = index_array_rd; + } + + RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe); + + if (pipeline_rd != prev_pipeline_rd) { + // checking with prev shader does not make so much sense, as + // the pipeline may still be different. + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd); + prev_pipeline_rd = pipeline_rd; + } + + if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, TRANSFORMS_UNIFORM_SET); + prev_xforms_uniform_set = xforms_uniform_set; + } + + if (material_uniform_set != prev_material_uniform_set) { + //update uniform set + if (material_uniform_set.is_valid()) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET); + } + + prev_material_uniform_set = material_uniform_set; + } + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant)); + + uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : element_info.repeat; + RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count); + i += element_info.repeat - 1; //skip equal elements + } +} + +void RendererSceneRenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { + //use template for faster performance (pass mode comparisons are inlined) + + switch (p_params->pass_mode) { + case PASS_MODE_COLOR: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_COLOR_SPECULAR: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_COLOR_TRANSPARENT: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SHADOW: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SHADOW_DP: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_MATERIAL: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SDF: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + } +} + +void RendererSceneRenderForwardClustered::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) { + uint32_t render_total = p_params->element_count; + uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); + uint32_t render_from = p_thread * render_total / total_threads; + uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads); + _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to); +} + +void RendererSceneRenderForwardClustered::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector &p_storage_textures) { + RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer); + p_params->framebuffer_format = fb_format; + + if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time + //multi threaded + thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); + RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RendererSceneRenderForwardClustered::_render_list_thread_function, p_params); + RD::get_singleton()->draw_list_end(p_params->barrier); + } else { + //single threaded + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); + _render_list(draw_list, fb_format, p_params, 0, p_params->element_count); + RD::get_singleton()->draw_list_end(p_params->barrier); + } +} + +void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) { + //CameraMatrix projection = p_cam_projection; + //projection.flip_y(); // Vulkan and modern APIs use Y-Down + CameraMatrix correction; + correction.set_depth_correction(p_flip_y); + CameraMatrix projection = correction * p_cam_projection; + + //store camera into ubo + RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix); + RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); + RendererStorageRD::store_transform(p_cam_transform, scene_state.ubo.camera_matrix); + RendererStorageRD::store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); + + scene_state.ubo.z_far = p_zfar; + scene_state.ubo.z_near = p_znear; + + scene_state.ubo.pancake_shadows = p_pancake_shadows; + + RendererStorageRD::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); + + scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get(); + scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get(); + scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get(); + scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get(); + + Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size); + scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x; + scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y; + + scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_cluster_size); + scene_state.ubo.max_cluster_element_count_div_32 = p_max_cluster_elements / 32; + { + uint32_t cluster_screen_width = (p_screen_size.width - 1) / p_cluster_size + 1; + uint32_t cluster_screen_height = (p_screen_size.height - 1) / p_cluster_size + 1; + scene_state.ubo.cluster_type_size = cluster_screen_width * cluster_screen_height * (scene_state.ubo.max_cluster_element_count_div_32 + 32); + scene_state.ubo.cluster_width = cluster_screen_width; + } + + if (p_shadow_atlas.is_valid()) { + Vector2 sas = shadow_atlas_get_size(p_shadow_atlas); + scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x; + scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y; + } + { + Vector2 dss = directional_shadow_get_size(); + scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x; + scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y; + } + //time global variables + scene_state.ubo.time = time; + + scene_state.ubo.gi_upscale_for_msaa = false; + scene_state.ubo.volumetric_fog_enabled = false; + scene_state.ubo.fog_enabled = false; + + if (p_render_buffers.is_valid()) { + RenderBufferDataForward *render_buffers = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) { + scene_state.ubo.gi_upscale_for_msaa = true; + } + + if (render_buffers_has_volumetric_fog(p_render_buffers)) { + scene_state.ubo.volumetric_fog_enabled = true; + float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers); + if (fog_end > 0.0) { + scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end; + } else { + scene_state.ubo.volumetric_fog_inv_length = 1.0; + } + + float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup + if (fog_detail_spread > 0.0) { + scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread; + } else { + scene_state.ubo.volumetric_fog_detail_spread = 1.0; + } + } + } +#if 0 + if (p_render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_buffers)) { + scene_state.ubo.sdfgi_cascade_count = render_buffers_get_sdfgi_cascade_count(p_render_buffers); + scene_state.ubo.sdfgi_probe_axis_size = render_buffers_get_sdfgi_cascade_probe_count(p_render_buffers); + scene_state.ubo.sdfgi_cascade_probe_size[0] = scene_state.ubo.sdfgi_probe_axis_size - 1; //float version for performance + scene_state.ubo.sdfgi_cascade_probe_size[1] = scene_state.ubo.sdfgi_probe_axis_size - 1; + scene_state.ubo.sdfgi_cascade_probe_size[2] = scene_state.ubo.sdfgi_probe_axis_size - 1; + + float csize = render_buffers_get_sdfgi_cascade_size(p_render_buffers); + scene_state.ubo.sdfgi_probe_to_uvw = 1.0 / float(scene_state.ubo.sdfgi_cascade_probe_size[0]); + float occ_bias = 0.0; + scene_state.ubo.sdfgi_occlusion_bias = occ_bias / csize; + scene_state.ubo.sdfgi_use_occlusion = render_buffers_is_sdfgi_using_occlusion(p_render_buffers); + scene_state.ubo.sdfgi_energy = render_buffers_get_sdfgi_energy(p_render_buffers); + + float cascade_voxel_size = (csize / scene_state.ubo.sdfgi_cascade_probe_size[0]); + float occlusion_clamp = (cascade_voxel_size - 0.5) / cascade_voxel_size; + scene_state.ubo.sdfgi_occlusion_clamp[0] = occlusion_clamp; + scene_state.ubo.sdfgi_occlusion_clamp[1] = occlusion_clamp; + scene_state.ubo.sdfgi_occlusion_clamp[2] = occlusion_clamp; + scene_state.ubo.sdfgi_normal_bias = (render_buffers_get_sdfgi_normal_bias(p_render_buffers) / csize) * scene_state.ubo.sdfgi_cascade_probe_size[0]; + + //vec2 tex_pixel_size = 1.0 / vec2(ivec2( (OCT_SIZE+2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE+2) * params.probe_axis_size ) ); + //vec3 probe_uv_offset = (ivec3(OCT_SIZE+2,OCT_SIZE+2,(OCT_SIZE+2) * params.probe_axis_size)) * tex_pixel_size.xyx; + + uint32_t oct_size = gi.sdfgi_get_lightprobe_octahedron_size(); + + scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size * scene_state.ubo.sdfgi_probe_axis_size); + scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size); + scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[2] = 1.0; + + scene_state.ubo.sdfgi_probe_uv_offset[0] = float(oct_size + 2) * scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[0]; + scene_state.ubo.sdfgi_probe_uv_offset[1] = float(oct_size + 2) * scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[1]; + scene_state.ubo.sdfgi_probe_uv_offset[2] = float((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size) * scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[0]; + + scene_state.ubo.sdfgi_occlusion_renormalize[0] = 0.5; + scene_state.ubo.sdfgi_occlusion_renormalize[1] = 1.0; + scene_state.ubo.sdfgi_occlusion_renormalize[2] = 1.0 / float(scene_state.ubo.sdfgi_cascade_count); + + for (uint32_t i = 0; i < scene_state.ubo.sdfgi_cascade_count; i++) { + SceneState::UBO::SDFGICascade &c = scene_state.ubo.sdfgi_cascades[i]; + Vector3 pos = render_buffers_get_sdfgi_cascade_offset(p_render_buffers, i); + pos -= p_cam_transform.origin; //make pos local to camera, to reduce numerical error + c.position[0] = pos.x; + c.position[1] = pos.y; + c.position[2] = pos.z; + c.to_probe = 1.0 / render_buffers_get_sdfgi_cascade_probe_size(p_render_buffers, i); + + Vector3i probe_ofs = render_buffers_get_sdfgi_cascade_probe_offset(p_render_buffers, i); + c.probe_world_offset[0] = probe_ofs.x; + c.probe_world_offset[1] = probe_ofs.y; + c.probe_world_offset[2] = probe_ofs.z; + } + } +#endif + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { + scene_state.ubo.use_ambient_light = true; + scene_state.ubo.ambient_light_color_energy[0] = 1; + scene_state.ubo.ambient_light_color_energy[1] = 1; + scene_state.ubo.ambient_light_color_energy[2] = 1; + scene_state.ubo.ambient_light_color_energy[3] = 1.0; + scene_state.ubo.use_ambient_cubemap = false; + scene_state.ubo.use_reflection_cubemap = false; + scene_state.ubo.ssao_enabled = false; + + } else if (is_environment(p_environment)) { + RS::EnvironmentBG env_bg = environment_get_background(p_environment); + RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_environment); + + float bg_energy = environment_get_bg_energy(p_environment); + scene_state.ubo.ambient_light_color_energy[3] = bg_energy; + + scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_environment); + + //ambient + if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) { + Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_environment); + color = color.to_linear(); + + scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy; + scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy; + scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy; + scene_state.ubo.use_ambient_light = true; + scene_state.ubo.use_ambient_cubemap = false; + } else { + float energy = environment_get_ambient_light_energy(p_environment); + Color color = environment_get_ambient_light_color(p_environment); + color = color.to_linear(); + scene_state.ubo.ambient_light_color_energy[0] = color.r * energy; + scene_state.ubo.ambient_light_color_energy[1] = color.g * energy; + scene_state.ubo.ambient_light_color_energy[2] = color.b * energy; + + Basis sky_transform = environment_get_sky_orientation(p_environment); + sky_transform = sky_transform.inverse() * p_cam_transform.basis; + RendererStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); + + scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY; + scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR; + } + + //specular + RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_environment); + if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) { + scene_state.ubo.use_reflection_cubemap = true; + } else { + scene_state.ubo.use_reflection_cubemap = false; + } + + scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_is_ssao_enabled(p_environment); + scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_environment); + scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_environment); + + Color ao_color = environment_get_ao_color(p_environment).to_linear(); + scene_state.ubo.ao_color[0] = ao_color.r; + scene_state.ubo.ao_color[1] = ao_color.g; + scene_state.ubo.ao_color[2] = ao_color.b; + scene_state.ubo.ao_color[3] = ao_color.a; + + scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment); + scene_state.ubo.fog_density = environment_get_fog_density(p_environment); + scene_state.ubo.fog_height = environment_get_fog_height(p_environment); + scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_environment); + if (scene_state.ubo.fog_height_density >= 0.0001) { + scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density; + } + scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment); + + Color fog_color = environment_get_fog_light_color(p_environment).to_linear(); + float fog_energy = environment_get_fog_light_energy(p_environment); + + scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; + scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy; + scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; + + scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment); + + } else { + if (p_reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) { + scene_state.ubo.use_ambient_light = false; + } else { + scene_state.ubo.use_ambient_light = true; + Color clear_color = p_default_bg_color; + clear_color = clear_color.to_linear(); + scene_state.ubo.ambient_light_color_energy[0] = clear_color.r; + scene_state.ubo.ambient_light_color_energy[1] = clear_color.g; + scene_state.ubo.ambient_light_color_energy[2] = clear_color.b; + scene_state.ubo.ambient_light_color_energy[3] = 1.0; + } + + scene_state.ubo.use_ambient_cubemap = false; + scene_state.ubo.use_reflection_cubemap = false; + scene_state.ubo.ssao_enabled = false; + } + + scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active(); + scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount(); + scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit(); + + if (p_index >= (int)scene_state.uniform_buffers.size()) { + uint32_t from = scene_state.uniform_buffers.size(); + scene_state.uniform_buffers.resize(p_index + 1); + render_pass_uniform_sets.resize(p_index + 1); + for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) { + scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); + } + } + RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER); +} + +void RendererSceneRenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) { + if (scene_state.instance_data[p_render_list].size() > 0) { + if (scene_state.instance_buffer[p_render_list] == RID() || scene_state.instance_buffer_size[p_render_list] < scene_state.instance_data[p_render_list].size()) { + if (scene_state.instance_buffer[p_render_list] != RID()) { + RD::get_singleton()->free(scene_state.instance_buffer[p_render_list]); + } + uint32_t new_size = nearest_power_of_2_templated(MAX(uint64_t(INSTANCE_DATA_BUFFER_MIN_SIZE), scene_state.instance_data[p_render_list].size())); + scene_state.instance_buffer[p_render_list] = RD::get_singleton()->storage_buffer_create(new_size * sizeof(SceneState::InstanceData)); + scene_state.instance_buffer_size[p_render_list] = new_size; + } + RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER); + } +} +void RendererSceneRenderForwardClustered::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { + RenderList *rl = &render_list[p_render_list]; + uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size(); + + scene_state.instance_data[p_render_list].resize(p_offset + element_total); + rl->element_info.resize(p_offset + element_total); + + uint32_t repeats = 0; + GeometryInstanceSurfaceDataCache *prev_surface = nullptr; + for (uint32_t i = 0; i < element_total; i++) { + GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset]; + GeometryInstanceForward *inst = surface->owner; + + SceneState::InstanceData &instance_data = scene_state.instance_data[p_render_list][i + p_offset]; + + if (inst->store_transform_cache) { + RendererStorageRD::store_transform(inst->transform, instance_data.transform); + } else { + RendererStorageRD::store_transform(Transform(), instance_data.transform); + } + + instance_data.flags = inst->flags_cache; + instance_data.gi_offset = inst->gi_offset_cache; + instance_data.layer_mask = inst->layer_mask; + instance_data.instance_uniforms_ofs = uint32_t(inst->shader_parameters_offset); + instance_data.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x; + instance_data.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y; + instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x; + instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y; + + bool cant_repeat = instance_data.flags & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid(); + + if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2) { + //this element is the same as the previous one, count repeats to draw it using instancing + repeats++; + } else { + if (repeats > 0) { + for (uint32_t j = 1; j <= repeats; j++) { + rl->element_info[p_offset + i - j].repeat = j; + } + } + repeats = 1; + } + + RenderElementInfo &element_info = rl->element_info[p_offset + i]; + + element_info.lod_index = surface->sort.lod_index; + element_info.uses_forward_gi = surface->sort.uses_forward_gi; + element_info.uses_lightmap = surface->sort.uses_lightmap; + + if (cant_repeat) { + prev_surface = nullptr; + } else { + prev_surface = surface; + } + } + + if (repeats > 0) { + for (uint32_t j = 1; j <= repeats; j++) { + rl->element_info[p_offset + element_total - j].repeat = j; + } + } + + if (p_update_buffer) { + _update_instance_data_buffer(p_render_list); + } +} + +void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_render_list, const PagedArray &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_append) { + if (p_render_list == RENDER_LIST_OPAQUE) { + scene_state.used_sss = false; + scene_state.used_screen_texture = false; + scene_state.used_normal_texture = false; + scene_state.used_depth_texture = false; + } + uint32_t lightmap_captures_used = 0; + + Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); + near_plane.d += p_cam_projection.get_z_near(); + float z_max = p_cam_projection.get_z_far() - p_cam_projection.get_z_near(); + + RenderList *rl = &render_list[p_render_list]; + _update_dirty_geometry_instances(); + + if (!p_append) { + rl->clear(); + if (p_render_list == RENDER_LIST_OPAQUE) { + render_list[RENDER_LIST_ALPHA].clear(); //opaque fills alpha too + } + } + + //fill list + + for (int i = 0; i < (int)p_instances.size(); i++) { + GeometryInstanceForward *inst = static_cast(p_instances[i]); + + Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal); + inst->depth = near_plane.distance_to(support_min); + uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15); + + uint32_t flags = inst->base_flags; //fill flags if appropriate + + bool uses_lightmap = false; + bool uses_gi = false; + + if (p_render_list == RENDER_LIST_OPAQUE) { + //setup GI + + if (inst->lightmap_instance.is_valid()) { + int32_t lightmap_cull_index = -1; + for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) { + if (scene_state.lightmap_ids[j] == inst->lightmap_instance) { + lightmap_cull_index = j; + break; + } + } + if (lightmap_cull_index >= 0) { + inst->gi_offset_cache = inst->lightmap_slice_index << 16; + inst->gi_offset_cache |= lightmap_cull_index; + flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP; + if (scene_state.lightmap_has_sh[lightmap_cull_index]) { + flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP; + } + uses_lightmap = true; + } else { + inst->gi_offset_cache = 0xFFFFFFFF; + } + + } else if (inst->lightmap_sh) { + if (lightmap_captures_used < scene_state.max_lightmap_captures) { + const Color *src_capture = inst->lightmap_sh->sh; + LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used]; + for (int j = 0; j < 9; j++) { + lcd.sh[j * 4 + 0] = src_capture[j].r; + lcd.sh[j * 4 + 1] = src_capture[j].g; + lcd.sh[j * 4 + 2] = src_capture[j].b; + lcd.sh[j * 4 + 3] = src_capture[j].a; + } + flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE; + inst->gi_offset_cache = lightmap_captures_used; + lightmap_captures_used++; + uses_lightmap = true; + } + + } else if (!low_end) { + if (p_using_opaque_gi) { + flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; + } + + if (inst->gi_probes[0].is_valid()) { + uint32_t probe0_index = 0xFFFF; + uint32_t probe1_index = 0xFFFF; + + for (uint32_t j = 0; j < scene_state.giprobes_used; j++) { + if (scene_state.giprobe_ids[j] == inst->gi_probes[0]) { + probe0_index = j; + } else if (scene_state.giprobe_ids[j] == inst->gi_probes[1]) { + probe1_index = j; + } + } + + if (probe0_index == 0xFFFF && probe1_index != 0xFFFF) { + //0 must always exist if a probe exists + SWAP(probe0_index, probe1_index); + } + + inst->gi_offset_cache = probe0_index | (probe1_index << 16); + flags |= INSTANCE_DATA_FLAG_USE_GIPROBE; + uses_gi = true; + } else { + if (p_using_sdfgi && inst->can_sdfgi) { + flags |= INSTANCE_DATA_FLAG_USE_SDFGI; + uses_gi = true; + } + inst->gi_offset_cache = 0xFFFFFFFF; + } + } + } + inst->flags_cache = flags; + + GeometryInstanceSurfaceDataCache *surf = inst->surface_caches; + + while (surf) { + surf->sort.uses_forward_gi = 0; + surf->sort.uses_lightmap = 0; + + // LOD + + if (p_screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) { + //lod + Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_lod_plane.normal); + Vector3 lod_support_max = inst->transformed_aabb.get_support(p_lod_plane.normal); + + float distance_min = p_lod_plane.distance_to(lod_support_min); + float distance_max = p_lod_plane.distance_to(lod_support_max); + + float distance = 0.0; + + if (distance_min * distance_max < 0.0) { + //crossing plane + distance = 0.0; + } else if (distance_min >= 0.0) { + distance = distance_min; + } else if (distance_max <= 0.0) { + distance = -distance_max; + } + + surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_lod_distance_multiplier, p_screen_lod_threshold); + } else { + surf->sort.lod_index = 0; + } + + // ADD Element + if (p_pass_mode == PASS_MODE_COLOR) { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + rl->add_element(surf); + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) { + render_list[RENDER_LIST_ALPHA].add_element(surf); + if (uses_gi) { + surf->sort.uses_forward_gi = 1; + } + } + + if (uses_lightmap) { + surf->sort.uses_lightmap = 1; + } + + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) { + scene_state.used_sss = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) { + scene_state.used_screen_texture = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE) { + scene_state.used_normal_texture = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) { + scene_state.used_depth_texture = true; + } + + } else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) { + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) { + rl->add_element(surf); + } + } else { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + rl->add_element(surf); + } + } + + surf->sort.depth_layer = depth_layer; + + surf = surf->next; + } + } + + if (p_render_list == RENDER_LIST_OPAQUE && lightmap_captures_used) { + RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures, RD::BARRIER_MASK_RASTER); + } +} + +void RendererSceneRenderForwardClustered::_setup_giprobes(const PagedArray &p_giprobes) { + scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES)); + for (uint32_t i = 0; i < scene_state.giprobes_used; i++) { + scene_state.giprobe_ids[i] = p_giprobes[i]; + } +} + +void RendererSceneRenderForwardClustered::_setup_lightmaps(const PagedArray &p_lightmaps, const Transform &p_cam_transform) { + scene_state.lightmaps_used = 0; + for (int i = 0; i < (int)p_lightmaps.size(); i++) { + if (i >= (int)scene_state.max_lightmaps) { + break; + } + + RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]); + + Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis; + to_lm = to_lm.inverse().transposed(); //will transform normals + RendererStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform); + scene_state.lightmap_ids[i] = p_lightmaps[i]; + scene_state.lightmap_has_sh[i] = storage->lightmap_uses_spherical_harmonics(lightmap); + + scene_state.lightmaps_used++; + } + if (scene_state.lightmaps_used > 0) { + RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER); + } +} + +void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, const PagedArray &p_gi_probes, const PagedArray &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) { + RenderBufferDataForward *render_buffer = nullptr; + if (p_render_buffer.is_valid()) { + render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer); + } + RendererSceneEnvironmentRD *env = get_environment(p_environment); + + //first of all, make a new render pass + //fill up ubo + + RENDER_TIMESTAMP("Setup 3D Scene"); + + float lod_distance_multiplier = p_cam_projection.get_lod_multiplier(); + Plane lod_camera_plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { + p_screen_lod_threshold = 0.0; + } + + //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size; + + Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); + scene_state.ubo.viewport_size[0] = vp_he.x; + scene_state.ubo.viewport_size[1] = vp_he.y; + scene_state.ubo.directional_light_count = 0; + + Size2i screen_size; + RID opaque_framebuffer; + RID opaque_specular_framebuffer; + RID depth_framebuffer; + RID alpha_framebuffer; + + PassMode depth_pass_mode = PASS_MODE_DEPTH; + Vector depth_pass_clear; + bool using_separate_specular = false; + bool using_ssr = false; + bool using_sdfgi = false; + bool using_giprobe = false; + + if (render_buffer) { + screen_size.x = render_buffer->width; + screen_size.y = render_buffer->height; + + opaque_framebuffer = render_buffer->color_fb; + + if (!low_end && p_gi_probes.size() > 0) { + using_giprobe = true; + } + + if (!p_environment.is_valid() && using_giprobe) { + depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE; + + } else if (p_environment.is_valid() && (environment_is_ssr_enabled(p_environment) || environment_is_sdfgi_enabled(p_environment) || using_giprobe)) { + if (environment_is_sdfgi_enabled(p_environment)) { + depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also giprobe + using_sdfgi = true; + } else { + depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; + } + + if (environment_is_ssr_enabled(p_environment)) { + render_buffer->ensure_specular(); + using_separate_specular = true; + using_ssr = true; + opaque_specular_framebuffer = render_buffer->color_specular_fb; + } + + } else if (p_environment.is_valid() && (environment_is_ssao_enabled(p_environment) || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) { + depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS; + } + + switch (depth_pass_mode) { + case PASS_MODE_DEPTH: { + depth_framebuffer = render_buffer->depth_fb; + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { + _allocate_normal_roughness_texture(render_buffer); + depth_framebuffer = render_buffer->depth_normal_roughness_fb; + depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0)); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { + _allocate_normal_roughness_texture(render_buffer); + render_buffer->ensure_giprobe(); + depth_framebuffer = render_buffer->depth_normal_roughness_giprobe_fb; + depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0)); + depth_pass_clear.push_back(Color(0, 0, 0, 0)); + } break; + default: { + }; + } + + alpha_framebuffer = opaque_framebuffer; + } else if (p_reflection_probe.is_valid()) { + uint32_t resolution = reflection_probe_instance_get_resolution(p_reflection_probe); + screen_size.x = resolution; + screen_size.y = resolution; + + opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass); + depth_framebuffer = reflection_probe_instance_get_depth_framebuffer(p_reflection_probe, p_reflection_probe_pass); + alpha_framebuffer = opaque_framebuffer; + + if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) { + p_environment = RID(); //no environment on interiors + } + } else { + ERR_FAIL(); //bug? + } + + RD::get_singleton()->draw_command_begin_label("Render Setup"); + + _setup_lightmaps(p_lightmaps, p_cam_transform); + _setup_giprobes(p_gi_probes); + _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); + + _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example) + + _fill_render_list(RENDER_LIST_OPAQUE, p_instances, PASS_MODE_COLOR, p_cam_projection, p_cam_transform, using_sdfgi, using_sdfgi || using_giprobe, lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + render_list[RENDER_LIST_OPAQUE].sort_by_key(); + render_list[RENDER_LIST_ALPHA].sort_by_depth(); + _fill_instance_data(RENDER_LIST_OPAQUE); + _fill_instance_data(RENDER_LIST_ALPHA); + + RD::get_singleton()->draw_command_end_label(); + + bool using_sss = !low_end && render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; + + if (using_sss) { + using_separate_specular = true; + render_buffer->ensure_specular(); + using_separate_specular = true; + opaque_specular_framebuffer = render_buffer->color_specular_fb; + } + RID radiance_texture; + bool draw_sky = false; + bool draw_sky_fog_only = false; + + Color clear_color; + bool keep_color = false; + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { + clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black + } else if (is_environment(p_environment)) { + RS::EnvironmentBG bg_mode = environment_get_background(p_environment); + float bg_energy = environment_get_bg_energy(p_environment); + switch (bg_mode) { + case RS::ENV_BG_CLEAR_COLOR: { + clear_color = p_default_bg_color; + clear_color.r *= bg_energy; + clear_color.g *= bg_energy; + clear_color.b *= bg_energy; + if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) { + draw_sky_fog_only = true; + storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); + } + } break; + case RS::ENV_BG_COLOR: { + clear_color = environment_get_bg_color(p_environment); + clear_color.r *= bg_energy; + clear_color.g *= bg_energy; + clear_color.b *= bg_energy; + if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) { + draw_sky_fog_only = true; + storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); + } + } break; + case RS::ENV_BG_SKY: { + draw_sky = true; + } break; + case RS::ENV_BG_CANVAS: { + keep_color = true; + } break; + case RS::ENV_BG_KEEP: { + keep_color = true; + } break; + case RS::ENV_BG_CAMERA_FEED: { + } break; + default: { + } + } + // setup sky if used for ambient, reflections, or background + if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) { + RENDER_TIMESTAMP("Setup Sky"); + RD::get_singleton()->draw_command_begin_label("Setup Sky"); + CameraMatrix projection = p_cam_projection; + if (p_reflection_probe.is_valid()) { + CameraMatrix correction; + correction.set_depth_correction(true); + projection = correction * p_cam_projection; + } + + sky.setup(env, p_render_buffer, projection, p_cam_transform, screen_size, this); + + RID sky_rid = env->sky; + if (sky_rid.is_valid()) { + sky.update(env, projection, p_cam_transform, time); + radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid); + } else { + // do not try to draw sky if invalid + draw_sky = false; + } + RD::get_singleton()->draw_command_end_label(); + } + } else { + clear_color = p_default_bg_color; + } + + bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION; + bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES; + bool depth_pre_pass = !low_end && depth_framebuffer.is_valid(); + + bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment); + bool continue_depth = false; + if (depth_pre_pass) { //depth pre pass + + bool needs_pre_resolve = _needs_post_prepass_render(using_sdfgi || using_giprobe); + if (needs_pre_resolve) { + RENDER_TIMESTAMP("GI + Render Depth Pre-Pass (parallel)"); + } else { + RENDER_TIMESTAMP("Render Depth Pre-Pass"); + } + if (needs_pre_resolve) { + //pre clear the depth framebuffer, as AMD (and maybe others?) use compute for it, and barrier other compute shaders. + RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, depth_pass_clear); + RD::get_singleton()->draw_list_end(); + //start compute processes here, so they run at the same time as depth pre-pass + _post_prepass_render(using_sdfgi || using_giprobe); + } + + RD::get_singleton()->draw_command_begin_label("Render Depth Pre-Pass"); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, RID(), RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); + + bool finish_depth = using_ssao || using_sdfgi || using_giprobe; + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector() : depth_pass_clear); + + RD::get_singleton()->draw_command_end_label(); + + if (needs_pre_resolve) { + _pre_resolve_render(using_sdfgi || using_giprobe); + } + + if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + RENDER_TIMESTAMP("Resolve Depth Pre-Pass"); + RD::get_singleton()->draw_command_begin_label("Resolve Depth Pre-Pass"); + if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) { + if (needs_pre_resolve) { + RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, RD::BARRIER_MASK_COMPUTE); + } + static int texture_samples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 }; + storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_giprobe ? render_buffer->giprobe_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_giprobe ? render_buffer->giprobe_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]); + } else if (finish_depth) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); + } + RD::get_singleton()->draw_command_end_label(); + } + + continue_depth = !finish_depth; + } + + _pre_opaque_render(using_ssao, using_sdfgi || using_giprobe, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->giprobe_buffer : RID()); + + RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); + + scene_state.ubo.directional_light_count = _get_render_state_directional_light_count(); + + _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), p_render_buffer.is_valid()); + + RENDER_TIMESTAMP("Render Opaque Pass"); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true); + + bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; + bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; + + { + bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes); + bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes); + + //regular forward for now + Vector c; + if (using_separate_specular) { + Color cc = clear_color.to_linear(); + cc.a = 0; //subsurf scatter must be 0 + c.push_back(cc); + c.push_back(Color(0, 0, 0, 0)); + } else { + c.push_back(clear_color.to_linear()); + } + + RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer; + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); + if (will_continue_color && using_separate_specular) { + // close the specular framebuffer, as it's no longer used + RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); + RD::get_singleton()->draw_list_end(); + } + } + + RD::get_singleton()->draw_command_end_label(); + + if (debug_giprobes) { + //debug giprobes + bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); + bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); + + CameraMatrix dc; + dc.set_depth_correction(true); + CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); + RD::get_singleton()->draw_command_begin_label("Debug GIProbes"); + for (int i = 0; i < (int)p_gi_probes.size(); i++) { + gi.debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); + } + RD::get_singleton()->draw_command_end_label(); + RD::get_singleton()->draw_list_end(); + } + + if (debug_sdfgi_probes) { + //debug giprobes + bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); + bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); + + CameraMatrix dc; + dc.set_depth_correction(true); + CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); + RD::get_singleton()->draw_command_begin_label("Debug SDFGI"); + _debug_sdfgi_probes(p_render_buffer, draw_list, opaque_framebuffer, cm); + RD::get_singleton()->draw_command_end_label(); + RD::get_singleton()->draw_list_end(); + } + + if (draw_sky || draw_sky_fog_only) { + RENDER_TIMESTAMP("Render Sky"); + + CameraMatrix projection = p_cam_projection; + if (p_reflection_probe.is_valid()) { + CameraMatrix correction; + correction.set_depth_correction(true); + projection = correction * p_cam_projection; + } + RD::get_singleton()->draw_command_begin_label("Draw Sky"); + sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_cam_transform, time); + RD::get_singleton()->draw_command_end_label(); + } + + if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); + if (using_separate_specular) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular); + } + } + + if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); + } + + if (using_separate_specular) { + if (using_sss) { + RENDER_TIMESTAMP("Sub Surface Scattering"); + RD::get_singleton()->draw_command_begin_label("Process Sub Surface Scattering"); + _process_sss(p_render_buffer, p_cam_projection); + RD::get_singleton()->draw_command_end_label(); + } + + if (using_ssr) { + RENDER_TIMESTAMP("Screen Space Reflection"); + RD::get_singleton()->draw_command_begin_label("Process Screen Space Reflections"); + _process_ssr(p_render_buffer, render_buffer->color_fb, render_buffer->normal_roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_environment, p_cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED); + RD::get_singleton()->draw_command_end_label(); + } else { + //just mix specular back + RENDER_TIMESTAMP("Merge Specular"); + storage->get_effects()->merge_specular(render_buffer->color_fb, render_buffer->specular, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED ? RID() : render_buffer->color, RID()); + } + } + + RENDER_TIMESTAMP("Render Transparent Pass"); + + RD::get_singleton()->draw_command_begin_label("Render Transparent Pass"); + + rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true); + + _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); + + { + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + } + + RD::get_singleton()->draw_command_end_label(); + + RD::get_singleton()->draw_command_begin_label("Resolve"); + + if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); + } + + RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneRenderForwardClustered::_render_shadow_begin() { + scene_state.shadow_passes.clear(); + RD::get_singleton()->draw_command_begin_label("Shadow Setup"); + _update_render_base_uniform_set(); + + render_list[RENDER_LIST_SECONDARY].clear(); + scene_state.instance_data[RENDER_LIST_SECONDARY].clear(); +} +void RendererSceneRenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) { + uint32_t shadow_pass_index = scene_state.shadow_passes.size(); + + SceneState::ShadowPass shadow_pass; + + scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; + + _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), !p_flip_y, Color(), 0, p_zfar, false, p_use_pancake, shadow_pass_index); + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { + p_screen_lod_threshold = 0.0; + } + + PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; + + uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size(); + _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_projection, p_transform, false, false, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, true); + uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from; + render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size); + _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false); + + { + //regular forward for now + bool flip_cull = p_use_dp_flip; + if (p_flip_y) { + flip_cull = !flip_cull; + } + + shadow_pass.element_from = render_list_from; + shadow_pass.element_count = render_list_size; + shadow_pass.flip_cull = flip_cull; + shadow_pass.pass_mode = pass_mode; + + shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete + shadow_pass.camera_plane = p_camera_plane; + shadow_pass.screen_lod_threshold = p_screen_lod_threshold; + shadow_pass.lod_distance_multiplier = p_lod_distance_multiplier; + + shadow_pass.framebuffer = p_framebuffer; + shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE); + shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE; + shadow_pass.rect = p_rect; + + scene_state.shadow_passes.push_back(shadow_pass); + } +} + +void RendererSceneRenderForwardClustered::_render_shadow_process() { + _update_instance_data_buffer(RENDER_LIST_SECONDARY); + //render shadows one after the other, so this can be done un-barriered and the driver can optimize (as well as allow us to run compute at the same time) + + for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { + //render passes need to be configured after instance buffer is done, since they need the latest version + SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; + shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray(), PagedArray(), false, i); + } + + RD::get_singleton()->draw_command_end_label(); +} +void RendererSceneRenderForwardClustered::_render_shadow_end(uint32_t p_barrier) { + RD::get_singleton()->draw_command_begin_label("Shadow Render"); + + for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { + SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; + RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, true, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER); + _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector(), 1.0, 0, shadow_pass.rect); + } + + if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) { + RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, p_barrier); + } + RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneRenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray &p_instances) { + RENDER_TIMESTAMP("Setup Render Collider Heightfield"); + + RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); + + _update_render_base_uniform_set(); + scene_state.ubo.dual_paraboloid_side = 0; + + _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false); + + PassMode pass_mode = PASS_MODE_SHADOW; + + _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); + + RENDER_TIMESTAMP("Render Collider Heightfield"); + + { + //regular forward for now + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, true, rp_uniform_set); + _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); + } + RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneRenderForwardClustered::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) { + RENDER_TIMESTAMP("Setup Rendering Material"); + + RD::get_singleton()->draw_command_begin_label("Render Material"); + + _update_render_base_uniform_set(); + + scene_state.ubo.dual_paraboloid_side = 0; + scene_state.ubo.material_uv2_mode = false; + + _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); + + PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; + _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); + + RENDER_TIMESTAMP("Render Material"); + + { + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set); + //regular forward for now + Vector clear; + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); + RD::get_singleton()->draw_list_end(); + } + + RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneRenderForwardClustered::_render_uv2(const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) { + RENDER_TIMESTAMP("Setup Rendering UV2"); + + RD::get_singleton()->draw_command_begin_label("Render UV2"); + + _update_render_base_uniform_set(); + + scene_state.ubo.dual_paraboloid_side = 0; + scene_state.ubo.material_uv2_mode = true; + + _setup_environment(RID(), RID(), CameraMatrix(), Transform(), RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); + + PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; + _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform()); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); + + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); + + RENDER_TIMESTAMP("Render Material"); + + { + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set, true); + //regular forward for now + Vector clear; + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + clear.push_back(Color(0, 0, 0, 0)); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); + + const int uv_offset_count = 9; + static const Vector2 uv_offsets[uv_offset_count] = { + Vector2(-1, 1), + Vector2(1, 1), + Vector2(1, -1), + Vector2(-1, -1), + Vector2(-1, 0), + Vector2(1, 0), + Vector2(0, -1), + Vector2(0, 1), + Vector2(0, 0), + + }; + + for (int i = 0; i < uv_offset_count; i++) { + Vector2 ofs = uv_offsets[i]; + ofs.x /= p_region.size.width; + ofs.y /= p_region.size.height; + render_list_params.uv_offset = ofs; + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative + } + render_list_params.uv_offset = Vector2(); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles + + RD::get_singleton()->draw_list_end(); + } + + RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneRenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) { + RENDER_TIMESTAMP("Render SDFGI"); + + RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel"); + + _update_render_base_uniform_set(); + + RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + ERR_FAIL_COND(!render_buffer); + + PassMode pass_mode = PASS_MODE_SDF; + _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform()); + render_list[RENDER_LIST_SECONDARY].sort_by_key(); + _fill_instance_data(RENDER_LIST_SECONDARY); + + Vector3 half_extents = p_bounds.size * 0.5; + Vector3 center = p_bounds.position + half_extents; + + Vector sbs; + sbs.push_back(p_albedo_texture); + sbs.push_back(p_emission_texture); + sbs.push_back(p_emission_aniso_texture); + sbs.push_back(p_geom_facing_texture); + + //print_line("re-render " + p_from + " - " + p_size + " bounds " + p_bounds); + for (int i = 0; i < 3; i++) { + scene_state.ubo.sdf_offset[i] = p_from[i]; + scene_state.ubo.sdf_size[i] = p_size[i]; + } + + for (int i = 0; i < 3; i++) { + Vector3 axis; + axis[i] = 1.0; + Vector3 up, right; + int right_axis = (i + 1) % 3; + int up_axis = (i + 2) % 3; + up[up_axis] = 1.0; + right[right_axis] = 1.0; + + Size2i fb_size; + fb_size.x = p_size[right_axis]; + fb_size.y = p_size[up_axis]; + + Transform cam_xform; + cam_xform.origin = center + axis * half_extents; + cam_xform.basis.set_axis(0, right); + cam_xform.basis.set_axis(1, up); + cam_xform.basis.set_axis(2, axis); + + //print_line("pass: " + itos(i) + " xform " + cam_xform); + + float h_size = half_extents[right_axis]; + float v_size = half_extents[up_axis]; + float d_size = half_extents[i] * 2.0; + CameraMatrix camera_proj; + camera_proj.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size); + //print_line("pass: " + itos(i) + " cam hsize: " + rtos(h_size) + " vsize: " + rtos(v_size) + " dsize " + rtos(d_size)); + + Transform to_bounds; + to_bounds.origin = p_bounds.position; + to_bounds.basis.scale(p_bounds.size); + + RendererStorageRD::store_transform(to_bounds.affine_inverse() * cam_xform, scene_state.ubo.sdf_to_bounds); + + _setup_environment(RID(), RID(), camera_proj, cam_xform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); + + RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture); + + Map::Element *E = sdfgi_framebuffer_size_cache.find(fb_size); + if (!E) { + RID fb = RD::get_singleton()->framebuffer_create_empty(fb_size); + E = sdfgi_framebuffer_size_cache.insert(fb_size, fb); + } + + RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set, false); + _render_list_with_threads(&render_list_params, E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector(), 1.0, 0, Rect2(), sbs); + } + + RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneRenderForwardClustered::_base_uniforms_changed() { + if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { + RD::get_singleton()->free(render_base_uniform_set); + } + render_base_uniform_set = RID(); +} + +void RendererSceneRenderForwardClustered::_update_render_base_uniform_set() { + if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) { + if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { + RD::get_singleton()->free(render_base_uniform_set); + } + + lightmap_texture_array_version = storage->lightmap_array_get_version(); + + Vector uniforms; + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 1; + u.ids.resize(12); + RID *ids_ptr = u.ids.ptrw(); + ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.ids.push_back(shadow_sampler); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_omni_light_buffer()); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_spot_light_buffer()); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 5; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_reflection_probe_buffer()); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(get_directional_light_buffer()); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 7; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(scene_state.lightmap_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(scene_state.lightmap_capture_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 9; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID decal_atlas = storage->decal_atlas_get_texture(); + u.ids.push_back(decal_atlas); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 10; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID decal_atlas = storage->decal_atlas_get_texture_srgb(); + u.ids.push_back(decal_atlas); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 11; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_decal_buffer()); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 12; + u.ids.push_back(storage->global_variables_get_storage_buffer()); + uniforms.push_back(u); + } + + if (!low_end) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 13; + u.ids.push_back(sdfgi_get_ubo()); + uniforms.push_back(u); + } + + render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, SCENE_UNIFORM_SET); + } +} + +RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray &p_gi_probes, const PagedArray &p_lightmaps, bool p_use_directional_shadow_atlas, int p_index) { + //there should always be enough uniform buffers for render passes, otherwise bugs + ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID()); + + RenderBufferDataForward *rb = nullptr; + if (p_render_buffers.is_valid()) { + rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + } + + //default render buffer and scene state uniform set + + Vector uniforms; + + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(scene_state.uniform_buffers[p_index]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + RID instance_buffer = scene_state.instance_buffer[p_render_list]; + if (instance_buffer == RID()) { + instance_buffer = default_vec4_xform_buffer; // any buffer will do since its not used + } + u.ids.push_back(instance_buffer); + uniforms.push_back(u); + } + { + RID radiance_texture; + if (p_radiance_texture.is_valid()) { + radiance_texture = p_radiance_texture; + } else { + radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + } + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(radiance_texture); + uniforms.push_back(u); + } + + { + RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID(); + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + if (ref_texture.is_valid()) { + u.ids.push_back(ref_texture); + } else { + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK)); + } + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture; + if (p_shadow_atlas.is_valid()) { + texture = shadow_atlas_get_texture(p_shadow_atlas); + } + if (!texture.is_valid()) { + texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + } + u.ids.push_back(texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 5; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) { + u.ids.push_back(directional_shadow_get_texture()); + } else { + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + } + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(scene_state.max_lightmaps); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { + if (i < p_lightmaps.size()) { + RID base = lightmap_instance_get_lightmap(p_lightmaps[i]); + RID texture = storage->lightmap_get_texture(base); + RID rd_texture = storage->texture_get_rd_texture(texture); + u.ids.write[i] = rd_texture; + } else { + u.ids.write[i] = default_tex; + } + } + + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 7; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(MAX_GI_PROBES); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + for (int i = 0; i < MAX_GI_PROBES; i++) { + if (i < (int)p_gi_probes.size()) { + RID tex = gi.gi_probe_instance_get_texture(p_gi_probes[i]); + if (!tex.is_valid()) { + tex = default_tex; + } + u.ids.write[i] = tex; + } else { + u.ids.write[i] = default_tex; + } + } + + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer; + u.ids.push_back(cb); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 9; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 10; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_buffers) : RID(); + RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + if (!low_end) { + { + RD::Uniform u; + u.binding = 11; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = rb && rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_NORMAL); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 12; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID aot = rb ? render_buffers_get_ao_texture(p_render_buffers) : RID(); + RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 13; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID ambient_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_ambient_texture(p_render_buffers) : RID(); + RID texture = ambient_buffer.is_valid() ? ambient_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 14; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID reflection_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_reflection_texture(p_render_buffers) : RID(); + RID texture = reflection_buffer.is_valid() ? reflection_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.ids.push_back(texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 15; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID t; + if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { + t = render_buffers_get_sdfgi_irradiance_probes(p_render_buffers); + } else { + t = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + } + u.ids.push_back(t); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 16; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { + u.ids.push_back(render_buffers_get_sdfgi_occlusion_texture(p_render_buffers)); + } else { + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + } + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 17; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_buffers) : render_buffers_get_default_gi_probe_buffer()); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 18; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID vfog = RID(); + if (rb && render_buffers_has_volumetric_fog(p_render_buffers)) { + vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers); + if (vfog.is_null()) { + vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + } + } else { + vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + } + u.ids.push_back(vfog); + uniforms.push_back(u); + } + } + + if (p_index >= (int)render_pass_uniform_sets.size()) { + render_pass_uniform_sets.resize(p_index + 1); + } + + if (render_pass_uniform_sets[p_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[p_index])) { + RD::get_singleton()->free(render_pass_uniform_sets[p_index]); + } + + render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_PASS_UNIFORM_SET); + return render_pass_uniform_sets[p_index]; +} + +RID RendererSceneRenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) { + if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { + RD::get_singleton()->free(sdfgi_pass_uniform_set); + } + + Vector uniforms; + + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(scene_state.uniform_buffers[0]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(scene_state.instance_buffer[RENDER_LIST_SECONDARY]); + uniforms.push_back(u); + } + { + // No radiance texture. + RID radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(radiance_texture); + uniforms.push_back(u); + } + + { + // No reflection atlas. + RID ref_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK); + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(ref_texture); + uniforms.push_back(u); + } + + { + // No shadow atlas. + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + { + // No directional shadow atlas. + RD::Uniform u; + u.binding = 5; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + { + // No Lightmaps + RD::Uniform u; + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(scene_state.max_lightmaps); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { + u.ids.write[i] = default_tex; + } + + uniforms.push_back(u); + } + + { + // No GIProbes + RD::Uniform u; + u.binding = 7; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(MAX_GI_PROBES); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + for (int i = 0; i < MAX_GI_PROBES; i++) { + u.ids.write[i] = default_tex; + } + + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + RID cb = default_vec4_xform_buffer; + u.ids.push_back(cb); + uniforms.push_back(u); + } + + // actual sdfgi stuff + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 9; + u.ids.push_back(p_albedo_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 10; + u.ids.push_back(p_emission_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 11; + u.ids.push_back(p_emission_aniso_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 12; + u.ids.push_back(p_geom_facing_texture); + uniforms.push_back(u); + } + + sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET); + return sdfgi_pass_uniform_set; +} + +void RendererSceneRenderForwardClustered::_render_buffers_clear_uniform_set(RenderBufferDataForward *rb) { +} + +void RendererSceneRenderForwardClustered::_render_buffers_uniform_set_changed(RID p_render_buffers) { + RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + + _render_buffers_clear_uniform_set(rb); +} + +RID RendererSceneRenderForwardClustered::_render_buffers_get_normal_texture(RID p_render_buffers) { + RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + + return rb->normal_roughness_buffer; +} + +RendererSceneRenderForwardClustered *RendererSceneRenderForwardClustered::singleton = nullptr; + +void RendererSceneRenderForwardClustered::set_time(double p_time, double p_step) { + time = p_time; + RendererSceneRenderRD::set_time(p_time, p_step); +} + +void RendererSceneRenderForwardClustered::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + if (ginstance->dirty_list_element.in_list()) { + return; + } + + //clear surface caches + GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; + + while (surf) { + GeometryInstanceSurfaceDataCache *next = surf->next; + geometry_instance_surface_alloc.free(surf); + surf = next; + } + + ginstance->surface_caches = nullptr; + + geometry_instance_dirty_list.add(&ginstance->dirty_list_element); +} + +void RendererSceneRenderForwardClustered::_geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) { + bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; + bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); + bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; + bool has_alpha = has_base_alpha || has_blend_alpha; + + uint32_t flags = 0; + + if (p_material->shader_data->uses_sss) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING; + } + + if (p_material->shader_data->uses_screen_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE; + } + + if (p_material->shader_data->uses_depth_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE; + } + + if (p_material->shader_data->uses_normal_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE; + } + + if (ginstance->data->cast_double_sided_shaodows) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS; + } + + if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) { + //material is only meant for alpha pass + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; + if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED)) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; + } + } else { + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; + } + + MaterialData *material_shadow = nullptr; + void *surface_shadow = nullptr; + if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; + material_shadow = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + + RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh); + + if (shadow_mesh.is_valid()) { + surface_shadow = storage->mesh_get_surface(shadow_mesh, p_surface); + } + + } else { + material_shadow = p_material; + } + + GeometryInstanceSurfaceDataCache *sdcache = geometry_instance_surface_alloc.alloc(); + + sdcache->flags = flags; + + sdcache->shader = p_material->shader_data; + sdcache->material_uniform_set = p_material->uniform_set; + sdcache->surface = storage->mesh_get_surface(p_mesh, p_surface); + sdcache->primitive = storage->mesh_surface_get_primitive(sdcache->surface); + sdcache->surface_index = p_surface; + + if (ginstance->data->dirty_dependencies) { + storage->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker); + } + + //shadow + sdcache->shader_shadow = material_shadow->shader_data; + sdcache->material_uniform_set_shadow = material_shadow->uniform_set; + + sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface; + + sdcache->owner = ginstance; + + sdcache->next = ginstance->surface_caches; + ginstance->surface_caches = sdcache; + + //sortkey + + sdcache->sort.sort_key1 = 0; + sdcache->sort.sort_key2 = 0; + + sdcache->sort.surface_index = p_surface; + sdcache->sort.material_id_low = p_material_id & 0x3FFF; + sdcache->sort.material_id_hi = p_material_id >> 14; + sdcache->sort.shader_id = p_shader_id; + sdcache->sort.geometry_id = p_mesh.get_local_index(); //only meshes can repeat anyway + sdcache->sort.uses_forward_gi = ginstance->can_sdfgi; + sdcache->sort.priority = p_material->priority; +} + +void RendererSceneRenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) { + RID m_src; + + m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material; + + MaterialData *material = nullptr; + + if (m_src.is_valid()) { + material = (MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (material) { + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker); + } + } else { + material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + m_src = default_material; + } + + ERR_FAIL_COND(!material); + + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, m_src.get_local_index(), storage->material_get_shader_id(m_src), p_mesh); + + while (material->next_pass.is_valid()) { + RID next_pass = material->next_pass; + material = (MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + break; + } + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker); + } + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh); + } +} + +void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + + if (ginstance->data->dirty_dependencies) { + ginstance->data->dependency_tracker.update_begin(); + } + + //add geometry for drawing + switch (ginstance->data->base_type) { + case RS::INSTANCE_MESH: { + const RID *materials = nullptr; + uint32_t surface_count; + RID mesh = ginstance->data->base; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + //if no materials, no surfaces. + const RID *inst_materials = ginstance->data->surface_materials.ptr(); + uint32_t surf_mat_count = ginstance->data->surface_materials.size(); + + for (uint32_t j = 0; j < surface_count; j++) { + RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j]; + _geometry_instance_add_surface(ginstance, j, material, mesh); + } + } + + ginstance->instance_count = 1; + + } break; + + case RS::INSTANCE_MULTIMESH: { + RID mesh = storage->multimesh_get_mesh(ginstance->data->base); + if (mesh.is_valid()) { + const RID *materials = nullptr; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + for (uint32_t j = 0; j < surface_count; j++) { + _geometry_instance_add_surface(ginstance, j, materials[j], mesh); + } + } + + ginstance->instance_count = storage->multimesh_get_instances_to_draw(ginstance->data->base); + } + + } break; +#if 0 + case RS::INSTANCE_IMMEDIATE: { + RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); + ERR_CONTINUE(!immediate); + + _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); + + } break; +#endif + case RS::INSTANCE_PARTICLES: { + int draw_passes = storage->particles_get_draw_passes(ginstance->data->base); + + for (int j = 0; j < draw_passes; j++) { + RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j); + if (!mesh.is_valid()) + continue; + + const RID *materials = nullptr; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + for (uint32_t k = 0; k < surface_count; k++) { + _geometry_instance_add_surface(ginstance, k, materials[k], mesh); + } + } + } + + ginstance->instance_count = storage->particles_get_amount(ginstance->data->base); + + } break; + + default: { + } + } + + //Fill push constant + + bool store_transform = true; + + if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; + uint32_t stride; + if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + stride = 2; + } else { + stride = 3; + } + if (storage->multimesh_uses_colors(ginstance->data->base)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + stride += 1; + } + if (storage->multimesh_uses_custom_data(ginstance->data->base)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + stride += 1; + } + + ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); + + } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; + uint32_t stride; + if (false) { // 2D particles + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + stride = 2; + } else { + stride = 3; + } + + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + stride += 1; + + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + stride += 1; + + ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + + if (!storage->particles_is_using_local_coords(ginstance->data->base)) { + store_transform = false; + } + ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); + + } else if (ginstance->data->base_type == RS::INSTANCE_MESH) { + if (storage->skeleton_is_valid(ginstance->data->skeleton)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_SKELETON; + ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET); + if (ginstance->data->dirty_dependencies) { + storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker); + } + } + } + + ginstance->store_transform_cache = store_transform; + ginstance->can_sdfgi = false; + + if (!lightmap_instance_is_valid(ginstance->lightmap_instance) && !low_end) { + if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) { + ginstance->can_sdfgi = true; + } + } + + if (ginstance->data->dirty_dependencies) { + ginstance->data->dependency_tracker.update_end(); + ginstance->data->dirty_dependencies = false; + } + + ginstance->dirty_list_element.remove_from_list(); +} + +void RendererSceneRenderForwardClustered::_update_dirty_geometry_instances() { + while (geometry_instance_dirty_list.first()) { + _geometry_instance_update(geometry_instance_dirty_list.first()->self()); + } +} + +void RendererSceneRenderForwardClustered::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) { + switch (p_notification) { + case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: + case RendererStorage::DEPENDENCY_CHANGED_MESH: + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: { + static_cast(singleton)->_geometry_instance_mark_dirty(static_cast(p_tracker->userdata)); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: { + GeometryInstanceForward *ginstance = static_cast(p_tracker->userdata); + if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { + ginstance->instance_count = static_cast(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base); + } + } break; + default: { + //rest of notifications of no interest + } break; + } +} +void RendererSceneRenderForwardClustered::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) { + static_cast(singleton)->_geometry_instance_mark_dirty(static_cast(p_tracker->userdata)); +} + +RendererSceneRender::GeometryInstance *RendererSceneRenderForwardClustered::geometry_instance_create(RID p_base) { + RS::InstanceType type = storage->get_base_type(p_base); + ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr); + + GeometryInstanceForward *ginstance = geometry_instance_alloc.alloc(); + ginstance->data = memnew(GeometryInstanceForward::Data); + + ginstance->data->base = p_base; + ginstance->data->base_type = type; + ginstance->data->dependency_tracker.userdata = ginstance; + ginstance->data->dependency_tracker.changed_callback = _geometry_instance_dependency_changed; + ginstance->data->dependency_tracker.deleted_callback = _geometry_instance_dependency_deleted; + + _geometry_instance_mark_dirty(ginstance); + + return ginstance; +} +void RendererSceneRenderForwardClustered::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->skeleton = p_skeleton; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForwardClustered::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->material_override = p_override; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForwardClustered::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_materials) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->surface_materials = p_materials; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForwardClustered::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->mesh_instance = p_mesh_instance; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->transform = p_transform; + ginstance->mirror = p_transform.basis.determinant() < 0; + ginstance->data->aabb = p_aabb; + ginstance->transformed_aabb = p_transformed_aabb; + + Vector3 model_scale_vec = p_transform.basis.get_scale_abs(); + // handle non uniform scale here + + float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z)); + float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z)); + ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9; + + ginstance->lod_model_scale = max_scale; +} +void RendererSceneRenderForwardClustered::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->lod_bias = p_lod_bias; +} +void RendererSceneRenderForwardClustered::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->use_baked_light = p_enable; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForwardClustered::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->use_dynamic_gi = p_enable; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForwardClustered::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->lightmap_instance = p_lightmap_instance; + ginstance->lightmap_uv_scale = p_lightmap_uv_scale; + ginstance->lightmap_slice_index = p_lightmap_slice_index; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForwardClustered::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (p_sh9) { + if (ginstance->lightmap_sh == nullptr) { + ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc(); + } + + copymem(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9); + } else { + if (ginstance->lightmap_sh != nullptr) { + geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); + ginstance->lightmap_sh = nullptr; + } + } + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForwardClustered::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->shader_parameters_offset = p_offset; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForwardClustered::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + + ginstance->data->cast_double_sided_shaodows = p_enable; + _geometry_instance_mark_dirty(ginstance); +} + +void RendererSceneRenderForwardClustered::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->layer_mask = p_layer_mask; +} + +void RendererSceneRenderForwardClustered::geometry_instance_free(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (ginstance->lightmap_sh != nullptr) { + geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); + } + GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; + while (surf) { + GeometryInstanceSurfaceDataCache *next = surf->next; + geometry_instance_surface_alloc.free(surf); + surf = next; + } + memdelete(ginstance->data); + geometry_instance_alloc.free(ginstance); +} + +uint32_t RendererSceneRenderForwardClustered::geometry_instance_get_pair_mask() { + return (1 << RS::INSTANCE_GI_PROBE); +} +void RendererSceneRenderForwardClustered::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { +} +void RendererSceneRenderForwardClustered::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { +} +void RendererSceneRenderForwardClustered::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { +} + +Transform RendererSceneRenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) { + GeometryInstanceForward *ginstance = static_cast(p_instance); + ERR_FAIL_COND_V(!ginstance, Transform()); + return ginstance->transform; +} +AABB RendererSceneRenderForwardClustered::geometry_instance_get_aabb(GeometryInstance *p_instance) { + GeometryInstanceForward *ginstance = static_cast(p_instance); + ERR_FAIL_COND_V(!ginstance, AABB()); + return ginstance->data->aabb; +} + +void RendererSceneRenderForwardClustered::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (p_gi_probe_instance_count > 0) { + ginstance->gi_probes[0] = p_gi_probe_instances[0]; + } else { + ginstance->gi_probes[0] = RID(); + } + + if (p_gi_probe_instance_count > 1) { + ginstance->gi_probes[1] = p_gi_probe_instances[1]; + } else { + ginstance->gi_probes[1] = RID(); + } +} + +RendererSceneRenderForwardClustered::RendererSceneRenderForwardClustered(RendererStorageRD *p_storage) : + RendererSceneRenderRD(p_storage) { + singleton = this; + low_end = is_low_end(); + storage = p_storage; + + /* SCENE SHADER */ + + { + String defines; + if (low_end) { + defines += "\n#define LOW_END_MODE \n"; + } + + defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; + if (is_using_radiance_cubemap_array()) { + defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; + } + defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n"; + defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n"; + + { + //lightmaps + scene_state.max_lightmaps = low_end ? 2 : MAX_LIGHTMAPS; + defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n"; + defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n"; + + scene_state.lightmap_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapData) * scene_state.max_lightmaps); + } + { + //captures + scene_state.max_lightmap_captures = 2048; + scene_state.lightmap_captures = memnew_arr(LightmapCaptureData, scene_state.max_lightmap_captures); + scene_state.lightmap_capture_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapCaptureData) * scene_state.max_lightmap_captures); + } + { + defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n"; + } + + Vector shader_versions; + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n"); + shader_versions.push_back(""); + shader_versions.push_back("\n#define USE_FORWARD_GI\n"); + shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); + shader_versions.push_back("\n#define USE_LIGHTMAP\n"); + shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); + shader.scene_shader.initialize(shader_versions, defines); + + if (is_low_end()) { + //disable the high end versions + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); + } + } + + storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs); + storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs); + + { + //shader compiler + ShaderCompilerRD::DefaultIdentifierActions actions; + + actions.renames["WORLD_MATRIX"] = "world_matrix"; + actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix"; + actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix"; + actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix"; + actions.renames["PROJECTION_MATRIX"] = "projection_matrix"; + actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix"; + actions.renames["MODELVIEW_MATRIX"] = "modelview"; + actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal"; + + actions.renames["VERTEX"] = "vertex"; + actions.renames["NORMAL"] = "normal"; + actions.renames["TANGENT"] = "tangent"; + actions.renames["BINORMAL"] = "binormal"; + actions.renames["POSITION"] = "position"; + actions.renames["UV"] = "uv_interp"; + actions.renames["UV2"] = "uv2_interp"; + actions.renames["COLOR"] = "color_interp"; + actions.renames["POINT_SIZE"] = "gl_PointSize"; + actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; + + actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold"; + actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale"; + actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge"; + actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate"; + + //builtins + + actions.renames["TIME"] = "scene_data.time"; + actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size"; + + actions.renames["FRAGCOORD"] = "gl_FragCoord"; + actions.renames["FRONT_FACING"] = "gl_FrontFacing"; + actions.renames["NORMAL_MAP"] = "normal_map"; + actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; + actions.renames["ALBEDO"] = "albedo"; + actions.renames["ALPHA"] = "alpha"; + actions.renames["METALLIC"] = "metallic"; + actions.renames["SPECULAR"] = "specular"; + actions.renames["ROUGHNESS"] = "roughness"; + actions.renames["RIM"] = "rim"; + actions.renames["RIM_TINT"] = "rim_tint"; + actions.renames["CLEARCOAT"] = "clearcoat"; + actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; + actions.renames["ANISOTROPY"] = "anisotropy"; + actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; + actions.renames["SSS_STRENGTH"] = "sss_strength"; + actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color"; + actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth"; + actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve"; + actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost"; + actions.renames["BACKLIGHT"] = "backlight"; + actions.renames["AO"] = "ao"; + actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; + actions.renames["EMISSION"] = "emission"; + actions.renames["POINT_COORD"] = "gl_PointCoord"; + actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; + actions.renames["SCREEN_UV"] = "screen_uv"; + actions.renames["SCREEN_TEXTURE"] = "color_buffer"; + actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; + actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; + actions.renames["DEPTH"] = "gl_FragDepth"; + actions.renames["OUTPUT_IS_SRGB"] = "true"; + actions.renames["FOG"] = "custom_fog"; + actions.renames["RADIANCE"] = "custom_radiance"; + actions.renames["IRRADIANCE"] = "custom_irradiance"; + actions.renames["BONE_INDICES"] = "bone_attrib"; + actions.renames["BONE_WEIGHTS"] = "weight_attrib"; + actions.renames["CUSTOM0"] = "custom0_attrib"; + actions.renames["CUSTOM1"] = "custom1_attrib"; + actions.renames["CUSTOM2"] = "custom2_attrib"; + actions.renames["CUSTOM3"] = "custom3_attrib"; + + //for light + actions.renames["VIEW"] = "view"; + actions.renames["LIGHT_COLOR"] = "light_color"; + actions.renames["LIGHT"] = "light"; + actions.renames["ATTENUATION"] = "attenuation"; + actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation"; + actions.renames["DIFFUSE_LIGHT"] = "diffuse_light"; + actions.renames["SPECULAR_LIGHT"] = "specular_light"; + + actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; + actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n"; + actions.usage_defines["BINORMAL"] = "@TANGENT"; + actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n"; + actions.usage_defines["RIM_TINT"] = "@RIM"; + actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n"; + actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; + actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n"; + actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; + actions.usage_defines["AO"] = "#define AO_USED\n"; + actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n"; + actions.usage_defines["UV"] = "#define UV_USED\n"; + actions.usage_defines["UV2"] = "#define UV2_USED\n"; + actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n"; + actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n"; + actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n"; + actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n"; + actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n"; + actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n"; + actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; + actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; + actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; + actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; + actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; + + actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n"; + actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n"; + actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n"; + actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE"; + + actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; + actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; + actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; + actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; + actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; + + actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + + actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n"; + actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n"; + actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n"; + + actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; + actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; + actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; + actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; + + bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley"); + + if (!force_lambert) { + actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + } + + actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; + actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; + actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; + + actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; + + bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); + + if (!force_blinn) { + actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + } else { + actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; + } + + actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; + actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; + actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; + actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; + actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; + actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; + actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; + actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; + + actions.sampler_array_name = "material_samplers"; + actions.base_texture_binding_index = 1; + actions.texture_layout_set = MATERIAL_UNIFORM_SET; + actions.base_uniform_string = "material."; + actions.base_varying_index = 10; + + actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; + actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; + actions.global_buffer_array_variable = "global_variables.data"; + actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs"; + + shader.compiler.initialize(actions); + } + + { + //default material and shader + default_shader = storage->shader_allocate(); + storage->shader_initialize(default_shader); + storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n"); + default_material = storage->material_allocate(); + storage->material_initialize(default_material); + storage->material_set_shader(default_material, default_shader); + + MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); + if (!low_end) { + default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); + } + } + + { + overdraw_material_shader = storage->shader_allocate(); + storage->shader_initialize(overdraw_material_shader); + storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); + overdraw_material = storage->material_allocate(); + storage->material_initialize(overdraw_material); + storage->material_set_shader(overdraw_material, overdraw_material_shader); + + wireframe_material_shader = storage->shader_allocate(); + storage->shader_initialize(wireframe_material_shader); + storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }"); + wireframe_material = storage->material_allocate(); + storage->material_initialize(wireframe_material); + storage->material_set_shader(wireframe_material, wireframe_material_shader); + } + + { + default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256); + Vector uniforms; + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(default_vec4_xform_buffer); + u.binding = 0; + uniforms.push_back(u); + + default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, TRANSFORMS_UNIFORM_SET); + } + { + RD::SamplerState sampler; + sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler.enable_compare = true; + sampler.compare_op = RD::COMPARE_OP_LESS; + shadow_sampler = RD::get_singleton()->sampler_create(sampler); + } + + render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances"); +} + +RendererSceneRenderForwardClustered::~RendererSceneRenderForwardClustered() { + directional_shadow_atlas_set_size(0); + + //clear base uniform set if still valid + for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) { + if (render_pass_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[i])) { + RD::get_singleton()->free(render_pass_uniform_sets[i]); + } + } + + if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { + RD::get_singleton()->free(sdfgi_pass_uniform_set); + } + + RD::get_singleton()->free(default_vec4_xform_buffer); + RD::get_singleton()->free(shadow_sampler); + + storage->free(wireframe_material_shader); + storage->free(overdraw_material_shader); + storage->free(default_shader); + + storage->free(wireframe_material); + storage->free(overdraw_material); + storage->free(default_material); + + { + for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) { + RD::get_singleton()->free(scene_state.uniform_buffers[i]); + } + RD::get_singleton()->free(scene_state.lightmap_buffer); + RD::get_singleton()->free(scene_state.lightmap_capture_buffer); + for (uint32_t i = 0; i < RENDER_LIST_MAX; i++) { + if (scene_state.instance_buffer[i] != RID()) { + RD::get_singleton()->free(scene_state.instance_buffer[i]); + } + } + memdelete_arr(scene_state.lightmap_captures); + } + + while (sdfgi_framebuffer_size_cache.front()) { + RD::get_singleton()->free(sdfgi_framebuffer_size_cache.front()->get()); + sdfgi_framebuffer_size_cache.erase(sdfgi_framebuffer_size_cache.front()); + } +} diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h b/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h new file mode 100644 index 0000000000..96ab227c7c --- /dev/null +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h @@ -0,0 +1,771 @@ +/*************************************************************************/ +/* renderer_scene_render_forward_clustered.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H +#define RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H + +#include "core/templates/paged_allocator.h" +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h" + +class RendererSceneRenderForwardClustered : public RendererSceneRenderRD { + enum { + SCENE_UNIFORM_SET = 0, + RENDER_PASS_UNIFORM_SET = 1, + TRANSFORMS_UNIFORM_SET = 2, + MATERIAL_UNIFORM_SET = 3 + }; + + enum { + SDFGI_MAX_CASCADES = 8, + MAX_GI_PROBES = 8, + MAX_LIGHTMAPS = 8, + MAX_GI_PROBES_PER_INSTANCE = 2, + INSTANCE_DATA_BUFFER_MIN_SIZE = 4096 + }; + + enum RenderListType { + RENDER_LIST_OPAQUE, //used for opaque objects + RENDER_LIST_ALPHA, //used for transparent objects + RENDER_LIST_SECONDARY, //used for shadows and other objects + RENDER_LIST_MAX + + }; + + /* Scene Shader */ + + enum ShaderVersion { + SHADER_VERSION_DEPTH_PASS, + SHADER_VERSION_DEPTH_PASS_DP, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, + SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, + SHADER_VERSION_DEPTH_PASS_WITH_SDF, + SHADER_VERSION_COLOR_PASS, + SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, + SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_LIGHTMAP_COLOR_PASS, + SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_MAX + }; + + struct { + SceneForwardClusteredShaderRD scene_shader; + ShaderCompilerRD compiler; + } shader; + + RendererStorageRD *storage; + + /* Material */ + + struct ShaderData : public RendererStorageRD::ShaderData { + enum BlendMode { //used internally + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + BLEND_MODE_ALPHA_TO_COVERAGE + }; + + enum DepthDraw { + DEPTH_DRAW_DISABLED, + DEPTH_DRAW_OPAQUE, + DEPTH_DRAW_ALWAYS + }; + + enum DepthTest { + DEPTH_TEST_DISABLED, + DEPTH_TEST_ENABLED + }; + + enum Cull { + CULL_DISABLED, + CULL_FRONT, + CULL_BACK + }; + + enum CullVariant { + CULL_VARIANT_NORMAL, + CULL_VARIANT_REVERSED, + CULL_VARIANT_DOUBLE_SIDED, + CULL_VARIANT_MAX + + }; + + enum AlphaAntiAliasing { + ALPHA_ANTIALIASING_OFF, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE + }; + + bool valid; + RID version; + uint32_t vertex_input_mask; + PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; + + String path; + + Map uniforms; + Vector texture_uniforms; + + Vector ubo_offsets; + uint32_t ubo_size; + + String code; + Map default_texture_params; + + DepthDraw depth_draw; + DepthTest depth_test; + + bool uses_point_size; + bool uses_alpha; + bool uses_blend_alpha; + bool uses_alpha_clip; + bool uses_depth_pre_pass; + bool uses_discard; + bool uses_roughness; + bool uses_normal; + + bool unshaded; + bool uses_vertex; + bool uses_sss; + bool uses_transmittance; + bool uses_screen_texture; + bool uses_depth_texture; + bool uses_normal_texture; + bool uses_time; + bool writes_modelview_or_projection; + bool uses_world_coordinates; + + uint64_t last_pass = 0; + uint32_t index = 0; + + virtual void set_code(const String &p_Code); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void get_param_list(List *p_param_list) const; + void get_instance_param_list(List *p_param_list) const; + + virtual bool is_param_texture(const StringName &p_param) const; + virtual bool is_animated() const; + virtual bool casts_shadows() const; + virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + + ShaderData(); + virtual ~ShaderData(); + }; + + RendererStorageRD::ShaderData *_create_shader_func(); + static RendererStorageRD::ShaderData *_create_shader_funcs() { + return static_cast(singleton)->_create_shader_func(); + } + + struct MaterialData : public RendererStorageRD::MaterialData { + uint64_t last_frame; + ShaderData *shader_data; + RID uniform_buffer; + RID uniform_set; + Vector texture_cache; + Vector ubo_data; + uint64_t last_pass = 0; + uint32_t index = 0; + RID next_pass; + uint8_t priority; + virtual void set_render_priority(int p_priority); + virtual void set_next_pass(RID p_pass); + virtual void update_parameters(const Map &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual ~MaterialData(); + }; + + RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); + static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) { + return static_cast(singleton)->_create_material_func(static_cast(p_shader)); + } + + /* Framebuffer */ + + struct RenderBufferDataForward : public RenderBufferData { + //for rendering, may be MSAAd + + RID color; + RID depth; + RID specular; + RID normal_roughness_buffer; + RID giprobe_buffer; + + RS::ViewportMSAA msaa; + RD::TextureSamples texture_samples; + + RID color_msaa; + RID depth_msaa; + RID specular_msaa; + RID normal_roughness_buffer_msaa; + RID roughness_buffer_msaa; + RID giprobe_buffer_msaa; + + RID depth_fb; + RID depth_normal_roughness_fb; + RID depth_normal_roughness_giprobe_fb; + RID color_fb; + RID color_specular_fb; + RID specular_only_fb; + int width, height; + + RID render_sdfgi_uniform_set; + void ensure_specular(); + void ensure_giprobe(); + void clear(); + virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); + + ~RenderBufferDataForward(); + }; + + virtual RenderBufferData *_create_render_buffer_data(); + void _allocate_normal_roughness_texture(RenderBufferDataForward *rb); + + RID shadow_sampler; + RID render_base_uniform_set; + LocalVector render_pass_uniform_sets; + RID sdfgi_pass_uniform_set; + + uint64_t lightmap_texture_array_version = 0xFFFFFFFF; + + virtual void _base_uniforms_changed(); + void _render_buffers_clear_uniform_set(RenderBufferDataForward *rb); + virtual void _render_buffers_uniform_set_changed(RID p_render_buffers); + virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); + + void _update_render_base_uniform_set(); + RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); + RID _setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray &p_gi_probes, const PagedArray &p_lightmaps, bool p_use_directional_shadow_atlas = false, int p_index = 0); + + enum PassMode { + PASS_MODE_COLOR, + PASS_MODE_COLOR_SPECULAR, + PASS_MODE_COLOR_TRANSPARENT, + PASS_MODE_SHADOW, + PASS_MODE_SHADOW_DP, + PASS_MODE_DEPTH, + PASS_MODE_DEPTH_NORMAL_ROUGHNESS, + PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE, + PASS_MODE_DEPTH_MATERIAL, + PASS_MODE_SDF, + }; + + struct GeometryInstanceSurfaceDataCache; + struct RenderElementInfo; + + struct RenderListParameters { + GeometryInstanceSurfaceDataCache **elements = nullptr; + RenderElementInfo *element_info = nullptr; + int element_count = 0; + bool reverse_cull = false; + PassMode pass_mode = PASS_MODE_COLOR; + bool no_gi = false; + RID render_pass_uniform_set; + bool force_wireframe = false; + Vector2 uv_offset; + Plane lod_plane; + float lod_distance_multiplier = 0.0; + float screen_lod_threshold = 0.0; + RD::FramebufferFormatID framebuffer_format = 0; + uint32_t element_offset = 0; + uint32_t barrier = RD::BARRIER_MASK_ALL; + + RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) { + elements = p_elements; + element_info = p_element_info; + element_count = p_element_count; + reverse_cull = p_reverse_cull; + pass_mode = p_pass_mode; + no_gi = p_no_gi; + render_pass_uniform_set = p_render_pass_uniform_set; + force_wireframe = p_force_wireframe; + uv_offset = p_uv_offset; + lod_plane = p_lod_plane; + lod_distance_multiplier = p_lod_distance_multiplier; + screen_lod_threshold = p_screen_lod_threshold; + element_offset = p_element_offset; + barrier = p_barrier; + } + }; + + struct LightmapData { + float normal_xform[12]; + }; + + struct LightmapCaptureData { + float sh[9 * 4]; + }; + + enum { + INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, + INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, + INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, + INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, + INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, + INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11, + INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, + INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, + INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, + INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, + INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16, + INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7, + INSTANCE_DATA_FLAG_SKELETON = 1 << 19, + }; + + struct SceneState { + struct UBO { + float projection_matrix[16]; + float inv_projection_matrix[16]; + + float camera_matrix[16]; + float inv_camera_matrix[16]; + + float viewport_size[2]; + float screen_pixel_size[2]; + + uint32_t cluster_shift; + uint32_t cluster_width; + uint32_t cluster_type_size; + uint32_t max_cluster_element_count_div_32; + + float directional_penumbra_shadow_kernel[128]; //32 vec4s + float directional_soft_shadow_kernel[128]; + float penumbra_shadow_kernel[128]; + float soft_shadow_kernel[128]; + + uint32_t directional_penumbra_shadow_samples; + uint32_t directional_soft_shadow_samples; + uint32_t penumbra_shadow_samples; + uint32_t soft_shadow_samples; + + float ambient_light_color_energy[4]; + + float ambient_color_sky_mix; + uint32_t use_ambient_light; + uint32_t use_ambient_cubemap; + uint32_t use_reflection_cubemap; + + float radiance_inverse_xform[12]; + + float shadow_atlas_pixel_size[2]; + float directional_shadow_pixel_size[2]; + + uint32_t directional_light_count; + float dual_paraboloid_side; + float z_far; + float z_near; + + uint32_t ssao_enabled; + float ssao_light_affect; + float ssao_ao_affect; + uint32_t roughness_limiter_enabled; + + float roughness_limiter_amount; + float roughness_limiter_limit; + uint32_t roughness_limiter_pad[2]; + + float ao_color[4]; + + float sdf_to_bounds[16]; + + int32_t sdf_offset[3]; + uint32_t material_uv2_mode; + + int32_t sdf_size[3]; + uint32_t gi_upscale_for_msaa; + + uint32_t volumetric_fog_enabled; + float volumetric_fog_inv_length; + float volumetric_fog_detail_spread; + uint32_t volumetric_fog_pad; + + // Fog + uint32_t fog_enabled; + float fog_density; + float fog_height; + float fog_height_density; + + float fog_light_color[3]; + float fog_sun_scatter; + + float fog_aerial_perspective; + + float time; + float reflection_multiplier; + + uint32_t pancake_shadows; + }; + + struct PushConstant { + uint32_t base_index; // + uint32_t uv_offset; //packed + uint32_t pad[2]; + }; + + struct InstanceData { + float transform[16]; + uint32_t flags; + uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables + uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index) + uint32_t layer_mask; + float lightmap_uv_scale[4]; + }; + + UBO ubo; + + LocalVector uniform_buffers; + + LightmapData lightmaps[MAX_LIGHTMAPS]; + RID lightmap_ids[MAX_LIGHTMAPS]; + bool lightmap_has_sh[MAX_LIGHTMAPS]; + uint32_t lightmaps_used = 0; + uint32_t max_lightmaps; + RID lightmap_buffer; + + RID instance_buffer[RENDER_LIST_MAX]; + uint32_t instance_buffer_size[RENDER_LIST_MAX] = { 0, 0, 0 }; + LocalVector instance_data[RENDER_LIST_MAX]; + + LightmapCaptureData *lightmap_captures; + uint32_t max_lightmap_captures; + RID lightmap_capture_buffer; + + RID giprobe_ids[MAX_GI_PROBES]; + uint32_t giprobes_used = 0; + + bool used_screen_texture = false; + bool used_normal_texture = false; + bool used_depth_texture = false; + bool used_sss = false; + + struct ShadowPass { + uint32_t element_from; + uint32_t element_count; + bool flip_cull; + PassMode pass_mode; + + RID rp_uniform_set; + Plane camera_plane; + float lod_distance_multiplier; + float screen_lod_threshold; + + RID framebuffer; + RD::InitialAction initial_depth_action; + RD::FinalAction final_depth_action; + Rect2i rect; + }; + + LocalVector shadow_passes; + + } scene_state; + + static RendererSceneRenderForwardClustered *singleton; + + double time; + RID default_shader; + RID default_material; + RID overdraw_material_shader; + RID overdraw_material; + RID wireframe_material_shader; + RID wireframe_material; + RID default_shader_rd; + RID default_shader_sdfgi_rd; + + RID default_vec4_xform_buffer; + RID default_vec4_xform_uniform_set; + + void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0); + void _setup_giprobes(const PagedArray &p_giprobes); + void _setup_lightmaps(const PagedArray &p_lightmaps, const Transform &p_cam_transform); + + struct RenderElementInfo { + uint32_t repeat : 22; + uint32_t uses_lightmap : 1; + uint32_t uses_forward_gi : 1; + uint32_t lod_index : 8; + }; + + template + _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); + + void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); + + LocalVector thread_draw_lists; + void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params); + void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); + + uint32_t render_list_thread_threshold = 500; + + void _update_instance_data_buffer(RenderListType p_render_list); + void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); + void _fill_render_list(RenderListType p_render_list, const PagedArray &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, const Plane &p_lod_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, bool p_append = false); + + Map sdfgi_framebuffer_size_cache; + + struct GeometryInstanceData; + struct GeometryInstanceForward; + + struct GeometryInstanceLightmapSH { + Color sh[9]; + }; + + // Cached data for drawing surfaces + struct GeometryInstanceSurfaceDataCache { + enum { + FLAG_PASS_DEPTH = 1, + FLAG_PASS_OPAQUE = 2, + FLAG_PASS_ALPHA = 4, + FLAG_PASS_SHADOW = 8, + FLAG_USES_SHARED_SHADOW_MATERIAL = 128, + FLAG_USES_SUBSURFACE_SCATTERING = 2048, + FLAG_USES_SCREEN_TEXTURE = 4096, + FLAG_USES_DEPTH_TEXTURE = 8192, + FLAG_USES_NORMAL_TEXTURE = 16384, + FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768, + }; + + union { + struct { + uint64_t lod_index : 8; + uint64_t surface_index : 10; + uint64_t geometry_id : 32; + uint64_t material_id_low : 14; + + uint64_t material_id_hi : 18; + uint64_t shader_id : 32; + uint64_t uses_forward_gi : 1; + uint64_t uses_lightmap : 1; + uint64_t depth_layer : 4; + uint64_t priority : 8; + }; + struct { + uint64_t sort_key1; + uint64_t sort_key2; + }; + } sort; + + RS::PrimitiveType primitive = RS::PRIMITIVE_MAX; + uint32_t flags = 0; + uint32_t surface_index = 0; + + void *surface = nullptr; + RID material_uniform_set; + ShaderData *shader = nullptr; + + void *surface_shadow = nullptr; + RID material_uniform_set_shadow; + ShaderData *shader_shadow = nullptr; + + GeometryInstanceSurfaceDataCache *next = nullptr; + GeometryInstanceForward *owner = nullptr; + }; + + struct GeometryInstanceForward : public GeometryInstance { + //used during rendering + bool mirror = false; + bool non_uniform_scale = false; + float lod_bias = 0.0; + float lod_model_scale = 1.0; + AABB transformed_aabb; //needed for LOD + float depth = 0; + uint32_t gi_offset_cache = 0; + uint32_t flags_cache = 0; + bool store_transform_cache = true; + int32_t shader_parameters_offset = -1; + uint32_t lightmap_slice_index; + Rect2 lightmap_uv_scale; + uint32_t layer_mask = 1; + RID transforms_uniform_set; + uint32_t instance_count = 0; + RID mesh_instance; + bool can_sdfgi = false; + //used during setup + uint32_t base_flags = 0; + Transform transform; + RID gi_probes[MAX_GI_PROBES_PER_INSTANCE]; + RID lightmap_instance; + GeometryInstanceLightmapSH *lightmap_sh = nullptr; + GeometryInstanceSurfaceDataCache *surface_caches = nullptr; + SelfList dirty_list_element; + + struct Data { + //data used less often goes into regular heap + RID base; + RS::InstanceType base_type; + + RID skeleton; + Vector surface_materials; + RID material_override; + AABB aabb; + + bool use_dynamic_gi = false; + bool use_baked_light = false; + bool cast_double_sided_shaodows = false; + bool mirror = false; + bool dirty_dependencies = false; + + RendererStorage::DependencyTracker dependency_tracker; + }; + + Data *data = nullptr; + + GeometryInstanceForward() : + dirty_list_element(this) {} + }; + + static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker); + static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker); + + SelfList::List geometry_instance_dirty_list; + + PagedAllocator geometry_instance_alloc; + PagedAllocator geometry_instance_surface_alloc; + PagedAllocator geometry_instance_lightmap_sh; + + void _geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh); + void _geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh); + void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance); + void _geometry_instance_update(GeometryInstance *p_geometry_instance); + void _update_dirty_geometry_instances(); + + bool low_end = false; + + /* Render List */ + + struct RenderList { + LocalVector elements; + LocalVector element_info; + + void clear() { + elements.clear(); + element_info.clear(); + } + + //should eventually be replaced by radix + + struct SortByKey { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2); + } + }; + + void sort_by_key() { + SortArray sorter; + sorter.sort(elements.ptr(), elements.size()); + } + + void sort_by_key_range(uint32_t p_from, uint32_t p_size) { + SortArray sorter; + sorter.sort(elements.ptr() + p_from, p_size); + } + + struct SortByDepth { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->owner->depth < B->owner->depth); + } + }; + + void sort_by_depth() { //used for shadows + + SortArray sorter; + sorter.sort(elements.ptr(), elements.size()); + } + + struct SortByReverseDepthAndPriority { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority); + } + }; + + void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha + + SortArray sorter; + sorter.sort(elements.ptr(), elements.size()); + } + + _FORCE_INLINE_ void add_element(GeometryInstanceSurfaceDataCache *p_element) { + elements.push_back(p_element); + } + }; + + RenderList render_list[RENDER_LIST_MAX]; + +protected: + virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, const PagedArray &p_gi_probes, const PagedArray &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_lod_threshold); + + virtual void _render_shadow_begin(); + virtual void _render_shadow_append(RID p_framebuffer, const PagedArray &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true); + virtual void _render_shadow_process(); + virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL); + + virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region); + virtual void _render_uv2(const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region); + virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray &p_instances); + +public: + virtual GeometryInstance *geometry_instance_create(RID p_base); + virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton); + virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override); + virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_materials); + virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance); + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb); + virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask); + virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias); + virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable); + virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable); + virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index); + virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9); + virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset); + virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable); + + virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance); + virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance); + + virtual void geometry_instance_free(GeometryInstance *p_geometry_instance); + + virtual uint32_t geometry_instance_get_pair_mask(); + virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count); + virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count); + virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count); + virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count); + + virtual void set_time(double p_time, double p_step); + + virtual bool free(RID p_rid); + + RendererSceneRenderForwardClustered(RendererStorageRD *p_storage); + ~RendererSceneRenderForwardClustered(); +}; +#endif // !RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub index c192574ff2..0f85e3fa30 100644 --- a/servers/rendering/renderer_rd/shaders/SCsub +++ b/servers/rendering/renderer_rd/shaders/SCsub @@ -11,7 +11,7 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("cubemap_roughness.glsl") env.RD_GLSL("cubemap_downsampler.glsl") env.RD_GLSL("cubemap_filter.glsl") - env.RD_GLSL("scene_forward.glsl") + env.RD_GLSL("scene_forward_clustered.glsl") env.RD_GLSL("sky.glsl") env.RD_GLSL("tonemap.glsl") env.RD_GLSL("cube_to_dp.glsl") diff --git a/servers/rendering/renderer_rd/shaders/scene_forward.glsl b/servers/rendering/renderer_rd/shaders/scene_forward.glsl deleted file mode 100644 index 1cea9bf8db..0000000000 --- a/servers/rendering/renderer_rd/shaders/scene_forward.glsl +++ /dev/null @@ -1,3293 +0,0 @@ -#[vertex] - -#version 450 - -VERSION_DEFINES - -#include "scene_forward_inc.glsl" - -/* INPUT ATTRIBS */ - -layout(location = 0) in vec3 vertex_attrib; - -//only for pure render depth when normal is not used - -#ifdef NORMAL_USED -layout(location = 1) in vec3 normal_attrib; -#endif - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -layout(location = 2) in vec4 tangent_attrib; -#endif - -#if defined(COLOR_USED) -layout(location = 3) in vec4 color_attrib; -#endif - -#ifdef UV_USED -layout(location = 4) in vec2 uv_attrib; -#endif - -#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL) -layout(location = 5) in vec2 uv2_attrib; -#endif - -#if defined(CUSTOM0_USED) -layout(location = 6) in vec4 custom0_attrib; -#endif - -#if defined(CUSTOM1_USED) -layout(location = 7) in vec4 custom1_attrib; -#endif - -#if defined(CUSTOM2_USED) -layout(location = 8) in vec4 custom2_attrib; -#endif - -#if defined(CUSTOM3_USED) -layout(location = 9) in vec4 custom3_attrib; -#endif - -#if defined(BONES_USED) -layout(location = 10) in uvec4 bone_attrib; -#endif - -#if defined(WEIGHTS_USED) -layout(location = 11) in vec4 weight_attrib; -#endif - -/* Varyings */ - -layout(location = 0) out vec3 vertex_interp; - -#ifdef NORMAL_USED -layout(location = 1) out vec3 normal_interp; -#endif - -#if defined(COLOR_USED) -layout(location = 2) out vec4 color_interp; -#endif - -#ifdef UV_USED -layout(location = 3) out vec2 uv_interp; -#endif - -#if defined(UV2_USED) || defined(USE_LIGHTMAP) -layout(location = 4) out vec2 uv2_interp; -#endif - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -layout(location = 5) out vec3 tangent_interp; -layout(location = 6) out vec3 binormal_interp; -#endif - -#ifdef USE_MATERIAL_UNIFORMS -layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ - /* clang-format off */ -MATERIAL_UNIFORMS - /* clang-format on */ -} material; -#endif - -invariant gl_Position; - -#ifdef MODE_DUAL_PARABOLOID - -layout(location = 8) out float dp_clip; - -#endif - -layout(location = 9) out flat uint instance_index; - -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -void main() { - vec4 instance_custom = vec4(0.0); -#if defined(COLOR_USED) - color_interp = color_attrib; -#endif - - instance_index = draw_call.instance_index; - - bool is_multimesh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH); - if (!is_multimesh) { - instance_index += gl_InstanceIndex; - } - - mat4 world_matrix = instances.data[instance_index].transform; - - mat3 world_normal_matrix; - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { - world_normal_matrix = inverse(mat3(world_matrix)); - } else { - world_normal_matrix = mat3(world_matrix); - } - - if (is_multimesh) { - //multimesh, instances are for it - uint offset = (instances.data[instance_index].flags >> INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT) & INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK; - offset *= gl_InstanceIndex; - - mat4 matrix; - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { - matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); - offset += 2; - } else { - matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], transforms.data[offset + 2], vec4(0.0, 0.0, 0.0, 1.0)); - offset += 3; - } - - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { -#ifdef COLOR_USED - color_interp *= transforms.data[offset]; -#endif - offset += 1; - } - - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { - instance_custom = transforms.data[offset]; - } - - //transpose - matrix = transpose(matrix); - world_matrix = world_matrix * matrix; - world_normal_matrix = world_normal_matrix * mat3(matrix); - } - - vec3 vertex = vertex_attrib; -#ifdef NORMAL_USED - vec3 normal = normal_attrib * 2.0 - 1.0; -#endif - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; - float binormalf = tangent_attrib.a * 2.0 - 1.0; - vec3 binormal = normalize(cross(normal, tangent) * binormalf); -#endif - -#if 0 - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) { - //multimesh, instances are for it - - uvec2 bones_01 = uvec2(bone_attrib.x & 0xFFFF, bone_attrib.x >> 16) * 3; - uvec2 bones_23 = uvec2(bone_attrib.y & 0xFFFF, bone_attrib.y >> 16) * 3; - vec2 weights_01 = unpackUnorm2x16(bone_attrib.z); - vec2 weights_23 = unpackUnorm2x16(bone_attrib.w); - - mat4 m = mat4(transforms.data[bones_01.x], transforms.data[bones_01.x + 1], transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x; - m += mat4(transforms.data[bones_01.y], transforms.data[bones_01.y + 1], transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y; - m += mat4(transforms.data[bones_23.x], transforms.data[bones_23.x + 1], transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; - m += mat4(transforms.data[bones_23.y], transforms.data[bones_23.y + 1], transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; - - //reverse order because its transposed - vertex = (vec4(vertex, 1.0) * m).xyz; - normal = (vec4(normal, 0.0) * m).xyz; - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - - tangent = (vec4(tangent, 0.0) * m).xyz; - binormal = (vec4(binormal, 0.0) * m).xyz; -#endif - } -#endif - -#ifdef UV_USED - uv_interp = uv_attrib; -#endif - -#if defined(UV2_USED) || defined(USE_LIGHTMAP) - uv2_interp = uv2_attrib; -#endif - -#ifdef OVERRIDE_POSITION - vec4 position; -#endif - - mat4 projection_matrix = scene_data.projection_matrix; - -//using world coordinates -#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - - vertex = (world_matrix * vec4(vertex, 1.0)).xyz; - - normal = world_normal_matrix * normal; - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - - tangent = world_normal_matrix * tangent; - binormal = world_normal_matrix * binormal; - -#endif -#endif - - float roughness = 1.0; - - mat4 modelview = scene_data.inv_camera_matrix * world_matrix; - mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * world_normal_matrix; - - { - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ - } - -// using local coordinates (default) -#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED) - - vertex = (modelview * vec4(vertex, 1.0)).xyz; -#ifdef NORMAL_USED - normal = modelview_normal * normal; -#endif - -#endif - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - - binormal = modelview_normal * binormal; - tangent = modelview_normal * tangent; -#endif - -//using world coordinates -#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - - vertex = (scene_data.inv_camera_matrix * vec4(vertex, 1.0)).xyz; - normal = mat3(scene_data.inverse_normal_matrix) * normal; - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - - binormal = mat3(scene_data.camera_inverse_binormal_matrix) * binormal; - tangent = mat3(scene_data.camera_inverse_tangent_matrix) * tangent; -#endif -#endif - - vertex_interp = vertex; -#ifdef NORMAL_USED - normal_interp = normal; -#endif - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - tangent_interp = tangent; - binormal_interp = binormal; -#endif - -#ifdef MODE_RENDER_DEPTH - -#ifdef MODE_DUAL_PARABOLOID - - vertex_interp.z *= scene_data.dual_paraboloid_side; - - dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias - - //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges - - vec3 vtx = vertex_interp; - float distance = length(vtx); - vtx = normalize(vtx); - vtx.xy /= 1.0 - vtx.z; - vtx.z = (distance / scene_data.z_far); - vtx.z = vtx.z * 2.0 - 1.0; - vertex_interp = vtx; - -#endif - -#endif //MODE_RENDER_DEPTH - -#ifdef OVERRIDE_POSITION - gl_Position = position; -#else - gl_Position = projection_matrix * vec4(vertex_interp, 1.0); -#endif - -#ifdef MODE_RENDER_DEPTH - if (scene_data.pancake_shadows) { - if (gl_Position.z <= 0.00001) { - gl_Position.z = 0.00001; - } - } -#endif -#ifdef MODE_RENDER_MATERIAL - if (scene_data.material_uv2_mode) { - vec2 uv_offset = unpackHalf2x16(draw_call.uv_offset); - gl_Position.xy = (uv2_attrib.xy + uv_offset) * 2.0 - 1.0; - gl_Position.z = 0.00001; - gl_Position.w = 1.0; - } -#endif -} - -#[fragment] - -#version 450 - -VERSION_DEFINES - -#include "scene_forward_inc.glsl" - -/* Varyings */ - -layout(location = 0) in vec3 vertex_interp; - -#ifdef NORMAL_USED -layout(location = 1) in vec3 normal_interp; -#endif - -#if defined(COLOR_USED) -layout(location = 2) in vec4 color_interp; -#endif - -#ifdef UV_USED -layout(location = 3) in vec2 uv_interp; -#endif - -#if defined(UV2_USED) || defined(USE_LIGHTMAP) -layout(location = 4) in vec2 uv2_interp; -#endif - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -layout(location = 5) in vec3 tangent_interp; -layout(location = 6) in vec3 binormal_interp; -#endif - -#ifdef MODE_DUAL_PARABOLOID - -layout(location = 8) in float dp_clip; - -#endif - -layout(location = 9) in flat uint instance_index; - -//defines to keep compatibility with vertex - -#define world_matrix instances.data[instance_index].transform -#define projection_matrix scene_data.projection_matrix - -#if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE) -//both required for transmittance to be enabled -#define LIGHT_TRANSMITTANCE_USED -#endif - -#ifdef USE_MATERIAL_UNIFORMS -layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ - /* clang-format off */ -MATERIAL_UNIFORMS - /* clang-format on */ -} material; -#endif - -/* clang-format off */ - -FRAGMENT_SHADER_GLOBALS - -/* clang-format on */ - -#ifdef MODE_RENDER_DEPTH - -#ifdef MODE_RENDER_MATERIAL - -layout(location = 0) out vec4 albedo_output_buffer; -layout(location = 1) out vec4 normal_output_buffer; -layout(location = 2) out vec4 orm_output_buffer; -layout(location = 3) out vec4 emission_output_buffer; -layout(location = 4) out float depth_output_buffer; - -#endif - -#ifdef MODE_RENDER_NORMAL_ROUGHNESS -layout(location = 0) out vec4 normal_roughness_output_buffer; - -#ifdef MODE_RENDER_GIPROBE -layout(location = 1) out uvec2 giprobe_buffer; -#endif - -#endif //MODE_RENDER_NORMAL -#else // RENDER DEPTH - -#ifdef MODE_MULTIPLE_RENDER_TARGETS - -layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness -layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter) -#else - -layout(location = 0) out vec4 frag_color; -#endif - -#endif // RENDER DEPTH - -#ifdef ALPHA_HASH_USED - -float hash_2d(vec2 p) { - return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) * - (0.1 + abs(sin(13.0 * p.y + p.x)))); -} - -float hash_3d(vec3 p) { - return hash_2d(vec2(hash_2d(p.xy), p.z)); -} - -float compute_alpha_hash_threshold(vec3 pos, float hash_scale) { - vec3 dx = dFdx(pos); - vec3 dy = dFdx(pos); - float delta_max_sqr = max(length(dx), length(dy)); - float pix_scale = 1.0 / (hash_scale * delta_max_sqr); - - vec2 pix_scales = - vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale)))); - - vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)), - hash_3d(floor(pix_scales.y * pos.xyz))); - - float lerp_factor = fract(log2(pix_scale)); - - float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y; - - float min_lerp = min(lerp_factor, 1.0 - lerp_factor); - - vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)), - (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp), - 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / - (2.0 * min_lerp * (1.0 - min_lerp)))); - - float alpha_hash_threshold = - (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z; - - return clamp(alpha_hash_threshold, 0.0, 1.0); -} - -#endif // ALPHA_HASH_USED - -#ifdef ALPHA_ANTIALIASING_EDGE_USED - -float calc_mip_level(vec2 texture_coord) { - vec2 dx = dFdx(texture_coord); - vec2 dy = dFdy(texture_coord); - float delta_max_sqr = max(dot(dx, dx), dot(dy, dy)); - return max(0.0, 0.5 * log2(delta_max_sqr)); -} - -float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) { - input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number - input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5; - return clamp(input_alpha, 0.0, 1.0); -} - -#endif // ALPHA_ANTIALIASING_USED - -// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. -// We're dividing this factor off because the overall term we'll end up looks like -// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): -// -// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) -// -// We're basically regouping this as -// -// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] -// -// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. -// -// The contents of the D and G (G1) functions (GGX) are taken from -// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). -// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). - -#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - -float G_GGX_2cos(float cos_theta_m, float alpha) { - // Schlick's approximation - // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) - // Eq. (19), although see Heitz (2014) the about the problems with his derivation. - // It nevertheless approximates GGX well with k = alpha/2. - float k = 0.5 * alpha; - return 0.5 / (cos_theta_m * (1.0 - k) + k); - - // float cos2 = cos_theta_m * cos_theta_m; - // float sin2 = (1.0 - cos2); - // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); -} - -float D_GGX(float cos_theta_m, float alpha) { - float alpha2 = alpha * alpha; - float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; - return alpha2 / (M_PI * d * d); -} - -float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float s_x = alpha_x * cos_phi; - float s_y = alpha_y * sin_phi; - return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); -} - -float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float r_x = cos_phi / alpha_x; - float r_y = sin_phi / alpha_y; - float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); - return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); -} - -float SchlickFresnel(float u) { - float m = 1.0 - u; - float m2 = m * m; - return m2 * m2 * m; // pow(m,5) -} - -float GTR1(float NdotH, float a) { - if (a >= 1.0) - return 1.0 / M_PI; - float a2 = a * a; - float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; - return (a2 - 1.0) / (M_PI * log(a2) * t); -} - -vec3 F0(float metallic, float specular, vec3 albedo) { - float dielectric = 0.16 * specular * specular; - // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; - // see https://google.github.io/filament/Filament.md.html - return mix(vec3(dielectric), albedo, vec3(metallic)); -} - -void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_curve, - float transmittance_boost, - float transmittance_z, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, vec3 rim_color, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 B, vec3 T, float anisotropy, -#endif -#ifdef USE_SOFT_SHADOWS - float A, -#endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif - inout vec3 diffuse_light, inout vec3 specular_light) { - -#if defined(USE_LIGHT_SHADER_CODE) - // light is written by the light shader - - vec3 normal = N; - vec3 light = L; - vec3 view = V; - - /* clang-format off */ - -LIGHT_SHADER_CODE - - /* clang-format on */ - -#else - -#ifdef USE_SOFT_SHADOWS - float NdotL = min(A + dot(N, L), 1.0); -#else - float NdotL = dot(N, L); -#endif - float cNdotL = max(NdotL, 0.0); // clamped NdotL - float NdotV = dot(N, V); - float cNdotV = max(NdotV, 0.0); - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - vec3 H = normalize(V + L); -#endif - -#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) -#ifdef USE_SOFT_SHADOWS - float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); -#else - float cNdotH = clamp(dot(N, H), 0.0, 1.0); -#endif -#endif - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) -#ifdef USE_SOFT_SHADOWS - float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); -#else - float cLdotH = clamp(dot(L, H), 0.0, 1.0); -#endif -#endif - - float metallic = unpackUnorm4x8(orms).z; - if (metallic < 1.0) { - float roughness = unpackUnorm4x8(orms).y; - -#if defined(DIFFUSE_OREN_NAYAR) - vec3 diffuse_brdf_NL; -#else - float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance -#endif - -#if defined(DIFFUSE_LAMBERT_WRAP) - // energy conserving lambert wrap shader - diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); -#elif defined(DIFFUSE_TOON) - - diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); - -#elif defined(DIFFUSE_BURLEY) - - { - float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; - float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); - float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); - diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; - /* - float energyBias = mix(roughness, 0.0, 0.5); - float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); - float fd90 = energyBias + 2.0 * VoH * VoH * roughness; - float f0 = 1.0; - float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); - float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); - - diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; - */ - } -#else - // lambert - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); -#endif - - diffuse_light += light_color * diffuse_brdf_NL * attenuation; - -#if defined(LIGHT_BACKLIGHT_USED) - diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; -#endif - -#if defined(LIGHT_RIM_USED) - float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); - diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color; -#endif - -#ifdef LIGHT_TRANSMITTANCE_USED - -#ifdef SSS_MODE_SKIN - - { - float scale = 8.25 / transmittance_depth; - float d = scale * abs(transmittance_z); - float dd = -d * d; - vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + - vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + - vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + - vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + - vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + - vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); - - diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); - } -#else - - if (transmittance_depth > 0.0) { - float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0); - - fade = pow(max(0.0, 1.0 - fade), transmittance_curve); - fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0); - - diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade; - } - -#endif //SSS_MODE_SKIN - -#endif //LIGHT_TRANSMITTANCE_USED - } - - float roughness = unpackUnorm4x8(orms).y; - if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely - - // D - -#if defined(SPECULAR_BLINN) - - //normalized blinn - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess) * cNdotL; - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - float intensity = blinn; - - specular_light += light_color * intensity * attenuation * specular_amount; - -#elif defined(SPECULAR_PHONG) - - vec3 R = normalize(-reflect(L, N)); - float cRdotV = clamp(A + dot(R, V), 0.0, 1.0); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float phong = pow(cRdotV, shininess); - phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); - - specular_light += light_color * intensity * attenuation * specular_amount; - -#elif defined(SPECULAR_TOON) - - vec3 R = normalize(-reflect(L, N)); - float RdotV = dot(R, V); - float mid = 1.0 - roughness; - mid *= mid; - float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; - diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection - -#elif defined(SPECULAR_DISABLED) - // none.. - -#elif defined(SPECULAR_SCHLICK_GGX) - // shlick+ggx as default - -#if defined(LIGHT_ANISOTROPY_USED) - - float alpha_ggx = roughness * roughness; - float aspect = sqrt(1.0 - anisotropy * 0.9); - float ax = alpha_ggx / aspect; - float ay = alpha_ggx * aspect; - float XdotH = dot(T, H); - float YdotH = dot(B, H); - float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); - float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); - -#else - float alpha_ggx = roughness * roughness; - float D = D_GGX(cNdotH, alpha_ggx); - float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); -#endif - // F - float cLdotH5 = SchlickFresnel(cLdotH); - vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); - - vec3 specular_brdf_NL = cNdotL * D * F * G; - - specular_light += specular_brdf_NL * light_color * attenuation * specular_amount; -#endif - -#if defined(LIGHT_CLEARCOAT_USED) - -#if !defined(SPECULAR_SCHLICK_GGX) - float cLdotH5 = SchlickFresnel(cLdotH); -#endif - float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); - float Fr = mix(.04, 1.0, cLdotH5); - float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); - - float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - - specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; -#endif - } - -#ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0)); -#endif - -#endif //defined(USE_LIGHT_SHADER_CODE) -} - -#ifndef USE_NO_SHADOWS - -// Interleaved Gradient Noise -// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare -float quick_hash(vec2 pos) { - const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); - return fract(magic.z * fract(dot(pos, magic.xy))); -} - -float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { - vec2 pos = coord.xy; - float depth = coord.z; - - //if only one sample is taken, take it from the center - if (scene_data.directional_soft_shadow_samples == 1) { - return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - } - - mat2 disk_rotation; - { - float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; - float sr = sin(r); - float cr = cos(r); - disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); - } - - float avg = 0.0; - - for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) { - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0)); - } - - return avg * (1.0 / float(scene_data.directional_soft_shadow_samples)); -} - -float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { - vec2 pos = coord.xy; - float depth = coord.z; - - //if only one sample is taken, take it from the center - if (scene_data.soft_shadow_samples == 1) { - return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - } - - mat2 disk_rotation; - { - float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; - float sr = sin(r); - float cr = cos(r); - disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); - } - - float avg = 0.0; - - for (uint i = 0; i < scene_data.soft_shadow_samples; i++) { - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0)); - } - - return avg * (1.0 / float(scene_data.soft_shadow_samples)); -} - -float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) { - //find blocker - float blocker_count = 0.0; - float blocker_average = 0.0; - - mat2 disk_rotation; - { - float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; - float sr = sin(r); - float cr = cos(r); - disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); - } - - for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { - vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; - float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; - if (d < pssm_coord.z) { - blocker_average += d; - blocker_count += 1.0; - } - } - - if (blocker_count > 0.0) { - //blockers found, do soft shadow - blocker_average /= blocker_count; - float penumbra = (pssm_coord.z - blocker_average) / blocker_average; - tex_scale *= penumbra; - - float s = 0.0; - for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { - vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; - s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0)); - } - - return s / float(scene_data.directional_penumbra_shadow_samples); - - } else { - //no blockers found, so no shadow - return 1.0; - } -} - -#endif //USE_NO_SHADOWS - -float get_omni_attenuation(float distance, float inv_range, float decay) { - float nd = distance * inv_range; - nd *= nd; - nd *= nd; // nd^4 - nd = max(1.0 - nd, 0.0); - nd *= nd; // nd^2 - return nd * pow(max(distance, 0.0001), -decay); -} - -float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { -#ifndef USE_NO_SHADOWS - if (omni_lights.data[idx].shadow_enabled) { - // there is a shadowmap - - vec3 light_rel_vec = omni_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - - vec4 v = vec4(vertex, 1.0); - - vec4 splane = (omni_lights.data[idx].shadow_matrix * v); - float shadow_len = length(splane.xyz); //need to remember shadow len from here - - { - vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius; - nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp)))); - v.xyz += nofs; - splane = (omni_lights.data[idx].shadow_matrix * v); - } - - float shadow; - -#ifdef USE_SOFT_SHADOWS - if (omni_lights.data[idx].soft_shadow_size > 0.0) { - //soft shadow - - //find blocker - - float blocker_count = 0.0; - float blocker_average = 0.0; - - mat2 disk_rotation; - { - float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; - float sr = sin(r); - float cr = cos(r); - disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); - } - - vec3 normal = normalize(splane.xyz); - vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); - vec3 tangent = normalize(cross(v0, normal)); - vec3 bitangent = normalize(cross(tangent, normal)); - float z_norm = shadow_len * omni_lights.data[idx].inv_radius; - - tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; - bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; - - for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { - vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; - - vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; - - pos = normalize(pos); - vec4 uv_rect = omni_lights.data[idx].atlas_rect; - - if (pos.z >= 0.0) { - pos.z += 1.0; - uv_rect.y += uv_rect.w; - } else { - pos.z = 1.0 - pos.z; - } - - pos.xy /= pos.z; - - pos.xy = pos.xy * 0.5 + 0.5; - pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; - - float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r; - if (d < z_norm) { - blocker_average += d; - blocker_count += 1.0; - } - } - - if (blocker_count > 0.0) { - //blockers found, do soft shadow - blocker_average /= blocker_count; - float penumbra = (z_norm - blocker_average) / blocker_average; - tangent *= penumbra; - bitangent *= penumbra; - - z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; - - shadow = 0.0; - for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { - vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; - vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; - - pos = normalize(pos); - vec4 uv_rect = omni_lights.data[idx].atlas_rect; - - if (pos.z >= 0.0) { - pos.z += 1.0; - uv_rect.y += uv_rect.w; - } else { - pos.z = 1.0 - pos.z; - } - - pos.xy /= pos.z; - - pos.xy = pos.xy * 0.5 + 0.5; - pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; - shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0)); - } - - shadow /= float(scene_data.penumbra_shadow_samples); - - } else { - //no blockers found, so no shadow - shadow = 1.0; - } - } else { -#endif - splane.xyz = normalize(splane.xyz); - vec4 clamp_rect = omni_lights.data[idx].atlas_rect; - - if (splane.z >= 0.0) { - splane.z += 1.0; - - clamp_rect.y += clamp_rect.w; - - } else { - splane.z = 1.0 - splane.z; - } - - splane.xy /= splane.z; - - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; //needed? i think it should be 1 already - shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); -#ifdef USE_SOFT_SHADOWS - } -#endif - - return shadow; - } -#endif - - return 1.0; -} - -void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_curve, - float transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, vec3 rim_color, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 binormal, vec3 tangent, float anisotropy, -#endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif - inout vec3 diffuse_light, inout vec3 specular_light) { - vec3 light_rel_vec = omni_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation); - float light_attenuation = omni_attenuation; - vec3 color = omni_lights.data[idx].color; - -#ifdef USE_SOFT_SHADOWS - float size_A = 0.0; - - if (omni_lights.data[idx].size > 0.0) { - float t = omni_lights.data[idx].size / max(0.001, light_length); - size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); - } -#endif - -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; //no transmittance by default - transmittance_color.a *= light_attenuation; - { - vec4 clamp_rect = omni_lights.data[idx].atlas_rect; - - //redo shadowmapping, but shrink the model a bit to avoid arctifacts - vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0)); - - shadow_len = length(splane.xyz); - splane = normalize(splane.xyz); - - if (splane.z >= 0.0) { - splane.z += 1.0; - - } else { - splane.z = 1.0 - splane.z; - } - - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len * omni_lights.data[idx].inv_radius; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; //needed? i think it should be 1 already - - float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; - transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius; - } -#endif - -#if 0 - - if (omni_lights.data[idx].projector_rect != vec4(0.0)) { - vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; - local_v = normalize(local_v); - - vec4 atlas_rect = omni_lights.data[idx].projector_rect; - - if (local_v.z >= 0.0) { - local_v.z += 1.0; - atlas_rect.y += atlas_rect.w; - - } else { - local_v.z = 1.0 - local_v.z; - } - - local_v.xy /= local_v.z; - local_v.xy = local_v.xy * 0.5 + 0.5; - vec2 proj_uv = local_v.xy * atlas_rect.zw; - - vec2 proj_uv_ddx; - vec2 proj_uv_ddy; - { - vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz; - local_v_ddx = normalize(local_v_ddx); - - if (local_v_ddx.z >= 0.0) { - local_v_ddx.z += 1.0; - } else { - local_v_ddx.z = 1.0 - local_v_ddx.z; - } - - local_v_ddx.xy /= local_v_ddx.z; - local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5; - - proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv; - - vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz; - local_v_ddy = normalize(local_v_ddy); - - if (local_v_ddy.z >= 0.0) { - local_v_ddy.z += 1.0; - } else { - local_v_ddy.z = 1.0 - local_v_ddy.z; - } - - local_v_ddy.xy /= local_v_ddy.z; - local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5; - - proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv; - } - - vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy); - no_shadow = mix(no_shadow, proj.rgb, proj.a); - } -#endif - - light_attenuation *= shadow; - - light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, -#ifdef LIGHT_BACKLIGHT_USED - backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, - transmittance_z, -#endif -#ifdef LIGHT_RIM_USED - rim * omni_attenuation, rim_tint, rim_color, -#endif -#ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - binormal, tangent, anisotropy, -#endif -#ifdef USE_SOFT_SHADOWS - size_A, -#endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif - diffuse_light, - specular_light); -} - -float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { -#ifndef USE_NO_SHADOWS - if (spot_lights.data[idx].shadow_enabled) { - vec3 light_rel_vec = spot_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - vec3 spot_dir = spot_lights.data[idx].direction; - //there is a shadowmap - vec4 v = vec4(vertex, 1.0); - - v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias; - - float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius; - - float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map - vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale; - normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z - v.xyz += normal_bias; - - //adjust with bias - z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius; - - float shadow; - - vec4 splane = (spot_lights.data[idx].shadow_matrix * v); - splane /= splane.w; - -#ifdef USE_SOFT_SHADOWS - if (spot_lights.data[idx].soft_shadow_size > 0.0) { - //soft shadow - - //find blocker - - vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; - - float blocker_count = 0.0; - float blocker_average = 0.0; - - mat2 disk_rotation; - { - float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; - float sr = sin(r); - float cr = cos(r); - disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); - } - - float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale; - vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw; - for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { - vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; - suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); - float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; - if (d < z_norm) { - blocker_average += d; - blocker_count += 1.0; - } - } - - if (blocker_count > 0.0) { - //blockers found, do soft shadow - blocker_average /= blocker_count; - float penumbra = (z_norm - blocker_average) / blocker_average; - uv_size *= penumbra; - - shadow = 0.0; - for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { - vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; - suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); - shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0)); - } - - shadow /= float(scene_data.penumbra_shadow_samples); - - } else { - //no blockers found, so no shadow - shadow = 1.0; - } - - } else { -#endif - //hard shadow - vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0); - - shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); -#ifdef USE_SOFT_SHADOWS - } -#endif - - return shadow; - } - -#endif //USE_NO_SHADOWS - - return 1.0; -} - -void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_curve, - float transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, vec3 rim_color, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 binormal, vec3 tangent, float anisotropy, -#endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif - inout vec3 diffuse_light, - inout vec3 specular_light) { - vec3 light_rel_vec = spot_lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation); - vec3 spot_dir = spot_lights.data[idx].direction; - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[idx].cone_angle); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[idx].cone_angle)); - spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation); - float light_attenuation = spot_attenuation; - vec3 color = spot_lights.data[idx].color; - float specular_amount = spot_lights.data[idx].specular_amount; - -#ifdef USE_SOFT_SHADOWS - float size_A = 0.0; - - if (spot_lights.data[idx].size > 0.0) { - float t = spot_lights.data[idx].size / max(0.001, light_length); - size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); - } -#endif - - /* - if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) { - //use projector texture - } - */ - -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; - transmittance_color.a *= light_attenuation; - { - splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0)); - splane /= splane.w; - splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; - - float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; - //reconstruct depth - shadow_z /= spot_lights.data[idx].inv_radius; - //distance to light plane - float z = dot(spot_dir, -light_rel_vec); - transmittance_z = z - shadow_z; - } -#endif //LIGHT_TRANSMITTANCE_USED - - light_attenuation *= shadow; - - light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, -#ifdef LIGHT_BACKLIGHT_USED - backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, - transmittance_z, -#endif -#ifdef LIGHT_RIM_USED - rim * spot_attenuation, rim_tint, rim_color, -#endif -#ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - binormal, tangent, anisotropy, -#endif -#ifdef USE_SOFT_SHADOW - size_A, -#endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif - diffuse_light, specular_light); -} - -void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughness, vec3 ambient_light, vec3 specular_light, inout vec4 ambient_accum, inout vec4 reflection_accum) { - vec3 box_extents = reflections.data[ref_index].box_extents; - vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz; - - if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box - return; - } - - vec3 ref_vec = normalize(reflect(vertex, normal)); - - vec3 inner_pos = abs(local_pos / box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - //make blend more rounded - blend = mix(length(inner_pos), blend, blend); - blend *= blend; - blend = max(0.0, 1.0 - blend); - - if (reflections.data[ref_index].intensity > 0.0) { // compute reflection - - vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; - - if (reflections.data[ref_index].box_project) { //box project - - vec3 nrdir = normalize(local_ref_vec); - vec3 rbmax = (box_extents - local_pos) / nrdir; - vec3 rbmin = (-box_extents - local_pos) / nrdir; - - vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0))); - - float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - vec3 posonbox = local_pos + nrdir * fa; - local_ref_vec = posonbox - reflections.data[ref_index].box_offset; - } - - vec4 reflection; - - reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb; - - if (reflections.data[ref_index].exterior) { - reflection.rgb = mix(specular_light, reflection.rgb, blend); - } - - reflection.rgb *= reflections.data[ref_index].intensity; //intensity - reflection.a = blend; - reflection.rgb *= reflection.a; - - reflection_accum += reflection; - } - - switch (reflections.data[ref_index].ambient_mode) { - case REFLECTION_AMBIENT_DISABLED: { - //do nothing - } break; - case REFLECTION_AMBIENT_ENVIRONMENT: { - //do nothing - vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz; - - vec4 ambient_out; - - ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb; - ambient_out.a = blend; - if (reflections.data[ref_index].exterior) { - ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); - } - - ambient_out.rgb *= ambient_out.a; - ambient_accum += ambient_out; - } break; - case REFLECTION_AMBIENT_COLOR: { - vec4 ambient_out; - ambient_out.a = blend; - ambient_out.rgb = reflections.data[ref_index].ambient; - if (reflections.data[ref_index].exterior) { - ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); - } - ambient_out.rgb *= ambient_out.a; - ambient_accum += ambient_out; - } break; - } -} - -#ifdef USE_FORWARD_GI - -//standard voxel cone trace -vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) { - float dist = p_bias; - vec4 color = vec4(0.0); - - while (dist < max_distance && color.a < 0.95) { - float diameter = max(1.0, 2.0 * tan_half_angle * dist); - vec3 uvw_pos = (pos + dist * direction) * cell_size; - float half_diameter = diameter * 0.5; - //check if outside, then break - if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + half_diameter * cell_size)))) { - break; - } - vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter)); - float a = (1.0 - color.a); - color += a * scolor; - dist += half_diameter; - } - - return color; -} - -vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) { - float dist = p_bias; - vec4 color = vec4(0.0); - float radius = max(0.5, tan_half_angle * dist); - float lod_level = log2(radius * 2.0); - - while (dist < max_distance && color.a < 0.95) { - vec3 uvw_pos = (pos + dist * direction) * cell_size; - - //check if outside, then break - if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + radius * cell_size)))) { - break; - } - vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level); - lod_level += 1.0; - - float a = (1.0 - color.a); - scolor *= a; - color += scolor; - dist += radius; - radius = max(0.5, tan_half_angle * dist); - } - - return color; -} - -void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) { - position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz; - ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz); - normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz); - - position += normal * gi_probes.data[index].normal_bias; - - //this causes corrupted pixels, i have no idea why.. - if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) { - return; - } - - vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0); - float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0); - //float blend=1.0; - - float max_distance = length(gi_probes.data[index].bounds); - vec3 cell_size = 1.0 / gi_probes.data[index].bounds; - - //radiance - -#define MAX_CONE_DIRS 4 - - vec3 cone_dirs[MAX_CONE_DIRS] = vec3[]( - vec3(0.707107, 0.0, 0.707107), - vec3(0.0, 0.707107, 0.707107), - vec3(-0.707107, 0.0, 0.707107), - vec3(0.0, -0.707107, 0.707107)); - - float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25); - float cone_angle_tan = 0.98269; - - vec3 light = vec3(0.0); - - for (int i = 0; i < MAX_CONE_DIRS; i++) { - vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz); - - vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias); - - if (gi_probes.data[index].blend_ambient) { - cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95)); - } - - light += cone_weights[i] * cone_light.rgb; - } - - light *= gi_probes.data[index].dynamic_range; - out_diff += vec4(light * blend, blend); - - //irradiance - vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias); - if (gi_probes.data[index].blend_ambient) { - irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95)); - } - irr_light.rgb *= gi_probes.data[index].dynamic_range; - //irr_light=vec3(0.0); - - out_spec += vec4(irr_light.rgb * blend, blend); -} - -vec2 octahedron_wrap(vec2 v) { - vec2 signVal; - signVal.x = v.x >= 0.0 ? 1.0 : -1.0; - signVal.y = v.y >= 0.0 ? 1.0 : -1.0; - return (1.0 - abs(v.yx)) * signVal; -} - -vec2 octahedron_encode(vec3 n) { - // https://twitter.com/Stubbesaurus/status/937994790553227264 - n /= (abs(n.x) + abs(n.y) + abs(n.z)); - n.xy = n.z >= 0.0 ? n.xy : octahedron_wrap(n.xy); - n.xy = n.xy * 0.5 + 0.5; - return n.xy; -} - -void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, bool use_specular, float roughness, out vec3 diffuse_light, out vec3 specular_light, out float blend) { - cascade_pos += cam_normal * sdfgi.normal_bias; - - vec3 base_pos = floor(cascade_pos); - //cascade_pos += mix(vec3(0.0),vec3(0.01),lessThan(abs(cascade_pos-base_pos),vec3(0.01))) * cam_normal; - ivec3 probe_base_pos = ivec3(base_pos); - - vec4 diffuse_accum = vec4(0.0); - vec3 specular_accum; - - ivec3 tex_pos = ivec3(probe_base_pos.xy, int(cascade)); - tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size; - tex_pos.xy = tex_pos.xy * (SDFGI_OCT_SIZE + 2) + ivec2(1); - - vec3 diffuse_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size; - - vec3 specular_posf; - - if (use_specular) { - specular_accum = vec3(0.0); - specular_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_specular_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size; - } - - vec4 light_accum = vec4(0.0); - float weight_accum = 0.0; - - for (uint j = 0; j < 8; j++) { - ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); - ivec3 probe_posi = probe_base_pos; - probe_posi += offset; - - // Compute weight - - vec3 probe_pos = vec3(probe_posi); - vec3 probe_to_pos = cascade_pos - probe_pos; - vec3 probe_dir = normalize(-probe_to_pos); - - vec3 trilinear = vec3(1.0) - abs(probe_to_pos); - float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(cam_normal, probe_dir)); - - // Compute lightprobe occlusion - - if (sdfgi.use_occlusion) { - ivec3 occ_indexv = abs((sdfgi.cascades[cascade].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4); - vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3))); - - vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw; - occ_pos.z += float(cascade); - if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures - occ_pos.x += 1.0; - } - - occ_pos *= sdfgi.occlusion_renormalize; - float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, material_samplers[SAMPLER_LINEAR_CLAMP]), occ_pos, 0.0), occ_mask); - - weight *= max(occlusion, 0.01); - } - - // Compute lightprobe texture position - - vec3 diffuse; - vec3 pos_uvw = diffuse_posf; - pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy; - pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z; - diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb; - - diffuse_accum += vec4(diffuse * weight, weight); - - if (use_specular) { - vec3 specular = vec3(0.0); - vec3 pos_uvw = specular_posf; - pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy; - pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z; - if (roughness < 0.99) { - specular = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw + vec3(0, 0, float(sdfgi.max_cascades)), 0.0).rgb; - } - if (roughness > 0.5) { - specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0); - } - - specular_accum += specular * weight; - } - } - - if (diffuse_accum.a > 0.0) { - diffuse_accum.rgb /= diffuse_accum.a; - } - - diffuse_light = diffuse_accum.rgb; - - if (use_specular) { - if (diffuse_accum.a > 0.0) { - specular_accum /= diffuse_accum.a; - } - - specular_light = specular_accum; - } - - { - //process blend - float blend_from = (float(sdfgi.probe_axis_size - 1) / 2.0) - 2.5; - float blend_to = blend_from + 2.0; - - vec3 inner_pos = cam_pos * sdfgi.cascades[cascade].to_probe; - - float len = length(inner_pos); - - inner_pos = abs(normalize(inner_pos)); - len *= max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - - if (len >= blend_from) { - blend = smoothstep(blend_from, blend_to, len); - } else { - blend = 0.0; - } - } -} - -#endif //USE_FORWARD_GI - -#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - -#ifndef MODE_RENDER_DEPTH - -#ifndef LOW_END_MODE - -vec4 volumetric_fog_process(vec2 screen_uv, float z) { - vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length); - if (fog_pos.z < 0.0) { - return vec4(0.0); - } else if (fog_pos.z < 1.0) { - fog_pos.z = pow(fog_pos.z, scene_data.volumetric_fog_detail_spread); - } - - return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); -} -#endif - -vec4 fog_process(vec3 vertex) { - vec3 fog_color = scene_data.fog_light_color; - - if (scene_data.fog_aerial_perspective > 0.0) { - vec3 sky_fog_color = vec3(0.0); - vec3 cube_view = scene_data.radiance_inverse_xform * vertex; - // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred - float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)); -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - float lod, blend; - blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod); - sky_fog_color = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod)).rgb; - sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod + 1)).rgb, blend); -#else - sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb; -#endif //USE_RADIANCE_CUBEMAP_ARRAY - fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective); - } - - if (scene_data.fog_sun_scatter > 0.001) { - vec4 sun_scatter = vec4(0.0); - float sun_total = 0.0; - vec3 view = normalize(vertex); - - for (uint i = 0; i < scene_data.directional_light_count; i++) { - vec3 light_color = directional_lights.data[i].color * directional_lights.data[i].energy; - float light_amount = pow(max(dot(view, directional_lights.data[i].direction), 0.0), 8.0); - fog_color += light_color * light_amount * scene_data.fog_sun_scatter; - } - } - - float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density)); - - if (abs(scene_data.fog_height_density) > 0.001) { - float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y; - - float y_dist = scene_data.fog_height - y; - - float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0); - - fog_amount = max(vfog_amount, fog_amount); - } - - return vec4(fog_color, fog_amount); -} - -void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { - uint item_min_max = cluster_buffer.data[p_offset]; - item_min = item_min_max & 0xFFFF; - item_max = item_min_max >> 16; - ; - - item_from = item_min >> 5; - item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements -} - -uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { - int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); - int mask_width = min(int(z_max) - int(z_min), 32 - local_min); - return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); -} - -float blur_shadow(float shadow) { - return shadow; -#if 0 - //disabling for now, will investigate later - float interp_shadow = shadow; - if (gl_HelperInvocation) { - interp_shadow = -4.0; // technically anything below -4 will do but just to make sure - } - - uvec2 fc2 = uvec2(gl_FragCoord.xy); - interp_shadow -= dFdx(interp_shadow) * (float(fc2.x & 1) - 0.5); - interp_shadow -= dFdy(interp_shadow) * (float(fc2.y & 1) - 0.5); - - if (interp_shadow >= 0.0) { - shadow = interp_shadow; - } - return shadow; -#endif -} - -#endif //!MODE_RENDER DEPTH - -void main() { -#ifdef MODE_DUAL_PARABOLOID - - if (dp_clip > 0.0) - discard; -#endif - - //lay out everything, whathever is unused is optimized away anyway - vec3 vertex = vertex_interp; - vec3 view = -normalize(vertex_interp); - vec3 albedo = vec3(1.0); - vec3 backlight = vec3(0.0); - vec4 transmittance_color = vec4(0.0); - float transmittance_depth = 0.0; - float transmittance_curve = 1.0; - float transmittance_boost = 0.0; - float metallic = 0.0; - float specular = 0.5; - vec3 emission = vec3(0.0); - float roughness = 1.0; - float rim = 0.0; - float rim_tint = 0.0; - float clearcoat = 0.0; - float clearcoat_gloss = 0.0; - float anisotropy = 0.0; - vec2 anisotropy_flow = vec2(1.0, 0.0); - vec4 fog = vec4(0.0); -#if defined(CUSTOM_RADIANCE_USED) - vec4 custom_radiance = vec4(0.0); -#endif -#if defined(CUSTOM_IRRADIANCE_USED) - vec4 custom_irradiance = vec4(0.0); -#endif - - float ao = 1.0; - float ao_light_affect = 0.0; - - float alpha = 1.0; - -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 binormal = normalize(binormal_interp); - vec3 tangent = normalize(tangent_interp); -#else - vec3 binormal = vec3(0.0); - vec3 tangent = vec3(0.0); -#endif - -#ifdef NORMAL_USED - vec3 normal = normalize(normal_interp); - -#if defined(DO_SIDE_CHECK) - if (!gl_FrontFacing) { - normal = -normal; - } -#endif - -#endif //NORMAL_USED - -#ifdef UV_USED - vec2 uv = uv_interp; -#endif - -#if defined(UV2_USED) || defined(USE_LIGHTMAP) - vec2 uv2 = uv2_interp; -#endif - -#if defined(COLOR_USED) - vec4 color = color_interp; -#endif - -#if defined(NORMAL_MAP_USED) - - vec3 normal_map = vec3(0.5); -#endif - - float normal_map_depth = 1.0; - - vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size + scene_data.screen_pixel_size * 0.5; //account for center - - float sss_strength = 0.0; - -#ifdef ALPHA_SCISSOR_USED - float alpha_scissor_threshold = 1.0; -#endif // ALPHA_SCISSOR_USED - -#ifdef ALPHA_HASH_USED - float alpha_hash_scale = 1.0; -#endif // ALPHA_HASH_USED - -#ifdef ALPHA_ANTIALIASING_EDGE_USED - float alpha_antialiasing_edge = 0.0; - vec2 alpha_texture_coordinate = vec2(0.0, 0.0); -#endif // ALPHA_ANTIALIASING_EDGE_USED - - { - /* clang-format off */ - -FRAGMENT_SHADER_CODE - - /* clang-format on */ - } - -#ifdef LIGHT_TRANSMITTANCE_USED -#ifdef SSS_MODE_SKIN - transmittance_color.a = sss_strength; -#else - transmittance_color.a *= sss_strength; -#endif -#endif - -#ifndef USE_SHADOW_TO_OPACITY - -#ifdef ALPHA_SCISSOR_USED - if (alpha < alpha_scissor_threshold) { - discard; - } -#endif // ALPHA_SCISSOR_USED - -// alpha hash can be used in unison with alpha antialiasing -#ifdef ALPHA_HASH_USED - if (alpha < compute_alpha_hash_threshold(vertex, alpha_hash_scale)) { - discard; - } -#endif // ALPHA_HASH_USED - -// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash -#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED) - alpha = 1.0; -#endif - -#ifdef ALPHA_ANTIALIASING_EDGE_USED -// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather -#ifdef ALPHA_SCISSOR_USED - alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0); -#endif - alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge); -#endif // ALPHA_ANTIALIASING_EDGE_USED - -#ifdef USE_OPAQUE_PREPASS - if (alpha < opaque_prepass_threshold) { - discard; - } -#endif // USE_OPAQUE_PREPASS - -#endif // !USE_SHADOW_TO_OPACITY - -#ifdef NORMAL_MAP_USED - - normal_map.xy = normal_map.xy * 2.0 - 1.0; - normal_map.z = sqrt(max(0.0, 1.0 - dot(normal_map.xy, normal_map.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. - - normal = normalize(mix(normal, tangent * normal_map.x + binormal * normal_map.y + normal * normal_map.z, normal_map_depth)); - -#endif - -#ifdef LIGHT_ANISOTROPY_USED - - if (anisotropy > 0.01) { - //rotation matrix - mat3 rot = mat3(tangent, binormal, normal); - //make local to space - tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0)); - binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0)); - } - -#endif - -#ifdef ENABLE_CLIP_ALPHA - if (albedo.a < 0.99) { - //used for doublepass and shadowmapping - discard; - } -#endif - - /////////////////////// FOG ////////////////////// -#ifndef MODE_RENDER_DEPTH - -#ifndef CUSTOM_FOG_USED - // fog must be processed as early as possible and then packed. - // to maximize VGPR usage - // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. - - if (scene_data.fog_enabled) { - fog = fog_process(vertex); - } - -#ifndef LOW_END_MODE - if (scene_data.volumetric_fog_enabled) { - vec4 volumetric_fog = volumetric_fog_process(screen_uv, -vertex.z); - if (scene_data.fog_enabled) { - //must use the full blending equation here to blend fogs - vec4 res; - float sa = 1.0 - volumetric_fog.a; - res.a = fog.a * sa + volumetric_fog.a; - if (res.a == 0.0) { - res.rgb = vec3(0.0); - } else { - res.rgb = (fog.rgb * fog.a * sa + volumetric_fog.rgb * volumetric_fog.a) / res.a; - } - fog = res; - } else { - fog = volumetric_fog; - } - } -#endif //!LOW_END_MODE -#endif //!CUSTOM_FOG_USED - - uint fog_rg = packHalf2x16(fog.rg); - uint fog_ba = packHalf2x16(fog.ba); - -#endif //!MODE_RENDER_DEPTH - - /////////////////////// DECALS //////////////////////////////// - -#ifndef MODE_RENDER_DEPTH - - uvec2 cluster_pos = uvec2(gl_FragCoord.xy) >> scene_data.cluster_shift; - uint cluster_offset = (scene_data.cluster_width * cluster_pos.y + cluster_pos.x) * (scene_data.max_cluster_element_count_div_32 + 32); - - uint cluster_z = uint(clamp((-vertex.z / scene_data.z_far) * 32.0, 0.0, 31.0)); - - //used for interpolating anything cluster related - vec3 vertex_ddx = dFdx(vertex); - vec3 vertex_ddy = dFdy(vertex); - - { // process decals - - uint cluster_decal_offset = cluster_offset + scene_data.cluster_type_size * 2; - - uint item_min; - uint item_max; - uint item_from; - uint item_to; - - cluster_get_item_range(cluster_decal_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - -#ifdef USE_SUBGROUPS - item_from = subgroupBroadcastFirst(subgroupMin(item_from)); - item_to = subgroupBroadcastFirst(subgroupMax(item_to)); -#endif - - for (uint i = item_from; i < item_to; i++) { - uint mask = cluster_buffer.data[cluster_decal_offset + i]; - mask &= cluster_get_range_clip_mask(i, item_min, item_max); -#ifdef USE_SUBGROUPS - uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); -#else - uint merged_mask = mask; -#endif - - while (merged_mask != 0) { - uint bit = findMSB(merged_mask); - merged_mask &= ~(1 << bit); -#ifdef USE_SUBGROUPS - if (((1 << bit) & mask) == 0) { //do not process if not originally here - continue; - } -#endif - uint decal_index = 32 * i + bit; - - if (!bool(decals.data[decal_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } - - vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; - if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { - continue; //out of decal - } - - //we need ddx/ddy for mipmaps, so simulate them - vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz; - vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz; - - float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade); - - if (decals.data[decal_index].normal_fade > 0.0) { - fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5); - } - - if (decals.data[decal_index].albedo_rect != vec4(0.0)) { - //has albedo - vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw); - decal_albedo *= decals.data[decal_index].modulate; - decal_albedo.a *= fade; - albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix); - - if (decals.data[decal_index].normal_rect != vec4(0.0)) { - vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz; - decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software - decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy))); - //convert to view space, use xzy because y is up - decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; - - normal = normalize(mix(normal, decal_normal, decal_albedo.a)); - } - - if (decals.data[decal_index].orm_rect != vec4(0.0)) { - vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz; - ao = mix(ao, decal_orm.r, decal_albedo.a); - roughness = mix(roughness, decal_orm.g, decal_albedo.a); - metallic = mix(metallic, decal_orm.b, decal_albedo.a); - } - } - - if (decals.data[decal_index].emission_rect != vec4(0.0)) { - //emission is additive, so its independent from albedo - emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade; - } - } - } - } - - //pack albedo until needed again, saves 2 VGPRs in the meantime - -#endif //not render depth - /////////////////////// LIGHTING ////////////////////////////// - -#ifdef NORMAL_USED - if (scene_data.roughness_limiter_enabled) { - //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf - float roughness2 = roughness * roughness; - vec3 dndu = dFdx(normal), dndv = dFdx(normal); - float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv)); - float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect - float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2); - roughness = sqrt(filteredRoughness2); - } -#endif - //apply energy conservation - - vec3 specular_light = vec3(0.0, 0.0, 0.0); - vec3 diffuse_light = vec3(0.0, 0.0, 0.0); - vec3 ambient_light = vec3(0.0, 0.0, 0.0); - -#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - - if (scene_data.use_reflection_cubemap) { - vec3 ref_vec = reflect(-view, normal); - ref_vec = scene_data.radiance_inverse_xform * ref_vec; -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - - float lod, blend; - blend = modf(roughness * MAX_ROUGHNESS_LOD, lod); - specular_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb; - specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend); - -#else - specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb; - -#endif //USE_RADIANCE_CUBEMAP_ARRAY - specular_light *= scene_data.ambient_light_color_energy.a; - } - -#if defined(CUSTOM_RADIANCE_USED) - specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a); -#endif - -#ifndef USE_LIGHTMAP - //lightmap overrides everything - if (scene_data.use_ambient_light) { - ambient_light = scene_data.ambient_light_color_energy.rgb; - - if (scene_data.use_ambient_cubemap) { - vec3 ambient_dir = scene_data.radiance_inverse_xform * normal; -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb; -#else - vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ambient_dir, MAX_ROUGHNESS_LOD).rgb; -#endif //USE_RADIANCE_CUBEMAP_ARRAY - - ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix); - } - } -#endif // USE_LIGHTMAP -#if defined(CUSTOM_IRRADIANCE_USED) - ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a); -#endif -#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - - //radiance - -/// GI /// -#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - -#ifdef USE_LIGHTMAP - - //lightmap - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture - uint index = instances.data[instance_index].gi_offset; - - vec3 wnormal = mat3(scene_data.camera_matrix) * normal; - const float c1 = 0.429043; - const float c2 = 0.511664; - const float c3 = 0.743125; - const float c4 = 0.886227; - const float c5 = 0.247708; - ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) + - c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z + - c4 * lightmap_captures.data[index].sh[0].rgb - - c5 * lightmap_captures.data[index].sh[6].rgb + - 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y + - 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z + - 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z + - 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x + - 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y + - 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z); - - } else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap - bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); - uint ofs = instances.data[instance_index].gi_offset & 0xFFFF; - vec3 uvw; - uvw.xy = uv2 * instances.data[instance_index].lightmap_uv_scale.zw + instances.data[instance_index].lightmap_uv_scale.xy; - uvw.z = float((instances.data[instance_index].gi_offset >> 16) & 0xFFFF); - - if (uses_sh) { - uvw.z *= 4.0; //SH textures use 4 times more data - vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb; - vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb; - vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb; - vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb; - - uint idx = instances.data[instance_index].gi_offset >> 20; - vec3 n = normalize(lightmaps.data[idx].normal_xform * normal); - - ambient_light += lm_light_l0 * 0.282095f; - ambient_light += lm_light_l1n1 * 0.32573 * n.y; - ambient_light += lm_light_l1_0 * 0.32573 * n.z; - ambient_light += lm_light_l1p1 * 0.32573 * n.x; - if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick - vec3 r = reflect(normalize(-vertex), normal); - specular_light += lm_light_l1n1 * 0.32573 * r.y; - specular_light += lm_light_l1_0 * 0.32573 * r.z; - specular_light += lm_light_l1p1 * 0.32573 * r.x; - } - - } else { - ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb; - } - } -#elif defined(USE_FORWARD_GI) - - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture - - //make vertex orientation the world one, but still align to camera - vec3 cam_pos = mat3(scene_data.camera_matrix) * vertex; - vec3 cam_normal = mat3(scene_data.camera_matrix) * normal; - vec3 cam_reflection = mat3(scene_data.camera_matrix) * reflect(-view, normal); - - //apply y-mult - cam_pos.y *= sdfgi.y_mult; - cam_normal.y *= sdfgi.y_mult; - cam_normal = normalize(cam_normal); - cam_reflection.y *= sdfgi.y_mult; - cam_normal = normalize(cam_normal); - cam_reflection = normalize(cam_reflection); - - vec4 light_accum = vec4(0.0); - float weight_accum = 0.0; - - vec4 light_blend_accum = vec4(0.0); - float weight_blend_accum = 0.0; - - float blend = -1.0; - - // helper constants, compute once - - uint cascade = 0xFFFFFFFF; - vec3 cascade_pos; - vec3 cascade_normal; - - for (uint i = 0; i < sdfgi.max_cascades; i++) { - cascade_pos = (cam_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe; - - if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) { - continue; //skip cascade - } - - cascade = i; - break; - } - - if (cascade < SDFGI_MAX_CASCADES) { - bool use_specular = true; - float blend; - vec3 diffuse, specular; - sdfgi_process(cascade, cascade_pos, cam_pos, cam_normal, cam_reflection, use_specular, roughness, diffuse, specular, blend); - - if (blend > 0.0) { - //blend - if (cascade == sdfgi.max_cascades - 1) { - diffuse = mix(diffuse, ambient_light, blend); - if (use_specular) { - specular = mix(specular, specular_light, blend); - } - } else { - vec3 diffuse2, specular2; - float blend2; - cascade_pos = (cam_pos - sdfgi.cascades[cascade + 1].position) * sdfgi.cascades[cascade + 1].to_probe; - sdfgi_process(cascade + 1, cascade_pos, cam_pos, cam_normal, cam_reflection, use_specular, roughness, diffuse2, specular2, blend2); - diffuse = mix(diffuse, diffuse2, blend); - if (use_specular) { - specular = mix(specular, specular2, blend); - } - } - } - - ambient_light = diffuse; - if (use_specular) { - specular_light = specular; - } - } - } - - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes - - uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; - vec3 ref_vec = normalize(reflect(normalize(vertex), normal)); - //find arbitrary tangent and bitangent, then build a matrix - vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); - vec3 tangent = normalize(cross(v0, normal)); - vec3 bitangent = normalize(cross(tangent, normal)); - mat3 normal_mat = mat3(tangent, bitangent, normal); - - vec4 amb_accum = vec4(0.0); - vec4 spec_accum = vec4(0.0); - gi_probe_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); - - uint index2 = instances.data[instance_index].gi_offset >> 16; - - if (index2 != 0xFFFF) { - gi_probe_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); - } - - if (amb_accum.a > 0.0) { - amb_accum.rgb /= amb_accum.a; - } - - if (spec_accum.a > 0.0) { - spec_accum.rgb /= spec_accum.a; - } - - specular_light = spec_accum.rgb; - ambient_light = amb_accum.rgb; - } -#elif !defined(LOW_END_MODE) - - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers - - vec2 coord; - - if (scene_data.gi_upscale_for_msaa) { - vec2 base_coord = screen_uv; - vec2 closest_coord = base_coord; - float closest_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord, 0.0).xyz * 2.0 - 1.0); - - for (int i = 0; i < 4; i++) { - const vec2 neighbours[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1)); - vec2 neighbour_coord = base_coord + neighbours[i] * scene_data.screen_pixel_size; - float neighbour_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), neighbour_coord, 0.0).xyz * 2.0 - 1.0); - if (neighbour_ang > closest_ang) { - closest_ang = neighbour_ang; - closest_coord = neighbour_coord; - } - } - - coord = closest_coord; - - } else { - coord = screen_uv; - } - - vec4 buffer_ambient = textureLod(sampler2D(ambient_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0.0); - vec4 buffer_reflection = textureLod(sampler2D(reflection_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0.0); - - ambient_light = mix(ambient_light, buffer_ambient.rgb, buffer_ambient.a); - specular_light = mix(specular_light, buffer_reflection.rgb, buffer_reflection.a); - } -#endif - -#ifndef LOW_END_MODE - if (scene_data.ssao_enabled) { - float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; - ao = min(ao, ssao); - ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); - } -#endif //LOW_END_MODE - - { // process reflections - - vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); - vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); - - uint cluster_reflection_offset = cluster_offset + scene_data.cluster_type_size * 3; - - uint item_min; - uint item_max; - uint item_from; - uint item_to; - - cluster_get_item_range(cluster_reflection_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - -#ifdef USE_SUBGROUPS - item_from = subgroupBroadcastFirst(subgroupMin(item_from)); - item_to = subgroupBroadcastFirst(subgroupMax(item_to)); -#endif - - for (uint i = item_from; i < item_to; i++) { - uint mask = cluster_buffer.data[cluster_reflection_offset + i]; - mask &= cluster_get_range_clip_mask(i, item_min, item_max); -#ifdef USE_SUBGROUPS - uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); -#else - uint merged_mask = mask; -#endif - - while (merged_mask != 0) { - uint bit = findMSB(merged_mask); - merged_mask &= ~(1 << bit); -#ifdef USE_SUBGROUPS - if (((1 << bit) & mask) == 0) { //do not process if not originally here - continue; - } -#endif - uint reflection_index = 32 * i + bit; - - if (!bool(reflections.data[reflection_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } - - reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); - } - } - - if (reflection_accum.a > 0.0) { - specular_light = reflection_accum.rgb / reflection_accum.a; - } - -#if !defined(USE_LIGHTMAP) - if (ambient_accum.a > 0.0) { - ambient_light = ambient_accum.rgb / ambient_accum.a; - } -#endif - } - - //finalize ambient light here - ambient_light *= albedo.rgb; - ambient_light *= ao; - - // convert ao to direct light ao - ao = mix(1.0, ao, ao_light_affect); - - //this saves some VGPRs - vec3 f0 = F0(metallic, specular, albedo); - - { -#if defined(DIFFUSE_TOON) - //simplify for toon, as - specular_light *= specular * metallic * albedo * 2.0; -#else - - // scales the specular reflections, needs to be be computed before lighting happens, - // but after environment, GI, and reflection probes are added - // Environment brdf approximation (Lazarov 2013) - // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile - const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); - const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); - vec4 r = roughness * c0 + c1; - float ndotv = clamp(dot(normal, view), 0.0, 1.0); - float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; - vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; - - specular_light *= env.x * f0 + env.y; -#endif - } - -#endif //GI !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - -#if !defined(MODE_RENDER_DEPTH) - //this saves some VGPRs - uint orms = packUnorm4x8(vec4(ao, roughness, metallic, specular)); -#endif - -// LIGHTING -#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - - { //directional light - - // Do shadow and lighting in two passes to reduce register pressure - uint shadow0 = 0; - uint shadow1 = 0; - - for (uint i = 0; i < 8; i++) { - if (i >= scene_data.directional_light_count) { - break; - } - - if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } - - float shadow = 1.0; - -#ifdef USE_SOFT_SHADOWS - //version with soft shadows, more expensive - if (directional_lights.data[i].shadow_enabled) { - float depth_z = -vertex.z; - - vec4 pssm_coord; - vec3 shadow_color = vec3(0.0); - vec3 light_dir = directional_lights.data[i].direction; - -#define BIAS_FUNC(m_var, m_idx) \ - m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ - vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \ - normal_bias -= light_dir * dot(light_dir, normal_bias); \ - m_var.xyz += normal_bias; - - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 0) - - pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.x; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - } else { - shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); - } - - shadow_color = directional_lights.data[i].shadow_color1.rgb; - - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 1) - - pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.y; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - } else { - shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); - } - - shadow_color = directional_lights.data[i].shadow_color2.rgb; - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 2) - - pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.z; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - } else { - shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); - } - - shadow_color = directional_lights.data[i].shadow_color3.rgb; - - } else { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 3) - - pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.w; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - } else { - shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); - } - - shadow_color = directional_lights.data[i].shadow_color4.rgb; - } - - if (directional_lights.data[i].blend_splits) { - vec3 shadow_color_blend = vec3(0.0); - float pssm_blend; - float shadow2; - - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { - vec4 v = vec4(vertex, 1.0); - BIAS_FUNC(v, 1) - pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.y; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; - shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - } else { - shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); - } - - pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); - shadow_color_blend = directional_lights.data[i].shadow_color2.rgb; - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { - vec4 v = vec4(vertex, 1.0); - BIAS_FUNC(v, 2) - pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); - pssm_coord /= pssm_coord.w; - - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.z; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; - shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - } else { - shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); - } - - pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); - - shadow_color_blend = directional_lights.data[i].shadow_color3.rgb; - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { - vec4 v = vec4(vertex, 1.0); - BIAS_FUNC(v, 3) - pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); - pssm_coord /= pssm_coord.w; - if (directional_lights.data[i].softshadow_angle > 0) { - float range_pos = dot(directional_lights.data[i].direction, v.xyz); - float range_begin = directional_lights.data[i].shadow_range_begin.w; - float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; - vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; - shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - } else { - shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); - } - - pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); - shadow_color_blend = directional_lights.data[i].shadow_color4.rgb; - } else { - pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) - } - - pssm_blend = sqrt(pssm_blend); - - shadow = mix(shadow, shadow2, pssm_blend); - shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend); - } - - shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance - -#undef BIAS_FUNC - } -#else - // Soft shadow disabled version - - if (directional_lights.data[i].shadow_enabled) { - float depth_z = -vertex.z; - - vec4 pssm_coord; - vec3 light_dir = directional_lights.data[i].direction; - vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))); - -#define BIAS_FUNC(m_var, m_idx) \ - m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ - vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \ - normal_bias -= light_dir * dot(light_dir, normal_bias); \ - m_var.xyz += normal_bias; - - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 0) - - pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; - - transmittance_z = z - shadow_z; - } -#endif - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 1) - - pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; - - transmittance_z = z - shadow_z; - } -#endif - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 2) - - pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; - - transmittance_z = z - shadow_z; - } -#endif - - } else { - vec4 v = vec4(vertex, 1.0); - - BIAS_FUNC(v, 3) - - pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; - - transmittance_z = z - shadow_z; - } -#endif - } - - pssm_coord /= pssm_coord.w; - - shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); - - if (directional_lights.data[i].blend_splits) { - float pssm_blend; - - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { - vec4 v = vec4(vertex, 1.0); - BIAS_FUNC(v, 1) - pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); - pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { - vec4 v = vec4(vertex, 1.0); - BIAS_FUNC(v, 2) - pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); - pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { - vec4 v = vec4(vertex, 1.0); - BIAS_FUNC(v, 3) - pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); - pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); - } else { - pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) - } - - pssm_coord /= pssm_coord.w; - - float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); - shadow = mix(shadow, shadow2, pssm_blend); - } - - shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance - -#undef BIAS_FUNC - } -#endif - - if (i < 4) { - shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8); - } else { - shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8); - } - } - - for (uint i = 0; i < 8; i++) { - if (i >= scene_data.directional_light_count) { - break; - } - - if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } - -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; - - if (directional_lights.data[i].shadow_enabled) { - float depth_z = -vertex.z; - - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; - - transmittance_z = z - shadow_z; - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; - - transmittance_z = z - shadow_z; - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; - - transmittance_z = z - shadow_z; - - } else { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; - - transmittance_z = z - shadow_z; - } -#endif - - float shadow = 1.0; - - if (i < 4) { - shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0; - } else { - shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; - } - - blur_shadow(shadow); - - light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, -#ifdef LIGHT_BACKLIGHT_USED - backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, - transmittance_z, -#endif -#ifdef LIGHT_RIM_USED - rim, rim_tint, albedo, -#endif -#ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - binormal, tangent, anisotropy, -#endif -#ifdef USE_SOFT_SHADOW - directional_lights.data[i].size, -#endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif - diffuse_light, - specular_light); - } - } - - { //omni lights - - uint cluster_omni_offset = cluster_offset; - - uint item_min; - uint item_max; - uint item_from; - uint item_to; - - cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - -#ifdef USE_SUBGROUPS - item_from = subgroupBroadcastFirst(subgroupMin(item_from)); - item_to = subgroupBroadcastFirst(subgroupMax(item_to)); -#endif - - for (uint i = item_from; i < item_to; i++) { - uint mask = cluster_buffer.data[cluster_omni_offset + i]; - mask &= cluster_get_range_clip_mask(i, item_min, item_max); -#ifdef USE_SUBGROUPS - uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); -#else - uint merged_mask = mask; -#endif - - while (merged_mask != 0) { - uint bit = findMSB(merged_mask); - merged_mask &= ~(1 << bit); -#ifdef USE_SUBGROUPS - if (((1 << bit) & mask) == 0) { //do not process if not originally here - continue; - } -#endif - uint light_index = 32 * i + bit; - - if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } - - float shadow = light_process_omni_shadow(light_index, vertex, view); - - shadow = blur_shadow(shadow); - - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, -#ifdef LIGHT_BACKLIGHT_USED - backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - rim, - rim_tint, - albedo, -#endif -#ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, -#endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif - diffuse_light, specular_light); - } - } - } - - { //spot lights - - uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size; - - uint item_min; - uint item_max; - uint item_from; - uint item_to; - - cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - -#ifdef USE_SUBGROUPS - item_from = subgroupBroadcastFirst(subgroupMin(item_from)); - item_to = subgroupBroadcastFirst(subgroupMax(item_to)); -#endif - - for (uint i = item_from; i < item_to; i++) { - uint mask = cluster_buffer.data[cluster_spot_offset + i]; - mask &= cluster_get_range_clip_mask(i, item_min, item_max); -#ifdef USE_SUBGROUPS - uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); -#else - uint merged_mask = mask; -#endif - - while (merged_mask != 0) { - uint bit = findMSB(merged_mask); - merged_mask &= ~(1 << bit); -#ifdef USE_SUBGROUPS - if (((1 << bit) & mask) == 0) { //do not process if not originally here - continue; - } -#endif - - uint light_index = 32 * i + bit; - - if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } - - float shadow = light_process_spot_shadow(light_index, vertex, view); - - shadow = blur_shadow(shadow); - - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, -#ifdef LIGHT_BACKLIGHT_USED - backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - rim, - rim_tint, - albedo, -#endif -#ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, -#endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif - diffuse_light, specular_light); - } - } - } - -#ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); - -#if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { - discard; - } -#endif // ALPHA_SCISSOR_USED - -#ifdef USE_OPAQUE_PREPASS - - if (alpha < opaque_prepass_threshold) { - discard; - } - -#endif // USE_OPAQUE_PREPASS - -#endif // USE_SHADOW_TO_OPACITY - -#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - -#ifdef MODE_RENDER_DEPTH - -#ifdef MODE_RENDER_SDF - - { - vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz; - ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size)); - - uint albedo16 = 0x1; //solid flag - albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11; - albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6; - albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1; - - imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16)); - - uint facing_bits = 0; - const vec3 aniso_dir[6] = vec3[]( - vec3(1, 0, 0), - vec3(0, 1, 0), - vec3(0, 0, 1), - vec3(-1, 0, 0), - vec3(0, -1, 0), - vec3(0, 0, -1)); - - vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp); - - float closest_dist = -1e20; - - for (uint i = 0; i < 6; i++) { - float d = dot(cam_normal, aniso_dir[i]); - if (d > closest_dist) { - closest_dist = d; - facing_bits = (1 << i); - } - } - - imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits - - if (length(emission) > 0.001) { - float lumas[6]; - vec3 light_total = vec3(0); - - for (int i = 0; i < 6; i++) { - float strength = max(0.0, dot(cam_normal, aniso_dir[i])); - vec3 light = emission * strength; - light_total += light; - lumas[i] = max(light.r, max(light.g, light.b)); - } - - float luma_total = max(light_total.r, max(light_total.g, light_total.b)); - - uint light_aniso = 0; - - for (int i = 0; i < 6; i++) { - light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5); - } - - //compress to RGBE9995 to save space - - const float pow2to9 = 512.0f; - const float B = 15.0f; - const float N = 9.0f; - const float LN2 = 0.6931471805599453094172321215; - - float cRed = clamp(light_total.r, 0.0, 65408.0); - float cGreen = clamp(light_total.g, 0.0, 65408.0); - float cBlue = clamp(light_total.b, 0.0, 65408.0); - - float cMax = max(cRed, max(cGreen, cBlue)); - - float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B; - - float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f); - - float exps = expp + 1.0f; - - if (0.0 <= sMax && sMax < pow2to9) { - exps = expp; - } - - float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); - float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); - float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); - //store as 8985 to have 2 extra neighbour bits - uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25); - - imageStore(emission_grid, grid_pos, uvec4(light_rgbe)); - imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso)); - } - } - -#endif - -#ifdef MODE_RENDER_MATERIAL - - albedo_output_buffer.rgb = albedo; - albedo_output_buffer.a = alpha; - - normal_output_buffer.rgb = normal * 0.5 + 0.5; - normal_output_buffer.a = 0.0; - depth_output_buffer.r = -vertex.z; - - orm_output_buffer.r = ao; - orm_output_buffer.g = roughness; - orm_output_buffer.b = metallic; - orm_output_buffer.a = sss_strength; - - emission_output_buffer.rgb = emission; - emission_output_buffer.a = 0.0; -#endif - -#ifdef MODE_RENDER_NORMAL_ROUGHNESS - normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness); - -#ifdef MODE_RENDER_GIPROBE - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes - uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; - uint index2 = instances.data[instance_index].gi_offset >> 16; - giprobe_buffer.x = index1 & 0xFF; - giprobe_buffer.y = index2 & 0xFF; - } else { - giprobe_buffer.x = 0xFF; - giprobe_buffer.y = 0xFF; - } -#endif - -#endif //MODE_RENDER_NORMAL_ROUGHNESS - -//nothing happens, so a tree-ssa optimizer will result in no fragment shader :) -#else - - // multiply by albedo - diffuse_light *= albedo; // ambient must be multiplied by albedo at the end - - // apply direct light AO - ao = unpackUnorm4x8(orms).x; - specular_light *= ao; - diffuse_light *= ao; - - // apply metallic - metallic = unpackUnorm4x8(orms).z; - diffuse_light *= 1.0 - metallic; - ambient_light *= 1.0 - metallic; - - //restore fog - fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba)); - -#ifdef MODE_MULTIPLE_RENDER_TARGETS - -#ifdef MODE_UNSHADED - diffuse_buffer = vec4(albedo.rgb, 0.0); - specular_buffer = vec4(0.0); - -#else - -#ifdef SSS_MODE_SKIN - sss_strength = -sss_strength; -#endif - diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength); - specular_buffer = vec4(specular_light, metallic); -#endif - - diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); - specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); - -#else //MODE_MULTIPLE_RENDER_TARGETS - -#ifdef MODE_UNSHADED - frag_color = vec4(albedo, alpha); -#else - frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha); - //frag_color = vec4(1.0); -#endif //USE_NO_SHADING - - // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. - frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); - ; - -#endif //MODE_MULTIPLE_RENDER_TARGETS - -#endif //MODE_RENDER_DEPTH - } diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl new file mode 100644 index 0000000000..7b86dac143 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -0,0 +1,3293 @@ +#[vertex] + +#version 450 + +VERSION_DEFINES + +#include "scene_forward_clustered_inc.glsl" + +/* INPUT ATTRIBS */ + +layout(location = 0) in vec3 vertex_attrib; + +//only for pure render depth when normal is not used + +#ifdef NORMAL_USED +layout(location = 1) in vec3 normal_attrib; +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +layout(location = 2) in vec4 tangent_attrib; +#endif + +#if defined(COLOR_USED) +layout(location = 3) in vec4 color_attrib; +#endif + +#ifdef UV_USED +layout(location = 4) in vec2 uv_attrib; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL) +layout(location = 5) in vec2 uv2_attrib; +#endif + +#if defined(CUSTOM0_USED) +layout(location = 6) in vec4 custom0_attrib; +#endif + +#if defined(CUSTOM1_USED) +layout(location = 7) in vec4 custom1_attrib; +#endif + +#if defined(CUSTOM2_USED) +layout(location = 8) in vec4 custom2_attrib; +#endif + +#if defined(CUSTOM3_USED) +layout(location = 9) in vec4 custom3_attrib; +#endif + +#if defined(BONES_USED) +layout(location = 10) in uvec4 bone_attrib; +#endif + +#if defined(WEIGHTS_USED) +layout(location = 11) in vec4 weight_attrib; +#endif + +/* Varyings */ + +layout(location = 0) out vec3 vertex_interp; + +#ifdef NORMAL_USED +layout(location = 1) out vec3 normal_interp; +#endif + +#if defined(COLOR_USED) +layout(location = 2) out vec4 color_interp; +#endif + +#ifdef UV_USED +layout(location = 3) out vec2 uv_interp; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) +layout(location = 4) out vec2 uv2_interp; +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +layout(location = 5) out vec3 tangent_interp; +layout(location = 6) out vec3 binormal_interp; +#endif + +#ifdef USE_MATERIAL_UNIFORMS +layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ + /* clang-format off */ +MATERIAL_UNIFORMS + /* clang-format on */ +} material; +#endif + +invariant gl_Position; + +#ifdef MODE_DUAL_PARABOLOID + +layout(location = 8) out float dp_clip; + +#endif + +layout(location = 9) out flat uint instance_index; + +/* clang-format off */ + +VERTEX_SHADER_GLOBALS + +/* clang-format on */ + +void main() { + vec4 instance_custom = vec4(0.0); +#if defined(COLOR_USED) + color_interp = color_attrib; +#endif + + instance_index = draw_call.instance_index; + + bool is_multimesh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH); + if (!is_multimesh) { + instance_index += gl_InstanceIndex; + } + + mat4 world_matrix = instances.data[instance_index].transform; + + mat3 world_normal_matrix; + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { + world_normal_matrix = inverse(mat3(world_matrix)); + } else { + world_normal_matrix = mat3(world_matrix); + } + + if (is_multimesh) { + //multimesh, instances are for it + uint offset = (instances.data[instance_index].flags >> INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT) & INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK; + offset *= gl_InstanceIndex; + + mat4 matrix; + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + offset += 2; + } else { + matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], transforms.data[offset + 2], vec4(0.0, 0.0, 0.0, 1.0)); + offset += 3; + } + + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { +#ifdef COLOR_USED + color_interp *= transforms.data[offset]; +#endif + offset += 1; + } + + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { + instance_custom = transforms.data[offset]; + } + + //transpose + matrix = transpose(matrix); + world_matrix = world_matrix * matrix; + world_normal_matrix = world_normal_matrix * mat3(matrix); + } + + vec3 vertex = vertex_attrib; +#ifdef NORMAL_USED + vec3 normal = normal_attrib * 2.0 - 1.0; +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; + float binormalf = tangent_attrib.a * 2.0 - 1.0; + vec3 binormal = normalize(cross(normal, tangent) * binormalf); +#endif + +#if 0 + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) { + //multimesh, instances are for it + + uvec2 bones_01 = uvec2(bone_attrib.x & 0xFFFF, bone_attrib.x >> 16) * 3; + uvec2 bones_23 = uvec2(bone_attrib.y & 0xFFFF, bone_attrib.y >> 16) * 3; + vec2 weights_01 = unpackUnorm2x16(bone_attrib.z); + vec2 weights_23 = unpackUnorm2x16(bone_attrib.w); + + mat4 m = mat4(transforms.data[bones_01.x], transforms.data[bones_01.x + 1], transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x; + m += mat4(transforms.data[bones_01.y], transforms.data[bones_01.y + 1], transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y; + m += mat4(transforms.data[bones_23.x], transforms.data[bones_23.x + 1], transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; + m += mat4(transforms.data[bones_23.y], transforms.data[bones_23.y + 1], transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; + + //reverse order because its transposed + vertex = (vec4(vertex, 1.0) * m).xyz; + normal = (vec4(normal, 0.0) * m).xyz; + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + tangent = (vec4(tangent, 0.0) * m).xyz; + binormal = (vec4(binormal, 0.0) * m).xyz; +#endif + } +#endif + +#ifdef UV_USED + uv_interp = uv_attrib; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) + uv2_interp = uv2_attrib; +#endif + +#ifdef OVERRIDE_POSITION + vec4 position; +#endif + + mat4 projection_matrix = scene_data.projection_matrix; + +//using world coordinates +#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) + + vertex = (world_matrix * vec4(vertex, 1.0)).xyz; + + normal = world_normal_matrix * normal; + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + tangent = world_normal_matrix * tangent; + binormal = world_normal_matrix * binormal; + +#endif +#endif + + float roughness = 1.0; + + mat4 modelview = scene_data.inv_camera_matrix * world_matrix; + mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * world_normal_matrix; + + { + /* clang-format off */ + +VERTEX_SHADER_CODE + + /* clang-format on */ + } + +// using local coordinates (default) +#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED) + + vertex = (modelview * vec4(vertex, 1.0)).xyz; +#ifdef NORMAL_USED + normal = modelview_normal * normal; +#endif + +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + binormal = modelview_normal * binormal; + tangent = modelview_normal * tangent; +#endif + +//using world coordinates +#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) + + vertex = (scene_data.inv_camera_matrix * vec4(vertex, 1.0)).xyz; + normal = mat3(scene_data.inverse_normal_matrix) * normal; + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + binormal = mat3(scene_data.camera_inverse_binormal_matrix) * binormal; + tangent = mat3(scene_data.camera_inverse_tangent_matrix) * tangent; +#endif +#endif + + vertex_interp = vertex; +#ifdef NORMAL_USED + normal_interp = normal; +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + tangent_interp = tangent; + binormal_interp = binormal; +#endif + +#ifdef MODE_RENDER_DEPTH + +#ifdef MODE_DUAL_PARABOLOID + + vertex_interp.z *= scene_data.dual_paraboloid_side; + + dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias + + //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges + + vec3 vtx = vertex_interp; + float distance = length(vtx); + vtx = normalize(vtx); + vtx.xy /= 1.0 - vtx.z; + vtx.z = (distance / scene_data.z_far); + vtx.z = vtx.z * 2.0 - 1.0; + vertex_interp = vtx; + +#endif + +#endif //MODE_RENDER_DEPTH + +#ifdef OVERRIDE_POSITION + gl_Position = position; +#else + gl_Position = projection_matrix * vec4(vertex_interp, 1.0); +#endif + +#ifdef MODE_RENDER_DEPTH + if (scene_data.pancake_shadows) { + if (gl_Position.z <= 0.00001) { + gl_Position.z = 0.00001; + } + } +#endif +#ifdef MODE_RENDER_MATERIAL + if (scene_data.material_uv2_mode) { + vec2 uv_offset = unpackHalf2x16(draw_call.uv_offset); + gl_Position.xy = (uv2_attrib.xy + uv_offset) * 2.0 - 1.0; + gl_Position.z = 0.00001; + gl_Position.w = 1.0; + } +#endif +} + +#[fragment] + +#version 450 + +VERSION_DEFINES + +#include "scene_forward_clustered_inc.glsl" + +/* Varyings */ + +layout(location = 0) in vec3 vertex_interp; + +#ifdef NORMAL_USED +layout(location = 1) in vec3 normal_interp; +#endif + +#if defined(COLOR_USED) +layout(location = 2) in vec4 color_interp; +#endif + +#ifdef UV_USED +layout(location = 3) in vec2 uv_interp; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) +layout(location = 4) in vec2 uv2_interp; +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +layout(location = 5) in vec3 tangent_interp; +layout(location = 6) in vec3 binormal_interp; +#endif + +#ifdef MODE_DUAL_PARABOLOID + +layout(location = 8) in float dp_clip; + +#endif + +layout(location = 9) in flat uint instance_index; + +//defines to keep compatibility with vertex + +#define world_matrix instances.data[instance_index].transform +#define projection_matrix scene_data.projection_matrix + +#if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE) +//both required for transmittance to be enabled +#define LIGHT_TRANSMITTANCE_USED +#endif + +#ifdef USE_MATERIAL_UNIFORMS +layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ + /* clang-format off */ +MATERIAL_UNIFORMS + /* clang-format on */ +} material; +#endif + +/* clang-format off */ + +FRAGMENT_SHADER_GLOBALS + +/* clang-format on */ + +#ifdef MODE_RENDER_DEPTH + +#ifdef MODE_RENDER_MATERIAL + +layout(location = 0) out vec4 albedo_output_buffer; +layout(location = 1) out vec4 normal_output_buffer; +layout(location = 2) out vec4 orm_output_buffer; +layout(location = 3) out vec4 emission_output_buffer; +layout(location = 4) out float depth_output_buffer; + +#endif + +#ifdef MODE_RENDER_NORMAL_ROUGHNESS +layout(location = 0) out vec4 normal_roughness_output_buffer; + +#ifdef MODE_RENDER_GIPROBE +layout(location = 1) out uvec2 giprobe_buffer; +#endif + +#endif //MODE_RENDER_NORMAL +#else // RENDER DEPTH + +#ifdef MODE_MULTIPLE_RENDER_TARGETS + +layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness +layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter) +#else + +layout(location = 0) out vec4 frag_color; +#endif + +#endif // RENDER DEPTH + +#ifdef ALPHA_HASH_USED + +float hash_2d(vec2 p) { + return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) * + (0.1 + abs(sin(13.0 * p.y + p.x)))); +} + +float hash_3d(vec3 p) { + return hash_2d(vec2(hash_2d(p.xy), p.z)); +} + +float compute_alpha_hash_threshold(vec3 pos, float hash_scale) { + vec3 dx = dFdx(pos); + vec3 dy = dFdx(pos); + float delta_max_sqr = max(length(dx), length(dy)); + float pix_scale = 1.0 / (hash_scale * delta_max_sqr); + + vec2 pix_scales = + vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale)))); + + vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)), + hash_3d(floor(pix_scales.y * pos.xyz))); + + float lerp_factor = fract(log2(pix_scale)); + + float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y; + + float min_lerp = min(lerp_factor, 1.0 - lerp_factor); + + vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)), + (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp), + 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / + (2.0 * min_lerp * (1.0 - min_lerp)))); + + float alpha_hash_threshold = + (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z; + + return clamp(alpha_hash_threshold, 0.0, 1.0); +} + +#endif // ALPHA_HASH_USED + +#ifdef ALPHA_ANTIALIASING_EDGE_USED + +float calc_mip_level(vec2 texture_coord) { + vec2 dx = dFdx(texture_coord); + vec2 dy = dFdy(texture_coord); + float delta_max_sqr = max(dot(dx, dx), dot(dy, dy)); + return max(0.0, 0.5 * log2(delta_max_sqr)); +} + +float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) { + input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number + input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5; + return clamp(input_alpha, 0.0, 1.0); +} + +#endif // ALPHA_ANTIALIASING_USED + +// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. +// We're dividing this factor off because the overall term we'll end up looks like +// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): +// +// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) +// +// We're basically regouping this as +// +// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] +// +// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. +// +// The contents of the D and G (G1) functions (GGX) are taken from +// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). +// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). + +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +float G_GGX_2cos(float cos_theta_m, float alpha) { + // Schlick's approximation + // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) + // Eq. (19), although see Heitz (2014) the about the problems with his derivation. + // It nevertheless approximates GGX well with k = alpha/2. + float k = 0.5 * alpha; + return 0.5 / (cos_theta_m * (1.0 - k) + k); + + // float cos2 = cos_theta_m * cos_theta_m; + // float sin2 = (1.0 - cos2); + // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); +} + +float D_GGX(float cos_theta_m, float alpha) { + float alpha2 = alpha * alpha; + float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; + return alpha2 / (M_PI * d * d); +} + +float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float s_x = alpha_x * cos_phi; + float s_y = alpha_y * sin_phi; + return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); +} + +float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float r_x = cos_phi / alpha_x; + float r_y = sin_phi / alpha_y; + float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); + return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); +} + +float SchlickFresnel(float u) { + float m = 1.0 - u; + float m2 = m * m; + return m2 * m2 * m; // pow(m,5) +} + +float GTR1(float NdotH, float a) { + if (a >= 1.0) + return 1.0 / M_PI; + float a2 = a * a; + float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; + return (a2 - 1.0) / (M_PI * log(a2) * t); +} + +vec3 F0(float metallic, float specular, vec3 albedo) { + float dielectric = 0.16 * specular * specular; + // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; + // see https://google.github.io/filament/Filament.md.html + return mix(vec3(dielectric), albedo, vec3(metallic)); +} + +void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, + float transmittance_z, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, vec3 rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 B, vec3 T, float anisotropy, +#endif +#ifdef USE_SOFT_SHADOWS + float A, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, inout vec3 specular_light) { + +#if defined(USE_LIGHT_SHADER_CODE) + // light is written by the light shader + + vec3 normal = N; + vec3 light = L; + vec3 view = V; + + /* clang-format off */ + +LIGHT_SHADER_CODE + + /* clang-format on */ + +#else + +#ifdef USE_SOFT_SHADOWS + float NdotL = min(A + dot(N, L), 1.0); +#else + float NdotL = dot(N, L); +#endif + float cNdotL = max(NdotL, 0.0); // clamped NdotL + float NdotV = dot(N, V); + float cNdotV = max(NdotV, 0.0); + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) + vec3 H = normalize(V + L); +#endif + +#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#ifdef USE_SOFT_SHADOWS + float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); +#else + float cNdotH = clamp(dot(N, H), 0.0, 1.0); +#endif +#endif + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#ifdef USE_SOFT_SHADOWS + float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); +#else + float cLdotH = clamp(dot(L, H), 0.0, 1.0); +#endif +#endif + + float metallic = unpackUnorm4x8(orms).z; + if (metallic < 1.0) { + float roughness = unpackUnorm4x8(orms).y; + +#if defined(DIFFUSE_OREN_NAYAR) + vec3 diffuse_brdf_NL; +#else + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance +#endif + +#if defined(DIFFUSE_LAMBERT_WRAP) + // energy conserving lambert wrap shader + diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); +#elif defined(DIFFUSE_TOON) + + diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); + +#elif defined(DIFFUSE_BURLEY) + + { + float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; + float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); + float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); + diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; + /* + float energyBias = mix(roughness, 0.0, 0.5); + float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); + float fd90 = energyBias + 2.0 * VoH * VoH * roughness; + float f0 = 1.0; + float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); + float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); + + diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; + */ + } +#else + // lambert + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + diffuse_light += light_color * diffuse_brdf_NL * attenuation; + +#if defined(LIGHT_BACKLIGHT_USED) + diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; +#endif + +#if defined(LIGHT_RIM_USED) + float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); + diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color; +#endif + +#ifdef LIGHT_TRANSMITTANCE_USED + +#ifdef SSS_MODE_SKIN + + { + float scale = 8.25 / transmittance_depth; + float d = scale * abs(transmittance_z); + float dd = -d * d; + vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + + vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); + + diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); + } +#else + + if (transmittance_depth > 0.0) { + float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0); + + fade = pow(max(0.0, 1.0 - fade), transmittance_curve); + fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0); + + diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade; + } + +#endif //SSS_MODE_SKIN + +#endif //LIGHT_TRANSMITTANCE_USED + } + + float roughness = unpackUnorm4x8(orms).y; + if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely + + // D + +#if defined(SPECULAR_BLINN) + + //normalized blinn + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess) * cNdotL; + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float intensity = blinn; + + specular_light += light_color * intensity * attenuation * specular_amount; + +#elif defined(SPECULAR_PHONG) + + vec3 R = normalize(-reflect(L, N)); + float cRdotV = clamp(A + dot(R, V), 0.0, 1.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float phong = pow(cRdotV, shininess); + phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); + + specular_light += light_color * intensity * attenuation * specular_amount; + +#elif defined(SPECULAR_TOON) + + vec3 R = normalize(-reflect(L, N)); + float RdotV = dot(R, V); + float mid = 1.0 - roughness; + mid *= mid; + float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; + diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection + +#elif defined(SPECULAR_DISABLED) + // none.. + +#elif defined(SPECULAR_SCHLICK_GGX) + // shlick+ggx as default + +#if defined(LIGHT_ANISOTROPY_USED) + + float alpha_ggx = roughness * roughness; + float aspect = sqrt(1.0 - anisotropy * 0.9); + float ax = alpha_ggx / aspect; + float ay = alpha_ggx * aspect; + float XdotH = dot(T, H); + float YdotH = dot(B, H); + float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); + float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); + +#else + float alpha_ggx = roughness * roughness; + float D = D_GGX(cNdotH, alpha_ggx); + float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); +#endif + // F + float cLdotH5 = SchlickFresnel(cLdotH); + vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); + + vec3 specular_brdf_NL = cNdotL * D * F * G; + + specular_light += specular_brdf_NL * light_color * attenuation * specular_amount; +#endif + +#if defined(LIGHT_CLEARCOAT_USED) + +#if !defined(SPECULAR_SCHLICK_GGX) + float cLdotH5 = SchlickFresnel(cLdotH); +#endif + float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Fr = mix(.04, 1.0, cLdotH5); + float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); + + float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + + specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; +#endif + } + +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0)); +#endif + +#endif //defined(USE_LIGHT_SHADER_CODE) +} + +#ifndef USE_NO_SHADOWS + +// Interleaved Gradient Noise +// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare +float quick_hash(vec2 pos) { + const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); + return fract(magic.z * fract(dot(pos, magic.xy))); +} + +float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { + vec2 pos = coord.xy; + float depth = coord.z; + + //if only one sample is taken, take it from the center + if (scene_data.directional_soft_shadow_samples == 1) { + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + } + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float avg = 0.0; + + for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) { + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0)); + } + + return avg * (1.0 / float(scene_data.directional_soft_shadow_samples)); +} + +float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { + vec2 pos = coord.xy; + float depth = coord.z; + + //if only one sample is taken, take it from the center + if (scene_data.soft_shadow_samples == 1) { + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + } + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float avg = 0.0; + + for (uint i = 0; i < scene_data.soft_shadow_samples; i++) { + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0)); + } + + return avg * (1.0 / float(scene_data.soft_shadow_samples)); +} + +float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) { + //find blocker + float blocker_count = 0.0; + float blocker_average = 0.0; + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { + vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; + float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; + if (d < pssm_coord.z) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (pssm_coord.z - blocker_average) / blocker_average; + tex_scale *= penumbra; + + float s = 0.0; + for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { + vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; + s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0)); + } + + return s / float(scene_data.directional_penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + return 1.0; + } +} + +#endif //USE_NO_SHADOWS + +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + +float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { +#ifndef USE_NO_SHADOWS + if (omni_lights.data[idx].shadow_enabled) { + // there is a shadowmap + + vec3 light_rel_vec = omni_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + + vec4 v = vec4(vertex, 1.0); + + vec4 splane = (omni_lights.data[idx].shadow_matrix * v); + float shadow_len = length(splane.xyz); //need to remember shadow len from here + + { + vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius; + nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp)))); + v.xyz += nofs; + splane = (omni_lights.data[idx].shadow_matrix * v); + } + + float shadow; + +#ifdef USE_SOFT_SHADOWS + if (omni_lights.data[idx].soft_shadow_size > 0.0) { + //soft shadow + + //find blocker + + float blocker_count = 0.0; + float blocker_average = 0.0; + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + vec3 normal = normalize(splane.xyz); + vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); + vec3 tangent = normalize(cross(v0, normal)); + vec3 bitangent = normalize(cross(tangent, normal)); + float z_norm = shadow_len * omni_lights.data[idx].inv_radius; + + tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; + bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; + + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; + + vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; + + pos = normalize(pos); + vec4 uv_rect = omni_lights.data[idx].atlas_rect; + + if (pos.z >= 0.0) { + pos.z += 1.0; + uv_rect.y += uv_rect.w; + } else { + pos.z = 1.0 - pos.z; + } + + pos.xy /= pos.z; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + + float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r; + if (d < z_norm) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (z_norm - blocker_average) / blocker_average; + tangent *= penumbra; + bitangent *= penumbra; + + z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; + + shadow = 0.0; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; + vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; + + pos = normalize(pos); + vec4 uv_rect = omni_lights.data[idx].atlas_rect; + + if (pos.z >= 0.0) { + pos.z += 1.0; + uv_rect.y += uv_rect.w; + } else { + pos.z = 1.0 - pos.z; + } + + pos.xy /= pos.z; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0)); + } + + shadow /= float(scene_data.penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } + } else { +#endif + splane.xyz = normalize(splane.xyz); + vec4 clamp_rect = omni_lights.data[idx].atlas_rect; + + if (splane.z >= 0.0) { + splane.z += 1.0; + + clamp_rect.y += clamp_rect.w; + + } else { + splane.z = 1.0 - splane.z; + } + + splane.xy /= splane.z; + + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius; + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; //needed? i think it should be 1 already + shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); +#ifdef USE_SOFT_SHADOWS + } +#endif + + return shadow; + } +#endif + + return 1.0; +} + +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, vec3 rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, inout vec3 specular_light) { + vec3 light_rel_vec = omni_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation); + float light_attenuation = omni_attenuation; + vec3 color = omni_lights.data[idx].color; + +#ifdef USE_SOFT_SHADOWS + float size_A = 0.0; + + if (omni_lights.data[idx].size > 0.0) { + float t = omni_lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } +#endif + +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; //no transmittance by default + transmittance_color.a *= light_attenuation; + { + vec4 clamp_rect = omni_lights.data[idx].atlas_rect; + + //redo shadowmapping, but shrink the model a bit to avoid arctifacts + vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0)); + + shadow_len = length(splane.xyz); + splane = normalize(splane.xyz); + + if (splane.z >= 0.0) { + splane.z += 1.0; + + } else { + splane.z = 1.0 - splane.z; + } + + splane.xy /= splane.z; + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = shadow_len * omni_lights.data[idx].inv_radius; + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; //needed? i think it should be 1 already + + float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; + transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius; + } +#endif + +#if 0 + + if (omni_lights.data[idx].projector_rect != vec4(0.0)) { + vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; + local_v = normalize(local_v); + + vec4 atlas_rect = omni_lights.data[idx].projector_rect; + + if (local_v.z >= 0.0) { + local_v.z += 1.0; + atlas_rect.y += atlas_rect.w; + + } else { + local_v.z = 1.0 - local_v.z; + } + + local_v.xy /= local_v.z; + local_v.xy = local_v.xy * 0.5 + 0.5; + vec2 proj_uv = local_v.xy * atlas_rect.zw; + + vec2 proj_uv_ddx; + vec2 proj_uv_ddy; + { + vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz; + local_v_ddx = normalize(local_v_ddx); + + if (local_v_ddx.z >= 0.0) { + local_v_ddx.z += 1.0; + } else { + local_v_ddx.z = 1.0 - local_v_ddx.z; + } + + local_v_ddx.xy /= local_v_ddx.z; + local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5; + + proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv; + + vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz; + local_v_ddy = normalize(local_v_ddy); + + if (local_v_ddy.z >= 0.0) { + local_v_ddy.z += 1.0; + } else { + local_v_ddy.z = 1.0 - local_v_ddy.z; + } + + local_v_ddy.xy /= local_v_ddy.z; + local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5; + + proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv; + } + + vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy); + no_shadow = mix(no_shadow, proj.rgb, proj.a); + } +#endif + + light_attenuation *= shadow; + + light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, +#endif +#ifdef LIGHT_RIM_USED + rim * omni_attenuation, rim_tint, rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, +#endif +#ifdef USE_SOFT_SHADOWS + size_A, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, + specular_light); +} + +float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { +#ifndef USE_NO_SHADOWS + if (spot_lights.data[idx].shadow_enabled) { + vec3 light_rel_vec = spot_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + vec3 spot_dir = spot_lights.data[idx].direction; + //there is a shadowmap + vec4 v = vec4(vertex, 1.0); + + v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias; + + float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius; + + float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map + vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale; + normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z + v.xyz += normal_bias; + + //adjust with bias + z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius; + + float shadow; + + vec4 splane = (spot_lights.data[idx].shadow_matrix * v); + splane /= splane.w; + +#ifdef USE_SOFT_SHADOWS + if (spot_lights.data[idx].soft_shadow_size > 0.0) { + //soft shadow + + //find blocker + + vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; + + float blocker_count = 0.0; + float blocker_average = 0.0; + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale; + vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; + suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); + float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; + if (d < z_norm) { + blocker_average += d; + blocker_count += 1.0; + } + } + + if (blocker_count > 0.0) { + //blockers found, do soft shadow + blocker_average /= blocker_count; + float penumbra = (z_norm - blocker_average) / blocker_average; + uv_size *= penumbra; + + shadow = 0.0; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; + suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); + shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0)); + } + + shadow /= float(scene_data.penumbra_shadow_samples); + + } else { + //no blockers found, so no shadow + shadow = 1.0; + } + + } else { +#endif + //hard shadow + vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0); + + shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); +#ifdef USE_SOFT_SHADOWS + } +#endif + + return shadow; + } + +#endif //USE_NO_SHADOWS + + return 1.0; +} + +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, vec3 rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, + inout vec3 specular_light) { + vec3 light_rel_vec = spot_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation); + vec3 spot_dir = spot_lights.data[idx].direction; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[idx].cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[idx].cone_angle)); + spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation); + float light_attenuation = spot_attenuation; + vec3 color = spot_lights.data[idx].color; + float specular_amount = spot_lights.data[idx].specular_amount; + +#ifdef USE_SOFT_SHADOWS + float size_A = 0.0; + + if (spot_lights.data[idx].size > 0.0) { + float t = spot_lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } +#endif + + /* + if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) { + //use projector texture + } + */ + +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; + transmittance_color.a *= light_attenuation; + { + splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0)); + splane /= splane.w; + splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; + + float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; + //reconstruct depth + shadow_z /= spot_lights.data[idx].inv_radius; + //distance to light plane + float z = dot(spot_dir, -light_rel_vec); + transmittance_z = z - shadow_z; + } +#endif //LIGHT_TRANSMITTANCE_USED + + light_attenuation *= shadow; + + light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, +#endif +#ifdef LIGHT_RIM_USED + rim * spot_attenuation, rim_tint, rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, +#endif +#ifdef USE_SOFT_SHADOW + size_A, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, specular_light); +} + +void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughness, vec3 ambient_light, vec3 specular_light, inout vec4 ambient_accum, inout vec4 reflection_accum) { + vec3 box_extents = reflections.data[ref_index].box_extents; + vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz; + + if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box + return; + } + + vec3 ref_vec = normalize(reflect(vertex, normal)); + + vec3 inner_pos = abs(local_pos / box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + //make blend more rounded + blend = mix(length(inner_pos), blend, blend); + blend *= blend; + blend = max(0.0, 1.0 - blend); + + if (reflections.data[ref_index].intensity > 0.0) { // compute reflection + + vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; + + if (reflections.data[ref_index].box_project) { //box project + + vec3 nrdir = normalize(local_ref_vec); + vec3 rbmax = (box_extents - local_pos) / nrdir; + vec3 rbmin = (-box_extents - local_pos) / nrdir; + + vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0))); + + float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); + vec3 posonbox = local_pos + nrdir * fa; + local_ref_vec = posonbox - reflections.data[ref_index].box_offset; + } + + vec4 reflection; + + reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb; + + if (reflections.data[ref_index].exterior) { + reflection.rgb = mix(specular_light, reflection.rgb, blend); + } + + reflection.rgb *= reflections.data[ref_index].intensity; //intensity + reflection.a = blend; + reflection.rgb *= reflection.a; + + reflection_accum += reflection; + } + + switch (reflections.data[ref_index].ambient_mode) { + case REFLECTION_AMBIENT_DISABLED: { + //do nothing + } break; + case REFLECTION_AMBIENT_ENVIRONMENT: { + //do nothing + vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz; + + vec4 ambient_out; + + ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb; + ambient_out.a = blend; + if (reflections.data[ref_index].exterior) { + ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); + } + + ambient_out.rgb *= ambient_out.a; + ambient_accum += ambient_out; + } break; + case REFLECTION_AMBIENT_COLOR: { + vec4 ambient_out; + ambient_out.a = blend; + ambient_out.rgb = reflections.data[ref_index].ambient; + if (reflections.data[ref_index].exterior) { + ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); + } + ambient_out.rgb *= ambient_out.a; + ambient_accum += ambient_out; + } break; + } +} + +#ifdef USE_FORWARD_GI + +//standard voxel cone trace +vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) { + float dist = p_bias; + vec4 color = vec4(0.0); + + while (dist < max_distance && color.a < 0.95) { + float diameter = max(1.0, 2.0 * tan_half_angle * dist); + vec3 uvw_pos = (pos + dist * direction) * cell_size; + float half_diameter = diameter * 0.5; + //check if outside, then break + if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + half_diameter * cell_size)))) { + break; + } + vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter)); + float a = (1.0 - color.a); + color += a * scolor; + dist += half_diameter; + } + + return color; +} + +vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) { + float dist = p_bias; + vec4 color = vec4(0.0); + float radius = max(0.5, tan_half_angle * dist); + float lod_level = log2(radius * 2.0); + + while (dist < max_distance && color.a < 0.95) { + vec3 uvw_pos = (pos + dist * direction) * cell_size; + + //check if outside, then break + if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + radius * cell_size)))) { + break; + } + vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level); + lod_level += 1.0; + + float a = (1.0 - color.a); + scolor *= a; + color += scolor; + dist += radius; + radius = max(0.5, tan_half_angle * dist); + } + + return color; +} + +void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) { + position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz; + ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz); + normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz); + + position += normal * gi_probes.data[index].normal_bias; + + //this causes corrupted pixels, i have no idea why.. + if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) { + return; + } + + vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0); + float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0); + //float blend=1.0; + + float max_distance = length(gi_probes.data[index].bounds); + vec3 cell_size = 1.0 / gi_probes.data[index].bounds; + + //radiance + +#define MAX_CONE_DIRS 4 + + vec3 cone_dirs[MAX_CONE_DIRS] = vec3[]( + vec3(0.707107, 0.0, 0.707107), + vec3(0.0, 0.707107, 0.707107), + vec3(-0.707107, 0.0, 0.707107), + vec3(0.0, -0.707107, 0.707107)); + + float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25); + float cone_angle_tan = 0.98269; + + vec3 light = vec3(0.0); + + for (int i = 0; i < MAX_CONE_DIRS; i++) { + vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz); + + vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias); + + if (gi_probes.data[index].blend_ambient) { + cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95)); + } + + light += cone_weights[i] * cone_light.rgb; + } + + light *= gi_probes.data[index].dynamic_range; + out_diff += vec4(light * blend, blend); + + //irradiance + vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias); + if (gi_probes.data[index].blend_ambient) { + irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95)); + } + irr_light.rgb *= gi_probes.data[index].dynamic_range; + //irr_light=vec3(0.0); + + out_spec += vec4(irr_light.rgb * blend, blend); +} + +vec2 octahedron_wrap(vec2 v) { + vec2 signVal; + signVal.x = v.x >= 0.0 ? 1.0 : -1.0; + signVal.y = v.y >= 0.0 ? 1.0 : -1.0; + return (1.0 - abs(v.yx)) * signVal; +} + +vec2 octahedron_encode(vec3 n) { + // https://twitter.com/Stubbesaurus/status/937994790553227264 + n /= (abs(n.x) + abs(n.y) + abs(n.z)); + n.xy = n.z >= 0.0 ? n.xy : octahedron_wrap(n.xy); + n.xy = n.xy * 0.5 + 0.5; + return n.xy; +} + +void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, bool use_specular, float roughness, out vec3 diffuse_light, out vec3 specular_light, out float blend) { + cascade_pos += cam_normal * sdfgi.normal_bias; + + vec3 base_pos = floor(cascade_pos); + //cascade_pos += mix(vec3(0.0),vec3(0.01),lessThan(abs(cascade_pos-base_pos),vec3(0.01))) * cam_normal; + ivec3 probe_base_pos = ivec3(base_pos); + + vec4 diffuse_accum = vec4(0.0); + vec3 specular_accum; + + ivec3 tex_pos = ivec3(probe_base_pos.xy, int(cascade)); + tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size; + tex_pos.xy = tex_pos.xy * (SDFGI_OCT_SIZE + 2) + ivec2(1); + + vec3 diffuse_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size; + + vec3 specular_posf; + + if (use_specular) { + specular_accum = vec3(0.0); + specular_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_specular_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size; + } + + vec4 light_accum = vec4(0.0); + float weight_accum = 0.0; + + for (uint j = 0; j < 8; j++) { + ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); + ivec3 probe_posi = probe_base_pos; + probe_posi += offset; + + // Compute weight + + vec3 probe_pos = vec3(probe_posi); + vec3 probe_to_pos = cascade_pos - probe_pos; + vec3 probe_dir = normalize(-probe_to_pos); + + vec3 trilinear = vec3(1.0) - abs(probe_to_pos); + float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(cam_normal, probe_dir)); + + // Compute lightprobe occlusion + + if (sdfgi.use_occlusion) { + ivec3 occ_indexv = abs((sdfgi.cascades[cascade].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4); + vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3))); + + vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw; + occ_pos.z += float(cascade); + if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures + occ_pos.x += 1.0; + } + + occ_pos *= sdfgi.occlusion_renormalize; + float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, material_samplers[SAMPLER_LINEAR_CLAMP]), occ_pos, 0.0), occ_mask); + + weight *= max(occlusion, 0.01); + } + + // Compute lightprobe texture position + + vec3 diffuse; + vec3 pos_uvw = diffuse_posf; + pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy; + pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z; + diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb; + + diffuse_accum += vec4(diffuse * weight, weight); + + if (use_specular) { + vec3 specular = vec3(0.0); + vec3 pos_uvw = specular_posf; + pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy; + pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z; + if (roughness < 0.99) { + specular = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw + vec3(0, 0, float(sdfgi.max_cascades)), 0.0).rgb; + } + if (roughness > 0.5) { + specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0); + } + + specular_accum += specular * weight; + } + } + + if (diffuse_accum.a > 0.0) { + diffuse_accum.rgb /= diffuse_accum.a; + } + + diffuse_light = diffuse_accum.rgb; + + if (use_specular) { + if (diffuse_accum.a > 0.0) { + specular_accum /= diffuse_accum.a; + } + + specular_light = specular_accum; + } + + { + //process blend + float blend_from = (float(sdfgi.probe_axis_size - 1) / 2.0) - 2.5; + float blend_to = blend_from + 2.0; + + vec3 inner_pos = cam_pos * sdfgi.cascades[cascade].to_probe; + + float len = length(inner_pos); + + inner_pos = abs(normalize(inner_pos)); + len *= max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + + if (len >= blend_from) { + blend = smoothstep(blend_from, blend_to, len); + } else { + blend = 0.0; + } + } +} + +#endif //USE_FORWARD_GI + +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#ifndef MODE_RENDER_DEPTH + +#ifndef LOW_END_MODE + +vec4 volumetric_fog_process(vec2 screen_uv, float z) { + vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length); + if (fog_pos.z < 0.0) { + return vec4(0.0); + } else if (fog_pos.z < 1.0) { + fog_pos.z = pow(fog_pos.z, scene_data.volumetric_fog_detail_spread); + } + + return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); +} +#endif + +vec4 fog_process(vec3 vertex) { + vec3 fog_color = scene_data.fog_light_color; + + if (scene_data.fog_aerial_perspective > 0.0) { + vec3 sky_fog_color = vec3(0.0); + vec3 cube_view = scene_data.radiance_inverse_xform * vertex; + // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred + float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)); +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + float lod, blend; + blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod); + sky_fog_color = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod)).rgb; + sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod + 1)).rgb, blend); +#else + sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb; +#endif //USE_RADIANCE_CUBEMAP_ARRAY + fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective); + } + + if (scene_data.fog_sun_scatter > 0.001) { + vec4 sun_scatter = vec4(0.0); + float sun_total = 0.0; + vec3 view = normalize(vertex); + + for (uint i = 0; i < scene_data.directional_light_count; i++) { + vec3 light_color = directional_lights.data[i].color * directional_lights.data[i].energy; + float light_amount = pow(max(dot(view, directional_lights.data[i].direction), 0.0), 8.0); + fog_color += light_color * light_amount * scene_data.fog_sun_scatter; + } + } + + float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density)); + + if (abs(scene_data.fog_height_density) > 0.001) { + float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y; + + float y_dist = scene_data.fog_height - y; + + float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0); + + fog_amount = max(vfog_amount, fog_amount); + } + + return vec4(fog_color, fog_amount); +} + +void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { + uint item_min_max = cluster_buffer.data[p_offset]; + item_min = item_min_max & 0xFFFF; + item_max = item_min_max >> 16; + ; + + item_from = item_min >> 5; + item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements +} + +uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { + int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); + int mask_width = min(int(z_max) - int(z_min), 32 - local_min); + return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); +} + +float blur_shadow(float shadow) { + return shadow; +#if 0 + //disabling for now, will investigate later + float interp_shadow = shadow; + if (gl_HelperInvocation) { + interp_shadow = -4.0; // technically anything below -4 will do but just to make sure + } + + uvec2 fc2 = uvec2(gl_FragCoord.xy); + interp_shadow -= dFdx(interp_shadow) * (float(fc2.x & 1) - 0.5); + interp_shadow -= dFdy(interp_shadow) * (float(fc2.y & 1) - 0.5); + + if (interp_shadow >= 0.0) { + shadow = interp_shadow; + } + return shadow; +#endif +} + +#endif //!MODE_RENDER DEPTH + +void main() { +#ifdef MODE_DUAL_PARABOLOID + + if (dp_clip > 0.0) + discard; +#endif + + //lay out everything, whathever is unused is optimized away anyway + vec3 vertex = vertex_interp; + vec3 view = -normalize(vertex_interp); + vec3 albedo = vec3(1.0); + vec3 backlight = vec3(0.0); + vec4 transmittance_color = vec4(0.0); + float transmittance_depth = 0.0; + float transmittance_curve = 1.0; + float transmittance_boost = 0.0; + float metallic = 0.0; + float specular = 0.5; + vec3 emission = vec3(0.0); + float roughness = 1.0; + float rim = 0.0; + float rim_tint = 0.0; + float clearcoat = 0.0; + float clearcoat_gloss = 0.0; + float anisotropy = 0.0; + vec2 anisotropy_flow = vec2(1.0, 0.0); + vec4 fog = vec4(0.0); +#if defined(CUSTOM_RADIANCE_USED) + vec4 custom_radiance = vec4(0.0); +#endif +#if defined(CUSTOM_IRRADIANCE_USED) + vec4 custom_irradiance = vec4(0.0); +#endif + + float ao = 1.0; + float ao_light_affect = 0.0; + + float alpha = 1.0; + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec3 binormal = normalize(binormal_interp); + vec3 tangent = normalize(tangent_interp); +#else + vec3 binormal = vec3(0.0); + vec3 tangent = vec3(0.0); +#endif + +#ifdef NORMAL_USED + vec3 normal = normalize(normal_interp); + +#if defined(DO_SIDE_CHECK) + if (!gl_FrontFacing) { + normal = -normal; + } +#endif + +#endif //NORMAL_USED + +#ifdef UV_USED + vec2 uv = uv_interp; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) + vec2 uv2 = uv2_interp; +#endif + +#if defined(COLOR_USED) + vec4 color = color_interp; +#endif + +#if defined(NORMAL_MAP_USED) + + vec3 normal_map = vec3(0.5); +#endif + + float normal_map_depth = 1.0; + + vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size + scene_data.screen_pixel_size * 0.5; //account for center + + float sss_strength = 0.0; + +#ifdef ALPHA_SCISSOR_USED + float alpha_scissor_threshold = 1.0; +#endif // ALPHA_SCISSOR_USED + +#ifdef ALPHA_HASH_USED + float alpha_hash_scale = 1.0; +#endif // ALPHA_HASH_USED + +#ifdef ALPHA_ANTIALIASING_EDGE_USED + float alpha_antialiasing_edge = 0.0; + vec2 alpha_texture_coordinate = vec2(0.0, 0.0); +#endif // ALPHA_ANTIALIASING_EDGE_USED + + { + /* clang-format off */ + +FRAGMENT_SHADER_CODE + + /* clang-format on */ + } + +#ifdef LIGHT_TRANSMITTANCE_USED +#ifdef SSS_MODE_SKIN + transmittance_color.a = sss_strength; +#else + transmittance_color.a *= sss_strength; +#endif +#endif + +#ifndef USE_SHADOW_TO_OPACITY + +#ifdef ALPHA_SCISSOR_USED + if (alpha < alpha_scissor_threshold) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +// alpha hash can be used in unison with alpha antialiasing +#ifdef ALPHA_HASH_USED + if (alpha < compute_alpha_hash_threshold(vertex, alpha_hash_scale)) { + discard; + } +#endif // ALPHA_HASH_USED + +// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash +#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED) + alpha = 1.0; +#endif + +#ifdef ALPHA_ANTIALIASING_EDGE_USED +// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather +#ifdef ALPHA_SCISSOR_USED + alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0); +#endif + alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge); +#endif // ALPHA_ANTIALIASING_EDGE_USED + +#ifdef USE_OPAQUE_PREPASS + if (alpha < opaque_prepass_threshold) { + discard; + } +#endif // USE_OPAQUE_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY + +#ifdef NORMAL_MAP_USED + + normal_map.xy = normal_map.xy * 2.0 - 1.0; + normal_map.z = sqrt(max(0.0, 1.0 - dot(normal_map.xy, normal_map.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. + + normal = normalize(mix(normal, tangent * normal_map.x + binormal * normal_map.y + normal * normal_map.z, normal_map_depth)); + +#endif + +#ifdef LIGHT_ANISOTROPY_USED + + if (anisotropy > 0.01) { + //rotation matrix + mat3 rot = mat3(tangent, binormal, normal); + //make local to space + tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0)); + binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0)); + } + +#endif + +#ifdef ENABLE_CLIP_ALPHA + if (albedo.a < 0.99) { + //used for doublepass and shadowmapping + discard; + } +#endif + + /////////////////////// FOG ////////////////////// +#ifndef MODE_RENDER_DEPTH + +#ifndef CUSTOM_FOG_USED + // fog must be processed as early as possible and then packed. + // to maximize VGPR usage + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + + if (scene_data.fog_enabled) { + fog = fog_process(vertex); + } + +#ifndef LOW_END_MODE + if (scene_data.volumetric_fog_enabled) { + vec4 volumetric_fog = volumetric_fog_process(screen_uv, -vertex.z); + if (scene_data.fog_enabled) { + //must use the full blending equation here to blend fogs + vec4 res; + float sa = 1.0 - volumetric_fog.a; + res.a = fog.a * sa + volumetric_fog.a; + if (res.a == 0.0) { + res.rgb = vec3(0.0); + } else { + res.rgb = (fog.rgb * fog.a * sa + volumetric_fog.rgb * volumetric_fog.a) / res.a; + } + fog = res; + } else { + fog = volumetric_fog; + } + } +#endif //!LOW_END_MODE +#endif //!CUSTOM_FOG_USED + + uint fog_rg = packHalf2x16(fog.rg); + uint fog_ba = packHalf2x16(fog.ba); + +#endif //!MODE_RENDER_DEPTH + + /////////////////////// DECALS //////////////////////////////// + +#ifndef MODE_RENDER_DEPTH + + uvec2 cluster_pos = uvec2(gl_FragCoord.xy) >> scene_data.cluster_shift; + uint cluster_offset = (scene_data.cluster_width * cluster_pos.y + cluster_pos.x) * (scene_data.max_cluster_element_count_div_32 + 32); + + uint cluster_z = uint(clamp((-vertex.z / scene_data.z_far) * 32.0, 0.0, 31.0)); + + //used for interpolating anything cluster related + vec3 vertex_ddx = dFdx(vertex); + vec3 vertex_ddy = dFdy(vertex); + + { // process decals + + uint cluster_decal_offset = cluster_offset + scene_data.cluster_type_size * 2; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_decal_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_decal_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint decal_index = 32 * i + bit; + + if (!bool(decals.data[decal_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; + if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { + continue; //out of decal + } + + //we need ddx/ddy for mipmaps, so simulate them + vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz; + vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz; + + float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade); + + if (decals.data[decal_index].normal_fade > 0.0) { + fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5); + } + + if (decals.data[decal_index].albedo_rect != vec4(0.0)) { + //has albedo + vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw); + decal_albedo *= decals.data[decal_index].modulate; + decal_albedo.a *= fade; + albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix); + + if (decals.data[decal_index].normal_rect != vec4(0.0)) { + vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz; + decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software + decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy))); + //convert to view space, use xzy because y is up + decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; + + normal = normalize(mix(normal, decal_normal, decal_albedo.a)); + } + + if (decals.data[decal_index].orm_rect != vec4(0.0)) { + vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz; + ao = mix(ao, decal_orm.r, decal_albedo.a); + roughness = mix(roughness, decal_orm.g, decal_albedo.a); + metallic = mix(metallic, decal_orm.b, decal_albedo.a); + } + } + + if (decals.data[decal_index].emission_rect != vec4(0.0)) { + //emission is additive, so its independent from albedo + emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade; + } + } + } + } + + //pack albedo until needed again, saves 2 VGPRs in the meantime + +#endif //not render depth + /////////////////////// LIGHTING ////////////////////////////// + +#ifdef NORMAL_USED + if (scene_data.roughness_limiter_enabled) { + //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf + float roughness2 = roughness * roughness; + vec3 dndu = dFdx(normal), dndv = dFdx(normal); + float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv)); + float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect + float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2); + roughness = sqrt(filteredRoughness2); + } +#endif + //apply energy conservation + + vec3 specular_light = vec3(0.0, 0.0, 0.0); + vec3 diffuse_light = vec3(0.0, 0.0, 0.0); + vec3 ambient_light = vec3(0.0, 0.0, 0.0); + +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + + if (scene_data.use_reflection_cubemap) { + vec3 ref_vec = reflect(-view, normal); + ref_vec = scene_data.radiance_inverse_xform * ref_vec; +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + + float lod, blend; + blend = modf(roughness * MAX_ROUGHNESS_LOD, lod); + specular_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb; + specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend); + +#else + specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb; + +#endif //USE_RADIANCE_CUBEMAP_ARRAY + specular_light *= scene_data.ambient_light_color_energy.a; + } + +#if defined(CUSTOM_RADIANCE_USED) + specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a); +#endif + +#ifndef USE_LIGHTMAP + //lightmap overrides everything + if (scene_data.use_ambient_light) { + ambient_light = scene_data.ambient_light_color_energy.rgb; + + if (scene_data.use_ambient_cubemap) { + vec3 ambient_dir = scene_data.radiance_inverse_xform * normal; +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb; +#else + vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ambient_dir, MAX_ROUGHNESS_LOD).rgb; +#endif //USE_RADIANCE_CUBEMAP_ARRAY + + ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix); + } + } +#endif // USE_LIGHTMAP +#if defined(CUSTOM_IRRADIANCE_USED) + ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a); +#endif +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + + //radiance + +/// GI /// +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#ifdef USE_LIGHTMAP + + //lightmap + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture + uint index = instances.data[instance_index].gi_offset; + + vec3 wnormal = mat3(scene_data.camera_matrix) * normal; + const float c1 = 0.429043; + const float c2 = 0.511664; + const float c3 = 0.743125; + const float c4 = 0.886227; + const float c5 = 0.247708; + ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) + + c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z + + c4 * lightmap_captures.data[index].sh[0].rgb - + c5 * lightmap_captures.data[index].sh[6].rgb + + 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y + + 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z + + 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z + + 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x + + 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y + + 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z); + + } else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap + bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); + uint ofs = instances.data[instance_index].gi_offset & 0xFFFF; + vec3 uvw; + uvw.xy = uv2 * instances.data[instance_index].lightmap_uv_scale.zw + instances.data[instance_index].lightmap_uv_scale.xy; + uvw.z = float((instances.data[instance_index].gi_offset >> 16) & 0xFFFF); + + if (uses_sh) { + uvw.z *= 4.0; //SH textures use 4 times more data + vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb; + vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb; + vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb; + vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb; + + uint idx = instances.data[instance_index].gi_offset >> 20; + vec3 n = normalize(lightmaps.data[idx].normal_xform * normal); + + ambient_light += lm_light_l0 * 0.282095f; + ambient_light += lm_light_l1n1 * 0.32573 * n.y; + ambient_light += lm_light_l1_0 * 0.32573 * n.z; + ambient_light += lm_light_l1p1 * 0.32573 * n.x; + if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick + vec3 r = reflect(normalize(-vertex), normal); + specular_light += lm_light_l1n1 * 0.32573 * r.y; + specular_light += lm_light_l1_0 * 0.32573 * r.z; + specular_light += lm_light_l1p1 * 0.32573 * r.x; + } + + } else { + ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb; + } + } +#elif defined(USE_FORWARD_GI) + + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture + + //make vertex orientation the world one, but still align to camera + vec3 cam_pos = mat3(scene_data.camera_matrix) * vertex; + vec3 cam_normal = mat3(scene_data.camera_matrix) * normal; + vec3 cam_reflection = mat3(scene_data.camera_matrix) * reflect(-view, normal); + + //apply y-mult + cam_pos.y *= sdfgi.y_mult; + cam_normal.y *= sdfgi.y_mult; + cam_normal = normalize(cam_normal); + cam_reflection.y *= sdfgi.y_mult; + cam_normal = normalize(cam_normal); + cam_reflection = normalize(cam_reflection); + + vec4 light_accum = vec4(0.0); + float weight_accum = 0.0; + + vec4 light_blend_accum = vec4(0.0); + float weight_blend_accum = 0.0; + + float blend = -1.0; + + // helper constants, compute once + + uint cascade = 0xFFFFFFFF; + vec3 cascade_pos; + vec3 cascade_normal; + + for (uint i = 0; i < sdfgi.max_cascades; i++) { + cascade_pos = (cam_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe; + + if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) { + continue; //skip cascade + } + + cascade = i; + break; + } + + if (cascade < SDFGI_MAX_CASCADES) { + bool use_specular = true; + float blend; + vec3 diffuse, specular; + sdfgi_process(cascade, cascade_pos, cam_pos, cam_normal, cam_reflection, use_specular, roughness, diffuse, specular, blend); + + if (blend > 0.0) { + //blend + if (cascade == sdfgi.max_cascades - 1) { + diffuse = mix(diffuse, ambient_light, blend); + if (use_specular) { + specular = mix(specular, specular_light, blend); + } + } else { + vec3 diffuse2, specular2; + float blend2; + cascade_pos = (cam_pos - sdfgi.cascades[cascade + 1].position) * sdfgi.cascades[cascade + 1].to_probe; + sdfgi_process(cascade + 1, cascade_pos, cam_pos, cam_normal, cam_reflection, use_specular, roughness, diffuse2, specular2, blend2); + diffuse = mix(diffuse, diffuse2, blend); + if (use_specular) { + specular = mix(specular, specular2, blend); + } + } + } + + ambient_light = diffuse; + if (use_specular) { + specular_light = specular; + } + } + } + + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes + + uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; + vec3 ref_vec = normalize(reflect(normalize(vertex), normal)); + //find arbitrary tangent and bitangent, then build a matrix + vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); + vec3 tangent = normalize(cross(v0, normal)); + vec3 bitangent = normalize(cross(tangent, normal)); + mat3 normal_mat = mat3(tangent, bitangent, normal); + + vec4 amb_accum = vec4(0.0); + vec4 spec_accum = vec4(0.0); + gi_probe_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); + + uint index2 = instances.data[instance_index].gi_offset >> 16; + + if (index2 != 0xFFFF) { + gi_probe_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); + } + + if (amb_accum.a > 0.0) { + amb_accum.rgb /= amb_accum.a; + } + + if (spec_accum.a > 0.0) { + spec_accum.rgb /= spec_accum.a; + } + + specular_light = spec_accum.rgb; + ambient_light = amb_accum.rgb; + } +#elif !defined(LOW_END_MODE) + + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers + + vec2 coord; + + if (scene_data.gi_upscale_for_msaa) { + vec2 base_coord = screen_uv; + vec2 closest_coord = base_coord; + float closest_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord, 0.0).xyz * 2.0 - 1.0); + + for (int i = 0; i < 4; i++) { + const vec2 neighbours[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1)); + vec2 neighbour_coord = base_coord + neighbours[i] * scene_data.screen_pixel_size; + float neighbour_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), neighbour_coord, 0.0).xyz * 2.0 - 1.0); + if (neighbour_ang > closest_ang) { + closest_ang = neighbour_ang; + closest_coord = neighbour_coord; + } + } + + coord = closest_coord; + + } else { + coord = screen_uv; + } + + vec4 buffer_ambient = textureLod(sampler2D(ambient_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0.0); + vec4 buffer_reflection = textureLod(sampler2D(reflection_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0.0); + + ambient_light = mix(ambient_light, buffer_ambient.rgb, buffer_ambient.a); + specular_light = mix(specular_light, buffer_reflection.rgb, buffer_reflection.a); + } +#endif + +#ifndef LOW_END_MODE + if (scene_data.ssao_enabled) { + float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; + ao = min(ao, ssao); + ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); + } +#endif //LOW_END_MODE + + { // process reflections + + vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); + vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); + + uint cluster_reflection_offset = cluster_offset + scene_data.cluster_type_size * 3; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_reflection_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_reflection_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint reflection_index = 32 * i + bit; + + if (!bool(reflections.data[reflection_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); + } + } + + if (reflection_accum.a > 0.0) { + specular_light = reflection_accum.rgb / reflection_accum.a; + } + +#if !defined(USE_LIGHTMAP) + if (ambient_accum.a > 0.0) { + ambient_light = ambient_accum.rgb / ambient_accum.a; + } +#endif + } + + //finalize ambient light here + ambient_light *= albedo.rgb; + ambient_light *= ao; + + // convert ao to direct light ao + ao = mix(1.0, ao, ao_light_affect); + + //this saves some VGPRs + vec3 f0 = F0(metallic, specular, albedo); + + { +#if defined(DIFFUSE_TOON) + //simplify for toon, as + specular_light *= specular * metallic * albedo * 2.0; +#else + + // scales the specular reflections, needs to be be computed before lighting happens, + // but after environment, GI, and reflection probes are added + // Environment brdf approximation (Lazarov 2013) + // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile + const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); + vec4 r = roughness * c0 + c1; + float ndotv = clamp(dot(normal, view), 0.0, 1.0); + float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; + + specular_light *= env.x * f0 + env.y; +#endif + } + +#endif //GI !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#if !defined(MODE_RENDER_DEPTH) + //this saves some VGPRs + uint orms = packUnorm4x8(vec4(ao, roughness, metallic, specular)); +#endif + +// LIGHTING +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + + { //directional light + + // Do shadow and lighting in two passes to reduce register pressure + uint shadow0 = 0; + uint shadow1 = 0; + + for (uint i = 0; i < 8; i++) { + if (i >= scene_data.directional_light_count) { + break; + } + + if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + float shadow = 1.0; + +#ifdef USE_SOFT_SHADOWS + //version with soft shadows, more expensive + if (directional_lights.data[i].shadow_enabled) { + float depth_z = -vertex.z; + + vec4 pssm_coord; + vec3 shadow_color = vec3(0.0); + vec3 light_dir = directional_lights.data[i].direction; + +#define BIAS_FUNC(m_var, m_idx) \ + m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ + vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \ + normal_bias -= light_dir * dot(light_dir, normal_bias); \ + m_var.xyz += normal_bias; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 0) + + pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.x; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color1.rgb; + + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 1) + + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.y; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color2.rgb; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 2) + + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.z; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color3.rgb; + + } else { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 3) + + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.w; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + shadow_color = directional_lights.data[i].shadow_color4.rgb; + } + + if (directional_lights.data[i].blend_splits) { + vec3 shadow_color_blend = vec3(0.0); + float pssm_blend; + float shadow2; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 1) + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.y; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); + shadow_color_blend = directional_lights.data[i].shadow_color2.rgb; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 2) + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_coord /= pssm_coord.w; + + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.z; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); + + shadow_color_blend = directional_lights.data[i].shadow_color3.rgb; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 3) + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_coord /= pssm_coord.w; + if (directional_lights.data[i].softshadow_angle > 0) { + float range_pos = dot(directional_lights.data[i].direction, v.xyz); + float range_begin = directional_lights.data[i].shadow_range_begin.w; + float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; + vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); + } else { + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + } + + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); + shadow_color_blend = directional_lights.data[i].shadow_color4.rgb; + } else { + pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) + } + + pssm_blend = sqrt(pssm_blend); + + shadow = mix(shadow, shadow2, pssm_blend); + shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend); + } + + shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance + +#undef BIAS_FUNC + } +#else + // Soft shadow disabled version + + if (directional_lights.data[i].shadow_enabled) { + float depth_z = -vertex.z; + + vec4 pssm_coord; + vec3 light_dir = directional_lights.data[i].direction; + vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))); + +#define BIAS_FUNC(m_var, m_idx) \ + m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ + vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \ + normal_bias -= light_dir * dot(light_dir, normal_bias); \ + m_var.xyz += normal_bias; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 0) + + pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; + + transmittance_z = z - shadow_z; + } +#endif + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 1) + + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; + + transmittance_z = z - shadow_z; + } +#endif + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 2) + + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; + + transmittance_z = z - shadow_z; + } +#endif + + } else { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 3) + + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; + + transmittance_z = z - shadow_z; + } +#endif + } + + pssm_coord /= pssm_coord.w; + + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + + if (directional_lights.data[i].blend_splits) { + float pssm_blend; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 1) + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 2) + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 3) + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); + } else { + pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) + } + + pssm_coord /= pssm_coord.w; + + float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + shadow = mix(shadow, shadow2, pssm_blend); + } + + shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance + +#undef BIAS_FUNC + } +#endif + + if (i < 4) { + shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8); + } else { + shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8); + } + } + + for (uint i = 0; i < 8; i++) { + if (i >= scene_data.directional_light_count) { + break; + } + + if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; + + if (directional_lights.data[i].shadow_enabled) { + float depth_z = -vertex.z; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; + + transmittance_z = z - shadow_z; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; + + transmittance_z = z - shadow_z; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; + + transmittance_z = z - shadow_z; + + } else { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; + + transmittance_z = z - shadow_z; + } +#endif + + float shadow = 1.0; + + if (i < 4) { + shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0; + } else { + shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; + } + + blur_shadow(shadow); + + light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, +#endif +#ifdef LIGHT_RIM_USED + rim, rim_tint, albedo, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, +#endif +#ifdef USE_SOFT_SHADOW + directional_lights.data[i].size, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, + specular_light); + } + } + + { //omni lights + + uint cluster_omni_offset = cluster_offset; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_omni_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint light_index = 32 * i + bit; + + if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + float shadow = light_process_omni_shadow(light_index, vertex, view); + + shadow = blur_shadow(shadow); + + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + rim, + rim_tint, + albedo, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + tangent, binormal, anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, specular_light); + } + } + } + + { //spot lights + + uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_spot_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + + uint light_index = 32 * i + bit; + + if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } + + float shadow = light_process_spot_shadow(light_index, vertex, view); + + shadow = blur_shadow(shadow); + + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + rim, + rim_tint, + albedo, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + tangent, binormal, anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + alpha, +#endif + diffuse_light, specular_light); + } + } + } + +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + +#if defined(ALPHA_SCISSOR_USED) + if (alpha < alpha_scissor) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_OPAQUE_PREPASS + + if (alpha < opaque_prepass_threshold) { + discard; + } + +#endif // USE_OPAQUE_PREPASS + +#endif // USE_SHADOW_TO_OPACITY + +#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#ifdef MODE_RENDER_DEPTH + +#ifdef MODE_RENDER_SDF + + { + vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz; + ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size)); + + uint albedo16 = 0x1; //solid flag + albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11; + albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6; + albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1; + + imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16)); + + uint facing_bits = 0; + const vec3 aniso_dir[6] = vec3[]( + vec3(1, 0, 0), + vec3(0, 1, 0), + vec3(0, 0, 1), + vec3(-1, 0, 0), + vec3(0, -1, 0), + vec3(0, 0, -1)); + + vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp); + + float closest_dist = -1e20; + + for (uint i = 0; i < 6; i++) { + float d = dot(cam_normal, aniso_dir[i]); + if (d > closest_dist) { + closest_dist = d; + facing_bits = (1 << i); + } + } + + imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits + + if (length(emission) > 0.001) { + float lumas[6]; + vec3 light_total = vec3(0); + + for (int i = 0; i < 6; i++) { + float strength = max(0.0, dot(cam_normal, aniso_dir[i])); + vec3 light = emission * strength; + light_total += light; + lumas[i] = max(light.r, max(light.g, light.b)); + } + + float luma_total = max(light_total.r, max(light_total.g, light_total.b)); + + uint light_aniso = 0; + + for (int i = 0; i < 6; i++) { + light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5); + } + + //compress to RGBE9995 to save space + + const float pow2to9 = 512.0f; + const float B = 15.0f; + const float N = 9.0f; + const float LN2 = 0.6931471805599453094172321215; + + float cRed = clamp(light_total.r, 0.0, 65408.0); + float cGreen = clamp(light_total.g, 0.0, 65408.0); + float cBlue = clamp(light_total.b, 0.0, 65408.0); + + float cMax = max(cRed, max(cGreen, cBlue)); + + float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B; + + float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f); + + float exps = expp + 1.0f; + + if (0.0 <= sMax && sMax < pow2to9) { + exps = expp; + } + + float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); + float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); + float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); + //store as 8985 to have 2 extra neighbour bits + uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25); + + imageStore(emission_grid, grid_pos, uvec4(light_rgbe)); + imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso)); + } + } + +#endif + +#ifdef MODE_RENDER_MATERIAL + + albedo_output_buffer.rgb = albedo; + albedo_output_buffer.a = alpha; + + normal_output_buffer.rgb = normal * 0.5 + 0.5; + normal_output_buffer.a = 0.0; + depth_output_buffer.r = -vertex.z; + + orm_output_buffer.r = ao; + orm_output_buffer.g = roughness; + orm_output_buffer.b = metallic; + orm_output_buffer.a = sss_strength; + + emission_output_buffer.rgb = emission; + emission_output_buffer.a = 0.0; +#endif + +#ifdef MODE_RENDER_NORMAL_ROUGHNESS + normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness); + +#ifdef MODE_RENDER_GIPROBE + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes + uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; + uint index2 = instances.data[instance_index].gi_offset >> 16; + giprobe_buffer.x = index1 & 0xFF; + giprobe_buffer.y = index2 & 0xFF; + } else { + giprobe_buffer.x = 0xFF; + giprobe_buffer.y = 0xFF; + } +#endif + +#endif //MODE_RENDER_NORMAL_ROUGHNESS + +//nothing happens, so a tree-ssa optimizer will result in no fragment shader :) +#else + + // multiply by albedo + diffuse_light *= albedo; // ambient must be multiplied by albedo at the end + + // apply direct light AO + ao = unpackUnorm4x8(orms).x; + specular_light *= ao; + diffuse_light *= ao; + + // apply metallic + metallic = unpackUnorm4x8(orms).z; + diffuse_light *= 1.0 - metallic; + ambient_light *= 1.0 - metallic; + + //restore fog + fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba)); + +#ifdef MODE_MULTIPLE_RENDER_TARGETS + +#ifdef MODE_UNSHADED + diffuse_buffer = vec4(albedo.rgb, 0.0); + specular_buffer = vec4(0.0); + +#else + +#ifdef SSS_MODE_SKIN + sss_strength = -sss_strength; +#endif + diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength); + specular_buffer = vec4(specular_light, metallic); +#endif + + diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); + specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); + +#else //MODE_MULTIPLE_RENDER_TARGETS + +#ifdef MODE_UNSHADED + frag_color = vec4(albedo, alpha); +#else + frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha); + //frag_color = vec4(1.0); +#endif //USE_NO_SHADING + + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); + ; + +#endif //MODE_MULTIPLE_RENDER_TARGETS + +#endif //MODE_RENDER_DEPTH + } diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl new file mode 100644 index 0000000000..d78890fa9e --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl @@ -0,0 +1,352 @@ +#define M_PI 3.14159265359 +#define ROUGHNESS_MAX_LOD 5 + +#define MAX_GI_PROBES 8 + +#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) + +#extension GL_KHR_shader_subgroup_ballot : enable +#extension GL_KHR_shader_subgroup_arithmetic : enable + +#define USE_SUBGROUPS + +#endif + +#include "cluster_data_inc.glsl" + +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_GIPROBE) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) +#ifndef NORMAL_USED +#define NORMAL_USED +#endif +#endif + +layout(push_constant, binding = 0, std430) uniform DrawCall { + uint instance_index; + uint uv_offset; + uint pad0; + uint pad1; +} +draw_call; + +/* Set 0 Scene data that never changes, ever */ + +#define SAMPLER_NEAREST_CLAMP 0 +#define SAMPLER_LINEAR_CLAMP 1 +#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 +#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 +#define SAMPLER_NEAREST_REPEAT 6 +#define SAMPLER_LINEAR_REPEAT 7 +#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 +#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 + +#define SDFGI_MAX_CASCADES 8 + +/* Set 1: Base Pass (never changes) */ + +layout(set = 0, binding = 1) uniform sampler material_samplers[12]; + +layout(set = 0, binding = 2) uniform sampler shadow_sampler; + +#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6) +#define INSTANCE_FLAGS_USE_SDFGI (1 << 7) +#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8) +#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9) +#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10) +#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11) +#define INSTANCE_FLAGS_MULTIMESH (1 << 12) +#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) +#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) +#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15) +#define INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT 16 +//3 bits of stride +#define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7 + +#define INSTANCE_FLAGS_SKELETON (1 << 19) +#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 20) + +layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { + LightData data[]; +} +omni_lights; + +layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { + LightData data[]; +} +spot_lights; + +layout(set = 0, binding = 5) buffer restrict readonly ReflectionProbeData { + ReflectionData data[]; +} +reflections; + +layout(set = 0, binding = 6, std140) uniform DirectionalLights { + DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +} +directional_lights; + +#define LIGHTMAP_FLAG_USE_DIRECTION 1 +#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2 + +struct Lightmap { + mat3 normal_xform; +}; + +layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps { + Lightmap data[]; +} +lightmaps; + +struct LightmapCapture { + vec4 sh[9]; +}; + +layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures { + LightmapCapture data[]; +} +lightmap_captures; + +layout(set = 0, binding = 9) uniform texture2D decal_atlas; +layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb; + +layout(set = 0, binding = 11, std430) restrict readonly buffer Decals { + DecalData data[]; +} +decals; + +layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; +} +global_variables; + +#ifndef LOW_END_MODE + +struct SDFGIProbeCascadeData { + vec3 position; + float to_probe; + ivec3 probe_world_offset; + float to_cell; // 1/bounds * grid_size +}; + +layout(set = 0, binding = 13, std140) uniform SDFGI { + vec3 grid_size; + uint max_cascades; + + bool use_occlusion; + int probe_axis_size; + float probe_to_uvw; + float normal_bias; + + vec3 lightprobe_tex_pixel_size; + float energy; + + vec3 lightprobe_uv_offset; + float y_mult; + + vec3 occlusion_clamp; + uint pad3; + + vec3 occlusion_renormalize; + uint pad4; + + vec3 cascade_probe_size; + uint pad5; + + SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES]; +} +sdfgi; + +#endif //LOW_END_MODE + +/* Set 2: Render Pass (changes per render pass) */ + +layout(set = 1, binding = 0, std140) uniform SceneData { + mat4 projection_matrix; + mat4 inv_projection_matrix; + + mat4 camera_matrix; + mat4 inv_camera_matrix; + + vec2 viewport_size; + vec2 screen_pixel_size; + + uint cluster_shift; + uint cluster_width; + uint cluster_type_size; + uint max_cluster_element_count_div_32; + + //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted + vec4 directional_penumbra_shadow_kernel[32]; + vec4 directional_soft_shadow_kernel[32]; + vec4 penumbra_shadow_kernel[32]; + vec4 soft_shadow_kernel[32]; + + uint directional_penumbra_shadow_samples; + uint directional_soft_shadow_samples; + uint penumbra_shadow_samples; + uint soft_shadow_samples; + + vec4 ambient_light_color_energy; + + float ambient_color_sky_mix; + bool use_ambient_light; + bool use_ambient_cubemap; + bool use_reflection_cubemap; + + mat3 radiance_inverse_xform; + + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + + uint directional_light_count; + float dual_paraboloid_side; + float z_far; + float z_near; + + bool ssao_enabled; + float ssao_light_affect; + float ssao_ao_affect; + bool roughness_limiter_enabled; + + float roughness_limiter_amount; + float roughness_limiter_limit; + uvec2 roughness_limiter_pad; + + vec4 ao_color; + + mat4 sdf_to_bounds; + + ivec3 sdf_offset; + bool material_uv2_mode; + + ivec3 sdf_size; + bool gi_upscale_for_msaa; + + bool volumetric_fog_enabled; + float volumetric_fog_inv_length; + float volumetric_fog_detail_spread; + uint volumetric_fog_pad; + + bool fog_enabled; + float fog_density; + float fog_height; + float fog_height_density; + + vec3 fog_light_color; + float fog_sun_scatter; + + float fog_aerial_perspective; + + float time; + float reflection_multiplier; // one normally, zero when rendering reflections + + bool pancake_shadows; +} + +scene_data; + +struct InstanceData { + mat4 transform; + uint flags; + uint instance_uniforms_ofs; //base offset in global buffer for instance variables + uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) + uint layer_mask; + vec4 lightmap_uv_scale; +}; + +layout(set = 1, binding = 1, std430) buffer restrict readonly InstanceDataBuffer { + InstanceData data[]; +} +instances; + +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + +layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap; + +#else + +layout(set = 1, binding = 2) uniform textureCube radiance_cubemap; + +#endif + +layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas; + +layout(set = 1, binding = 4) uniform texture2D shadow_atlas; + +layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas; + +layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; + +#ifndef LOW_END_MOD +layout(set = 1, binding = 7) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +#endif + +layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer { + uint data[]; +} +cluster_buffer; + +#ifdef MODE_RENDER_SDF + +layout(r16ui, set = 1, binding = 9) uniform restrict writeonly uimage3D albedo_volume_grid; +layout(r32ui, set = 1, binding = 10) uniform restrict writeonly uimage3D emission_grid; +layout(r32ui, set = 1, binding = 11) uniform restrict writeonly uimage3D emission_aniso_grid; +layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid; + +//still need to be present for shaders that use it, so remap them to something +#define depth_buffer shadow_atlas +#define color_buffer shadow_atlas +#define normal_roughness_buffer shadow_atlas + +#else + +layout(set = 1, binding = 9) uniform texture2D depth_buffer; +layout(set = 1, binding = 10) uniform texture2D color_buffer; + +#ifndef LOW_END_MODE + +layout(set = 1, binding = 11) uniform texture2D normal_roughness_buffer; +layout(set = 1, binding = 12) uniform texture2D ao_buffer; +layout(set = 1, binding = 13) uniform texture2D ambient_buffer; +layout(set = 1, binding = 14) uniform texture2D reflection_buffer; +layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture; +layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades; + +struct GIProbeData { + mat4 xform; + vec3 bounds; + float dynamic_range; + + float bias; + float normal_bias; + bool blend_ambient; + uint texture_slot; + + float anisotropy_strength; + float ambient_occlusion; + float ambient_occlusion_size; + uint mipmaps; +}; + +layout(set = 1, binding = 17, std140) uniform GIProbes { + GIProbeData data[MAX_GI_PROBES]; +} +gi_probes; + +layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture; + +#endif // LOW_END_MODE + +#endif + +/* Set 2 Skeleton & Instancing (can change per item) */ + +layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms { + vec4 data[]; +} +transforms; + +/* Set 3 User Material */ diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl deleted file mode 100644 index d78890fa9e..0000000000 --- a/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl +++ /dev/null @@ -1,352 +0,0 @@ -#define M_PI 3.14159265359 -#define ROUGHNESS_MAX_LOD 5 - -#define MAX_GI_PROBES 8 - -#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) - -#extension GL_KHR_shader_subgroup_ballot : enable -#extension GL_KHR_shader_subgroup_arithmetic : enable - -#define USE_SUBGROUPS - -#endif - -#include "cluster_data_inc.glsl" - -#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_GIPROBE) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) -#ifndef NORMAL_USED -#define NORMAL_USED -#endif -#endif - -layout(push_constant, binding = 0, std430) uniform DrawCall { - uint instance_index; - uint uv_offset; - uint pad0; - uint pad1; -} -draw_call; - -/* Set 0 Scene data that never changes, ever */ - -#define SAMPLER_NEAREST_CLAMP 0 -#define SAMPLER_LINEAR_CLAMP 1 -#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 -#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 -#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 -#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 -#define SAMPLER_NEAREST_REPEAT 6 -#define SAMPLER_LINEAR_REPEAT 7 -#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 -#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 -#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 -#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 - -#define SDFGI_MAX_CASCADES 8 - -/* Set 1: Base Pass (never changes) */ - -layout(set = 0, binding = 1) uniform sampler material_samplers[12]; - -layout(set = 0, binding = 2) uniform sampler shadow_sampler; - -#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6) -#define INSTANCE_FLAGS_USE_SDFGI (1 << 7) -#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8) -#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9) -#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10) -#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11) -#define INSTANCE_FLAGS_MULTIMESH (1 << 12) -#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) -#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) -#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15) -#define INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT 16 -//3 bits of stride -#define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7 - -#define INSTANCE_FLAGS_SKELETON (1 << 19) -#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 20) - -layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { - LightData data[]; -} -omni_lights; - -layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { - LightData data[]; -} -spot_lights; - -layout(set = 0, binding = 5) buffer restrict readonly ReflectionProbeData { - ReflectionData data[]; -} -reflections; - -layout(set = 0, binding = 6, std140) uniform DirectionalLights { - DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; -} -directional_lights; - -#define LIGHTMAP_FLAG_USE_DIRECTION 1 -#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2 - -struct Lightmap { - mat3 normal_xform; -}; - -layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps { - Lightmap data[]; -} -lightmaps; - -struct LightmapCapture { - vec4 sh[9]; -}; - -layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures { - LightmapCapture data[]; -} -lightmap_captures; - -layout(set = 0, binding = 9) uniform texture2D decal_atlas; -layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb; - -layout(set = 0, binding = 11, std430) restrict readonly buffer Decals { - DecalData data[]; -} -decals; - -layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData { - vec4 data[]; -} -global_variables; - -#ifndef LOW_END_MODE - -struct SDFGIProbeCascadeData { - vec3 position; - float to_probe; - ivec3 probe_world_offset; - float to_cell; // 1/bounds * grid_size -}; - -layout(set = 0, binding = 13, std140) uniform SDFGI { - vec3 grid_size; - uint max_cascades; - - bool use_occlusion; - int probe_axis_size; - float probe_to_uvw; - float normal_bias; - - vec3 lightprobe_tex_pixel_size; - float energy; - - vec3 lightprobe_uv_offset; - float y_mult; - - vec3 occlusion_clamp; - uint pad3; - - vec3 occlusion_renormalize; - uint pad4; - - vec3 cascade_probe_size; - uint pad5; - - SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES]; -} -sdfgi; - -#endif //LOW_END_MODE - -/* Set 2: Render Pass (changes per render pass) */ - -layout(set = 1, binding = 0, std140) uniform SceneData { - mat4 projection_matrix; - mat4 inv_projection_matrix; - - mat4 camera_matrix; - mat4 inv_camera_matrix; - - vec2 viewport_size; - vec2 screen_pixel_size; - - uint cluster_shift; - uint cluster_width; - uint cluster_type_size; - uint max_cluster_element_count_div_32; - - //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted - vec4 directional_penumbra_shadow_kernel[32]; - vec4 directional_soft_shadow_kernel[32]; - vec4 penumbra_shadow_kernel[32]; - vec4 soft_shadow_kernel[32]; - - uint directional_penumbra_shadow_samples; - uint directional_soft_shadow_samples; - uint penumbra_shadow_samples; - uint soft_shadow_samples; - - vec4 ambient_light_color_energy; - - float ambient_color_sky_mix; - bool use_ambient_light; - bool use_ambient_cubemap; - bool use_reflection_cubemap; - - mat3 radiance_inverse_xform; - - vec2 shadow_atlas_pixel_size; - vec2 directional_shadow_pixel_size; - - uint directional_light_count; - float dual_paraboloid_side; - float z_far; - float z_near; - - bool ssao_enabled; - float ssao_light_affect; - float ssao_ao_affect; - bool roughness_limiter_enabled; - - float roughness_limiter_amount; - float roughness_limiter_limit; - uvec2 roughness_limiter_pad; - - vec4 ao_color; - - mat4 sdf_to_bounds; - - ivec3 sdf_offset; - bool material_uv2_mode; - - ivec3 sdf_size; - bool gi_upscale_for_msaa; - - bool volumetric_fog_enabled; - float volumetric_fog_inv_length; - float volumetric_fog_detail_spread; - uint volumetric_fog_pad; - - bool fog_enabled; - float fog_density; - float fog_height; - float fog_height_density; - - vec3 fog_light_color; - float fog_sun_scatter; - - float fog_aerial_perspective; - - float time; - float reflection_multiplier; // one normally, zero when rendering reflections - - bool pancake_shadows; -} - -scene_data; - -struct InstanceData { - mat4 transform; - uint flags; - uint instance_uniforms_ofs; //base offset in global buffer for instance variables - uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) - uint layer_mask; - vec4 lightmap_uv_scale; -}; - -layout(set = 1, binding = 1, std430) buffer restrict readonly InstanceDataBuffer { - InstanceData data[]; -} -instances; - -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - -layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap; - -#else - -layout(set = 1, binding = 2) uniform textureCube radiance_cubemap; - -#endif - -layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas; - -layout(set = 1, binding = 4) uniform texture2D shadow_atlas; - -layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas; - -layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; - -#ifndef LOW_END_MOD -layout(set = 1, binding = 7) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; -#endif - -layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer { - uint data[]; -} -cluster_buffer; - -#ifdef MODE_RENDER_SDF - -layout(r16ui, set = 1, binding = 9) uniform restrict writeonly uimage3D albedo_volume_grid; -layout(r32ui, set = 1, binding = 10) uniform restrict writeonly uimage3D emission_grid; -layout(r32ui, set = 1, binding = 11) uniform restrict writeonly uimage3D emission_aniso_grid; -layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid; - -//still need to be present for shaders that use it, so remap them to something -#define depth_buffer shadow_atlas -#define color_buffer shadow_atlas -#define normal_roughness_buffer shadow_atlas - -#else - -layout(set = 1, binding = 9) uniform texture2D depth_buffer; -layout(set = 1, binding = 10) uniform texture2D color_buffer; - -#ifndef LOW_END_MODE - -layout(set = 1, binding = 11) uniform texture2D normal_roughness_buffer; -layout(set = 1, binding = 12) uniform texture2D ao_buffer; -layout(set = 1, binding = 13) uniform texture2D ambient_buffer; -layout(set = 1, binding = 14) uniform texture2D reflection_buffer; -layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture; -layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades; - -struct GIProbeData { - mat4 xform; - vec3 bounds; - float dynamic_range; - - float bias; - float normal_bias; - bool blend_ambient; - uint texture_slot; - - float anisotropy_strength; - float ambient_occlusion; - float ambient_occlusion_size; - uint mipmaps; -}; - -layout(set = 1, binding = 17, std140) uniform GIProbes { - GIProbeData data[MAX_GI_PROBES]; -} -gi_probes; - -layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture; - -#endif // LOW_END_MODE - -#endif - -/* Set 2 Skeleton & Instancing (can change per item) */ - -layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms { - vec4 data[]; -} -transforms; - -/* Set 3 User Material */ -- cgit v1.2.3