From 4c691c6b605b3963f3c67a44ca2400b2fcfec6cc Mon Sep 17 00:00:00 2001 From: Hendrik Brucker Date: Sat, 14 Dec 2024 03:59:11 +0100 Subject: [PATCH] Add transparency support for LightmapGI Co-authored-by: Guerro323 --- doc/classes/ProjectSettings.xml | 3 + drivers/gles3/rasterizer_scene_gles3.cpp | 28 ++- drivers/gles3/rasterizer_scene_gles3.h | 12 +- drivers/gles3/shaders/scene.glsl | 16 ++ drivers/gles3/storage/material_storage.cpp | 22 +- drivers/gles3/storage/material_storage.h | 9 +- modules/lightmapper_rd/lightmapper_rd.cpp | 12 +- modules/lightmapper_rd/lightmapper_rd.h | 5 +- modules/lightmapper_rd/lm_common_inc.glsl | 9 +- modules/lightmapper_rd/lm_compute.glsl | 237 ++++++++++++++++-- modules/lightmapper_rd/register_types.cpp | 1 + scene/3d/lightmap_gi.cpp | 8 +- scene/3d/lightmapper.h | 1 + .../dummy/storage/material_storage.h | 1 + .../render_forward_clustered.cpp | 4 + .../scene_shader_forward_clustered.cpp | 10 +- .../scene_shader_forward_clustered.h | 10 +- .../forward_mobile/render_forward_mobile.cpp | 4 + .../scene_shader_forward_mobile.cpp | 8 +- .../scene_shader_forward_mobile.h | 8 +- .../scene_forward_clustered.glsl | 37 ++- .../forward_mobile/scene_forward_mobile.glsl | 37 ++- .../storage_rd/material_storage.cpp | 19 ++ .../renderer_rd/storage_rd/material_storage.h | 1 + servers/rendering/storage/material_storage.h | 1 + servers/rendering_server.h | 6 + 26 files changed, 420 insertions(+), 89 deletions(-) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 388cd8175382..0825f48913dc 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2730,6 +2730,9 @@ The maximum number of rays that can be thrown per pass when baking dynamic object lighting in [LightmapProbe]s with [LightmapGI]. Depending on the scene, adjusting this value may result in higher GPU utilization when baking lightmaps, leading to faster bake times. + + The maximum number of retry rays that can be thrown per pass when hitting a transparent surface when baking lightmaps with [LightmapGI]. Depending on the scene, reducing this value may lead to faster bake times. + The region size to use when baking lightmaps with [LightmapGI]. diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 857ab89c326d..21e70ca5ae96 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -977,7 +977,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p glBindFramebuffer(GL_FRAMEBUFFER, sky->radiance_framebuffer); scene_state.reset_gl_state(); - scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED); + scene_state.set_gl_cull_mode(RS::CULL_MODE_DISABLED); scene_state.enable_gl_blend(false); for (int i = 0; i < 6; i++) { @@ -1000,7 +1000,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p } else { if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) { scene_state.reset_gl_state(); - scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED); + scene_state.set_gl_cull_mode(RS::CULL_MODE_DISABLED); scene_state.enable_gl_blend(false); cubemap_filter->filter_radiance(sky->raw_radiance, sky->radiance, sky->radiance_framebuffer, sky->radiance_size, sky->mipmap_count, sky->processing_layer); @@ -1433,6 +1433,10 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const if (surf->flags & GeometryInstanceSurface::FLAG_PASS_SHADOW) { rl->add_element(surf); } + } else if (p_pass_mode == PASS_MODE_MATERIAL) { + if (surf->flags & (GeometryInstanceSurface::FLAG_PASS_DEPTH | GeometryInstanceSurface::FLAG_PASS_OPAQUE | GeometryInstanceSurface::FLAG_PASS_ALPHA)) { + rl->add_element(surf); + } } else { if (surf->flags & (GeometryInstanceSurface::FLAG_PASS_DEPTH | GeometryInstanceSurface::FLAG_PASS_OPAQUE)) { rl->add_element(surf); @@ -2210,7 +2214,7 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas, scene_state.enable_gl_depth_test(false); scene_state.enable_gl_depth_draw(true); glDisable(GL_CULL_FACE); - scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED; + scene_state.cull_mode = RS::CULL_MODE_DISABLED; glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } @@ -2587,7 +2591,7 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ scene_state.enable_gl_depth_draw(false); scene_state.enable_gl_depth_test(false); scene_state.enable_gl_blend(false); - scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_BACK); + scene_state.set_gl_cull_mode(RS::CULL_MODE_BACK); Ref feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id); @@ -2615,7 +2619,7 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ scene_state.enable_gl_depth_test(true); scene_state.enable_gl_blend(false); - scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_BACK); + scene_state.set_gl_cull_mode(RS::CULL_MODE_BACK); Transform3D transform = render_data.cam_transform; Projection projection = render_data.cam_projection; @@ -3099,19 +3103,19 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, } // Find cull variant. - GLES3::SceneShaderData::Cull cull_mode = shader->cull_mode; + RS::CullMode cull_mode = shader->cull_mode; if (p_pass_mode == PASS_MODE_MATERIAL || (surf->flags & GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS)) { - cull_mode = GLES3::SceneShaderData::CULL_DISABLED; + cull_mode = RS::CULL_MODE_DISABLED; } else { bool mirror = inst->mirror; if (p_params->reverse_cull) { mirror = !mirror; } - if (cull_mode == GLES3::SceneShaderData::CULL_FRONT && mirror) { - cull_mode = GLES3::SceneShaderData::CULL_BACK; - } else if (cull_mode == GLES3::SceneShaderData::CULL_BACK && mirror) { - cull_mode = GLES3::SceneShaderData::CULL_FRONT; + if (cull_mode == RS::CULL_MODE_FRONT && mirror) { + cull_mode = RS::CULL_MODE_BACK; + } else if (cull_mode == RS::CULL_MODE_BACK && mirror) { + cull_mode = RS::CULL_MODE_FRONT; } } @@ -3832,7 +3836,7 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref } } +RS::CullMode MaterialStorage::shader_get_cull_mode(RID p_shader) const { + const GLES3::Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_NULL_V(shader, RS::CULL_MODE_DISABLED); + if (shader->mode == RS::SHADER_SPATIAL && shader->data) { + SceneShaderData *data = dynamic_cast(shader->data); + if (data) { + return (RS::CullMode)data->cull_mode; + } + } + return RS::CULL_MODE_DISABLED; +} + void MaterialStorage::shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) { GLES3::Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_NULL(shader); @@ -2907,7 +2919,7 @@ void SceneShaderData::set_code(const String &p_code) { int blend_modei = BLEND_MODE_MIX; int depth_testi = DEPTH_TEST_ENABLED; int alpha_antialiasing_modei = ALPHA_ANTIALIASING_OFF; - int cull_modei = CULL_BACK; + int cull_modei = RS::CULL_MODE_BACK; int depth_drawi = DEPTH_DRAW_OPAQUE; ShaderCompiler::IdentifierActions actions; @@ -2930,9 +2942,9 @@ void SceneShaderData::set_code(const String &p_code) { actions.render_mode_values["depth_test_disabled"] = Pair(&depth_testi, DEPTH_TEST_DISABLED); - actions.render_mode_values["cull_disabled"] = Pair(&cull_modei, CULL_DISABLED); - actions.render_mode_values["cull_front"] = Pair(&cull_modei, CULL_FRONT); - actions.render_mode_values["cull_back"] = Pair(&cull_modei, CULL_BACK); + actions.render_mode_values["cull_disabled"] = Pair(&cull_modei, RS::CULL_MODE_DISABLED); + actions.render_mode_values["cull_front"] = Pair(&cull_modei, RS::CULL_MODE_FRONT); + actions.render_mode_values["cull_back"] = Pair(&cull_modei, RS::CULL_MODE_BACK); actions.render_mode_flags["unshaded"] = &unshaded; actions.render_mode_flags["wireframe"] = &wireframe; @@ -2990,7 +3002,7 @@ void SceneShaderData::set_code(const String &p_code) { alpha_antialiasing_mode = AlphaAntiAliasing(alpha_antialiasing_modei); depth_draw = DepthDraw(depth_drawi); depth_test = DepthTest(depth_testi); - cull_mode = Cull(cull_modei); + cull_mode = RS::CullMode(cull_modei); vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL; // We can always read vertices and normals. vertex_input_mask |= uses_tangent << RS::ARRAY_TANGENT; diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h index 6c21abc2764c..c5e1885405e1 100644 --- a/drivers/gles3/storage/material_storage.h +++ b/drivers/gles3/storage/material_storage.h @@ -263,12 +263,6 @@ struct SceneShaderData : public ShaderData { DEPTH_TEST_ENABLED }; - enum Cull { - CULL_DISABLED, - CULL_FRONT, - CULL_BACK - }; - enum AlphaAntiAliasing { ALPHA_ANTIALIASING_OFF, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, @@ -292,7 +286,7 @@ struct SceneShaderData : public ShaderData { AlphaAntiAliasing alpha_antialiasing_mode; DepthDraw depth_draw; DepthTest depth_test; - Cull cull_mode; + RS::CullMode cull_mode; bool uses_point_size; bool uses_alpha; @@ -589,6 +583,7 @@ class MaterialStorage : public RendererMaterialStorage { virtual void shader_set_path_hint(RID p_shader, const String &p_path) override; virtual String shader_get_code(RID p_shader) const override; virtual void get_shader_parameter_list(RID p_shader, List *p_param_list) const override; + virtual RS::CullMode shader_get_cull_mode(RID p_shader) const override; virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override; virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override; diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index a6074012de75..9c69a1df6848 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -40,6 +40,7 @@ #include "editor/editor_paths.h" #include "editor/editor_settings.h" #include "servers/rendering/rendering_device_binds.h" +#include "servers/rendering/rendering_server_globals.h" #if defined(VULKAN_ENABLED) #include "drivers/vulkan/rendering_context_driver_vulkan.h" @@ -477,7 +478,14 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i t.max_bounds[0] = taabb.position.x + MAX(taabb.size.x, 0.0001); t.max_bounds[1] = taabb.position.y + MAX(taabb.size.y, 0.0001); t.max_bounds[2] = taabb.position.z + MAX(taabb.size.z, 0.0001); - t.pad0 = t.pad1 = 0; //make valgrind not complain + + t.cull_mode = RS::CULL_MODE_BACK; + + RID material = mi.data.material[i]; + if (material.is_valid()) { + t.cull_mode = RSG::material_storage->shader_get_cull_mode(material); + } + t.pad1 = 0; //make valgrind not complain triangles.push_back(t); slice_triangle_count.write[t.slice]++; } @@ -1319,6 +1327,8 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d bake_parameters.bounces = p_bounces; bake_parameters.bounce_indirect_energy = p_bounce_indirect_energy; bake_parameters.shadowmask_light_idx = shadowmask_light_idx; + // Same number of rays for transparency regardless of quality (it's more of a retry rather than shooting new ones). + bake_parameters.transparency_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_transparency_rays"); bake_parameters_buffer = rd->uniform_buffer_create(sizeof(BakeParameters)); rd->buffer_update(bake_parameters_buffer, 0, sizeof(BakeParameters), &bake_parameters); diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h index 7e3efa71ccaa..43981420b107 100644 --- a/modules/lightmapper_rd/lightmapper_rd.h +++ b/modules/lightmapper_rd/lightmapper_rd.h @@ -58,7 +58,8 @@ class LightmapperRD : public Lightmapper { float bounce_indirect_energy = 0.0f; int shadowmask_light_idx = 0; - uint32_t pad[2] = {}; + uint32_t transparency_rays = 0; + uint32_t pad[1] = {}; }; struct MeshInstance { @@ -185,7 +186,7 @@ class LightmapperRD : public Lightmapper { uint32_t indices[3] = {}; uint32_t slice = 0; float min_bounds[3] = {}; - float pad0 = 0.0; + uint32_t cull_mode = 0; float max_bounds[3] = {}; float pad1 = 0.0; bool operator<(const Triangle &p_triangle) const { diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl index 954440dfe5fd..b47aef91a243 100644 --- a/modules/lightmapper_rd/lm_common_inc.glsl +++ b/modules/lightmapper_rd/lm_common_inc.glsl @@ -1,4 +1,3 @@ -/* SET 0, static data that does not change between any call */ layout(set = 0, binding = 0) uniform BakeParameters { vec3 world_size; @@ -17,9 +16,9 @@ layout(set = 0, binding = 0) uniform BakeParameters { uint bounces; float bounce_indirect_energy; + uint transparency_rays; int shadowmask_light_idx; uint pad0; - uint pad1; } bake_params; @@ -35,11 +34,15 @@ layout(set = 0, binding = 1, std430) restrict readonly buffer Vertices { } vertices; +#define CULL_DISABLED 0 +#define CULL_FRONT 1 +#define CULL_BACK 2 + struct Triangle { uvec3 indices; uint slice; vec3 min_bounds; - uint pad0; + uint cull_mode; vec3 max_bounds; uint pad1; }; diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl index fd18d879c9b8..5387c16bf6c5 100644 --- a/modules/lightmapper_rd/lm_compute.glsl +++ b/modules/lightmapper_rd/lm_compute.glsl @@ -226,14 +226,6 @@ uint trace_ray(vec3 p_from, vec3 p_to, bool p_any_hit, out float r_distance, out return RAY_ANY; } - vec3 position = p_from + dir * distance; - vec3 hit_cell = (position - bake_params.to_cell_offset) * bake_params.to_cell_size; - if (icell != ivec3(hit_cell)) { - // It's possible for the ray to hit a triangle in a position outside the bounds of the cell - // if it's large enough to cover multiple ones. The hit must be ignored if this is the case. - continue; - } - if (!backface) { // The case of meshes having both a front and back face in the same plane is more common than // expected, so if this is a front-face, bias it closer to the ray origin, so it always wins @@ -242,6 +234,17 @@ uint trace_ray(vec3 p_from, vec3 p_to, bool p_any_hit, out float r_distance, out } if (distance < best_distance) { + switch (triangle.cull_mode) { + case CULL_DISABLED: + backface = false; + break; + case CULL_FRONT: + backface = !backface; + break; + case CULL_BACK: // Default behavior. + break; + } + hit = backface ? RAY_BACK : RAY_FRONT; best_distance = distance; r_distance = distance; @@ -294,6 +297,27 @@ uint trace_ray_closest_hit_triangle(vec3 p_from, vec3 p_to, out uint r_triangle, return trace_ray(p_from, p_to, false, distance, normal, r_triangle, r_barycentric); } +uint trace_ray_closest_hit_triangle_albedo_alpha(vec3 p_from, vec3 p_to, out vec4 albedo_alpha, out vec3 hit_position) { + float distance; + vec3 normal; + uint tidx; + vec3 barycentric; + + uint ret = trace_ray(p_from, p_to, false, distance, normal, tidx, barycentric); + if (ret != RAY_MISS) { + Vertex vert0 = vertices.data[triangles.data[tidx].indices.x]; + Vertex vert1 = vertices.data[triangles.data[tidx].indices.y]; + Vertex vert2 = vertices.data[triangles.data[tidx].indices.z]; + + vec3 uvw = vec3(barycentric.x * vert0.uv + barycentric.y * vert1.uv + barycentric.z * vert2.uv, float(triangles.data[tidx].slice)); + + albedo_alpha = textureLod(sampler2DArray(albedo_tex, linear_sampler), uvw, 0); + hit_position = barycentric.x * vert0.position + barycentric.y * vert1.position + barycentric.z * vert2.position; + } + + return ret; +} + uint trace_ray_closest_hit_distance(vec3 p_from, vec3 p_to, out float r_distance, out vec3 r_normal) { uint triangle; vec3 barycentric; @@ -392,6 +416,8 @@ vec2 get_vogel_disk(float p_i, float p_rotation, float p_sample_count_sqrt) { } void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool p_soft_shadowing, out vec3 r_light, out vec3 r_light_dir, inout uint r_noise, float p_texel_size, out float r_shadow) { + const float EPSILON = 0.00001; + r_light = vec3(0.0f); r_shadow = 0.0f; @@ -460,6 +486,7 @@ void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool vec3 light_to_point_bitan = normalize(cross(light_to_point, light_to_point_tan)); uint hits = 0; + float aa_power = 0.0; for (uint i = 0; i < ray_count; i++) { // Create a random sample within the texel. vec2 disk_sample = (halton_map[i] - vec2(0.5)) * p_texel_size * light_data.shadow_blur; @@ -468,9 +495,13 @@ void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool vec3 origin = p_position - disk_aligned; vec3 light_dir = normalize(light_pos - origin); + float power = 0.0; + uint power_accm = 0; + vec3 prev_pos = origin; if (use_soft_shadows) { uint soft_shadow_hits = 0; for (uint j = 0; j < shadowing_ray_count; j++) { + origin = prev_pos; // Optimization: // Once already traced an important proportion of rays, if all are hits or misses, // assume we're not in the penumbra so we can infer the rest would have the same result. @@ -490,24 +521,114 @@ void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool float vogel_index = float(total_ray_count - 1 - (i * shadowing_ray_count + j)); // Start from (total_ray_count - 1) so we check the outer points first. vec2 light_disk_sample = get_vogel_disk(vogel_index, a, shadowing_ray_count_sqrt) * soft_shadowing_disk_size * light_data.shadow_blur; vec3 light_disk_to_point = normalize(light_to_point + light_disk_sample.x * light_to_point_tan + light_disk_sample.y * light_to_point_bitan); - // Offset the ray origin for AA, offset the light position for soft shadows. - if (trace_ray_any_hit(origin - light_disk_to_point * (bake_params.bias + length(disk_sample)), p_position - light_disk_to_point * dist) == RAY_MISS) { - soft_shadow_hits++; + float sample_penumbra = 0.0; + bool sample_did_hit = false; + + for (uint iter = 0; iter < bake_params.transparency_rays; iter++) { + vec4 hit_albedo = vec4(1.0); + vec3 hit_position; + // Offset the ray origin for AA, offset the light position for soft shadows. + uint ret = trace_ray_closest_hit_triangle_albedo_alpha(origin - light_disk_to_point * (bake_params.bias + length(disk_sample)), origin - light_disk_to_point * dist, hit_albedo, hit_position); + if (ret == RAY_MISS) { + if (!sample_did_hit) + sample_penumbra = 1.0; + soft_shadow_hits += 1; + break; + } else if (ret == RAY_FRONT || ret == RAY_BACK) { + bool contribute = ret == RAY_FRONT || !sample_did_hit; + if (!sample_did_hit) { + sample_penumbra = 1.0; + sample_did_hit = true; + } + + soft_shadow_hits += 1; + + if (contribute) + sample_penumbra = max(sample_penumbra - hit_albedo.a - EPSILON, 0.0); + origin = hit_position + r_light_dir * bake_params.bias; + + if (sample_penumbra - EPSILON <= 0) { + break; + } + } } + + power += sample_penumbra; + power_accm++; } + hits += soft_shadow_hits; - } else { - // Offset the ray origin based on the disk. Also increase the bias for further samples to avoid bleeding. - if (trace_ray_any_hit(origin + light_dir * (bake_params.bias + length(disk_sample)), light_pos) == RAY_MISS) { - hits++; + } else { // No soft shadows. + float sample_penumbra = 0.0; + bool sample_did_hit = false; + for (uint iter = 0; iter < bake_params.transparency_rays; iter++) { + vec4 hit_albedo = vec4(1.0); + vec3 hit_position; + // Offset the ray origin for AA, offset the light position for soft shadows. + uint ret = trace_ray_closest_hit_triangle_albedo_alpha(origin + light_dir * (bake_params.bias + length(disk_sample)), light_pos, hit_albedo, hit_position); + if (ret == RAY_MISS) { + if (!sample_did_hit) { + sample_penumbra = 1.0; + } + hits++; + break; + } else if (ret == RAY_FRONT || ret == RAY_BACK) { + bool contribute = ret == RAY_FRONT || !sample_did_hit; + if (!sample_did_hit) { + sample_penumbra = 1.0; + sample_did_hit = true; + } + + hits++; + + if (contribute) { + sample_penumbra = max(sample_penumbra - hit_albedo.a - EPSILON, 0.0); + } + origin = hit_position + r_light_dir * bake_params.bias; + + if (sample_penumbra - EPSILON <= 0) { + break; + } + } } + power += sample_penumbra; + power_accm = 1; } + aa_power = power / float(power_accm); } - penumbra = float(hits) / float(total_ray_count); - } else { - if (trace_ray_any_hit(p_position + r_light_dir * bake_params.bias, light_pos) == RAY_MISS) { - penumbra = 1.0; + penumbra = aa_power; + } else { // No soft shadows. + bool did_hit = false; + penumbra = 0.0; + for (uint iter = 0; iter < bake_params.transparency_rays; iter++) { + vec4 hit_albedo = vec4(1.0); + vec3 hit_position; + uint ret = trace_ray_closest_hit_triangle_albedo_alpha(p_position + r_light_dir * bake_params.bias, light_pos, hit_albedo, hit_position); + if (ret == RAY_MISS) { + if (!did_hit) { + penumbra = 1.0; + } + break; + } else if (ret == RAY_FRONT || ret == RAY_BACK) { + bool contribute = (ret == RAY_FRONT || !did_hit); + if (!did_hit) { + penumbra = 1.0; + did_hit = true; + } + + if (contribute) { + penumbra = max(penumbra - hit_albedo.a - EPSILON, 0.0); + } + + p_position = hit_position + r_light_dir * bake_params.bias; + + if (penumbra - EPSILON <= 0) { + break; + } + } } + + penumbra = clamp(penumbra, 0.0, 1.0); } r_shadow = penumbra; @@ -533,6 +654,7 @@ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise, f vec3 position = p_position; vec3 ray_dir = p_ray_dir; uint max_depth = max(bake_params.bounces, 1); + uint transparency_rays_left = bake_params.transparency_rays; vec3 throughput = vec3(1.0); vec3 light = vec3(0.0); for (uint depth = 0; depth < max_depth; depth++) { @@ -546,6 +668,8 @@ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise, f vec3 uvw = vec3(barycentric.x * vert0.uv + barycentric.y * vert1.uv + barycentric.z * vert2.uv, float(triangles.data[tidx].slice)); position = barycentric.x * vert0.position + barycentric.y * vert1.position + barycentric.z * vert2.position; + vec3 prev_normal = ray_dir; + vec3 norm0 = vec3(vert0.normal_xy, vert0.normal_z); vec3 norm1 = vec3(vert1.normal_xy, vert1.normal_z); vec3 norm2 = vec3(vert2.normal_xy, vert2.normal_z); @@ -568,13 +692,29 @@ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise, f direct_light *= bake_params.exposure_normalization; #endif - vec3 albedo = textureLod(sampler2DArray(albedo_tex, linear_sampler), uvw, 0).rgb; + vec4 albedo_alpha = textureLod(sampler2DArray(albedo_tex, linear_sampler), uvw, 0).rgba; vec3 emissive = textureLod(sampler2DArray(emission_tex, linear_sampler), uvw, 0).rgb; emissive *= bake_params.exposure_normalization; - light += throughput * emissive; - throughput *= albedo; - light += throughput * direct_light * bake_params.bounce_indirect_energy; + light += throughput * emissive * albedo_alpha.a; + throughput = mix(throughput, throughput * albedo_alpha.rgb, albedo_alpha.a); + light += throughput * direct_light * bake_params.bounce_indirect_energy * albedo_alpha.a; + + if (albedo_alpha.a < 1.0) { + transparency_rays_left -= 1; + depth -= 1; + if (transparency_rays_left <= 0) { + break; + } + + // Either bounce off the transparent surface or keep going forward + float pa = albedo_alpha.a * albedo_alpha.a; + if (randomize(r_noise) > pa) { + normal = prev_normal; + } + + position += normal * bake_params.bias; + } // Use Russian Roulette to determine a probability to terminate the bounce earlier as an optimization. // @@ -592,9 +732,54 @@ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise, f // Look for the environment color and stop bouncing. light += throughput * trace_environment_color(ray_dir); break; - } else { - // Ignore any other trace results. - break; + } else if (trace_result == RAY_BACK) { + Vertex vert0 = vertices.data[triangles.data[tidx].indices.x]; + Vertex vert1 = vertices.data[triangles.data[tidx].indices.y]; + Vertex vert2 = vertices.data[triangles.data[tidx].indices.z]; + vec3 uvw = vec3(barycentric.x * vert0.uv + barycentric.y * vert1.uv + barycentric.z * vert2.uv, float(triangles.data[tidx].slice)); + position = barycentric.x * vert0.position + barycentric.y * vert1.position + barycentric.z * vert2.position; + + vec4 albedo_alpha = textureLod(sampler2DArray(albedo_tex, linear_sampler), uvw, 0).rgba; + + if (albedo_alpha.a > 1.0) { + break; + } + + transparency_rays_left -= 1; + depth -= 1; + if (transparency_rays_left <= 0) { + break; + } + + vec3 norm0 = vec3(vert0.normal_xy, vert0.normal_z); + vec3 norm1 = vec3(vert1.normal_xy, vert1.normal_z); + vec3 norm2 = vec3(vert2.normal_xy, vert2.normal_z); + vec3 normal = barycentric.x * norm0 + barycentric.y * norm1 + barycentric.z * norm2; + + vec3 direct_light = vec3(0.0f); +#ifdef USE_LIGHT_TEXTURE_FOR_BOUNCES + direct_light += textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb; +#else + // Trace the lights directly. Significantly more expensive but more accurate in scenarios + // where the lightmap texture isn't reliable. + for (uint i = 0; i < bake_params.light_count; i++) { + vec3 light; + vec3 light_dir; + trace_direct_light(position, normal, i, false, light, light_dir, r_noise, p_texel_size, shadow); + direct_light += light * lights.data[i].indirect_energy; + } + + direct_light *= bake_params.exposure_normalization; +#endif + + vec3 emissive = textureLod(sampler2DArray(emission_tex, linear_sampler), uvw, 0).rgb; + emissive *= bake_params.exposure_normalization; + + light += throughput * emissive * albedo_alpha.a; + throughput = mix(mix(throughput, throughput * albedo_alpha.rgb, albedo_alpha.a), vec3(0.0), albedo_alpha.a); + light += throughput * direct_light * bake_params.bounce_indirect_energy * albedo_alpha.a; + + position += ray_dir * bake_params.bias; } } diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp index 4fe8f207237d..0d369955b7d5 100644 --- a/modules/lightmapper_rd/register_types.cpp +++ b/modules/lightmapper_rd/register_types.cpp @@ -52,6 +52,7 @@ void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/ultra_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 2048); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_rays_per_pass", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 32); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/region_size", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_transparency_rays", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/low_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 64); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/medium_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 256); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 752db3f3d01c..4c1b848b38f4 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -981,7 +981,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa w_albedo[i + 0] = uint8_t(CLAMP(float(r_aa[i + 0]) * (1.0 - float(r_orm[i + 2] / 255.0)), 0, 255)); w_albedo[i + 1] = uint8_t(CLAMP(float(r_aa[i + 1]) * (1.0 - float(r_orm[i + 2] / 255.0)), 0, 255)); w_albedo[i + 2] = uint8_t(CLAMP(float(r_aa[i + 2]) * (1.0 - float(r_orm[i + 2] / 255.0)), 0, 255)); - w_albedo[i + 3] = 255; + w_albedo[i + 3] = r_aa[i + 3]; } md.albedo_on_uv2.instantiate(); @@ -1002,6 +1002,11 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa continue; } Array a = mf.mesh->surface_get_arrays(i); + Ref mat = mf.mesh->surface_get_material(i); + RID mat_rid = RID(); + if (mat.is_valid()) { + mat_rid = mat->get_rid(); + } Vector vertices = a[Mesh::ARRAY_VERTEX]; const Vector3 *vr = vertices.ptr(); @@ -1051,6 +1056,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa md.uv2.push_back(uvr[vidx[k]]); md.normal.push_back(normal_xform.xform(nr[vidx[k]]).normalized()); + md.material.push_back(mat_rid); } } } diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h index 03ef3f38060c..d3a33b6532da 100644 --- a/scene/3d/lightmapper.h +++ b/scene/3d/lightmapper.h @@ -171,6 +171,7 @@ class Lightmapper : public RefCounted { Vector points; Vector uv2; Vector normal; + Vector material; Ref albedo_on_uv2; Ref emission_on_uv2; Variant userdata; diff --git a/servers/rendering/dummy/storage/material_storage.h b/servers/rendering/dummy/storage/material_storage.h index 74ae71cba656..9a54e58697d1 100644 --- a/servers/rendering/dummy/storage/material_storage.h +++ b/servers/rendering/dummy/storage/material_storage.h @@ -87,6 +87,7 @@ class MaterialStorage : public RendererMaterialStorage { virtual String shader_get_code(RID p_shader) const override { return ""; } virtual void get_shader_parameter_list(RID p_shader, List *p_param_list) const override; + virtual RS::CullMode shader_get_cull_mode(RID p_shader) const override { return RS::CULL_MODE_DISABLED; } virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override {} virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override { return RID(); } diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 408446503352..4ba816918425 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1120,6 +1120,10 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) { rl->add_element(surf); } + } else if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL) { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE | GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) { + rl->add_element(surf); + } } else { if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { rl->add_element(surf); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 6dadbf25ac42..a8318a8f4231 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -54,7 +54,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { blend_mode = BLEND_MODE_MIX; depth_testi = DEPTH_TEST_ENABLED; alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; - int cull_modei = CULL_BACK; + int cull_modei = RS::CULL_MODE_BACK; uses_point_size = false; uses_alpha = false; @@ -101,9 +101,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { actions.render_mode_values["depth_test_disabled"] = Pair(&depth_testi, DEPTH_TEST_DISABLED); - actions.render_mode_values["cull_disabled"] = Pair(&cull_modei, CULL_DISABLED); - actions.render_mode_values["cull_front"] = Pair(&cull_modei, CULL_FRONT); - actions.render_mode_values["cull_back"] = Pair(&cull_modei, CULL_BACK); + actions.render_mode_values["cull_disabled"] = Pair(&cull_modei, RS::CULL_MODE_DISABLED); + actions.render_mode_values["cull_front"] = Pair(&cull_modei, RS::CULL_MODE_FRONT); + actions.render_mode_values["cull_back"] = Pair(&cull_modei, RS::CULL_MODE_BACK); actions.render_mode_flags["unshaded"] = &unshaded; actions.render_mode_flags["wireframe"] = &wireframe; @@ -158,7 +158,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { depth_draw = DepthDraw(depth_drawi); depth_test = DepthTest(depth_testi); - cull_mode = Cull(cull_modei); + cull_mode = RS::CullMode(cull_modei); uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps; uses_screen_texture = gen_code.uses_screen_texture; uses_depth_texture = gen_code.uses_depth_texture; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index 1f4058a1219d..c9278fcd995d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -153,12 +153,6 @@ class SceneShaderForwardClustered { DEPTH_TEST_ENABLED }; - enum Cull { - CULL_DISABLED, - CULL_FRONT, - CULL_BACK - }; - enum CullVariant { CULL_VARIANT_NORMAL, CULL_VARIANT_REVERSED, @@ -250,7 +244,7 @@ class SceneShaderForwardClustered { bool writes_modelview_or_projection = false; bool uses_world_coordinates = false; bool uses_screen_texture_mipmaps = false; - Cull cull_mode = CULL_DISABLED; + RS::CullMode cull_mode = RS::CULL_MODE_DISABLED; uint64_t last_pass = 0; uint32_t index = 0; @@ -272,7 +266,7 @@ class SceneShaderForwardClustered { } _FORCE_INLINE_ bool uses_shared_shadow_material() const { - bool backface_culling = cull_mode == CULL_BACK; + bool backface_culling = cull_mode == RS::CULL_MODE_BACK; return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_position && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && backface_culling && !uses_point_size && !uses_world_coordinates && !wireframe; } diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 20f8ef02c07d..2a9e564a2c0f 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2061,6 +2061,10 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) { rl->add_element(surf); } + } else if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL) { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE | GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) { + rl->add_element(surf); + } } else { if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { rl->add_element(surf); diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index eb2d25f2a7dd..c7a68b13967d 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -56,7 +56,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { blend_mode = BLEND_MODE_MIX; depth_testi = DEPTH_TEST_ENABLED; alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; - cull_mode = CULL_BACK; + cull_mode = RS::CULL_MODE_BACK; uses_point_size = false; uses_alpha = false; @@ -102,9 +102,9 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { actions.render_mode_values["depth_test_disabled"] = Pair(&depth_testi, DEPTH_TEST_DISABLED); - actions.render_mode_values["cull_disabled"] = Pair(&cull_mode, CULL_DISABLED); - actions.render_mode_values["cull_front"] = Pair(&cull_mode, CULL_FRONT); - actions.render_mode_values["cull_back"] = Pair(&cull_mode, CULL_BACK); + actions.render_mode_values["cull_disabled"] = Pair(&cull_mode, RS::CULL_MODE_DISABLED); + actions.render_mode_values["cull_front"] = Pair(&cull_mode, RS::CULL_MODE_FRONT); + actions.render_mode_values["cull_back"] = Pair(&cull_mode, RS::CULL_MODE_BACK); actions.render_mode_flags["unshaded"] = &unshaded; actions.render_mode_flags["wireframe"] = &wireframe; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index a40c5446c74a..fee3c6af48f6 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -141,12 +141,6 @@ class SceneShaderForwardMobile { DEPTH_TEST_ENABLED }; - enum Cull { - CULL_DISABLED, - CULL_FRONT, - CULL_BACK - }; - enum CullVariant { CULL_VARIANT_NORMAL, CULL_VARIANT_REVERSED, @@ -209,7 +203,7 @@ class SceneShaderForwardMobile { int blend_mode = BLEND_MODE_MIX; int depth_testi = DEPTH_TEST_ENABLED; int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; - int cull_mode = CULL_BACK; + int cull_mode = RS::CULL_MODE_BACK; bool uses_point_size = false; bool uses_alpha = false; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index c14ea34c8f0c..a3c2557c75de 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -1256,21 +1256,37 @@ void fragment_shader(in SceneData scene_data) { #ifndef USE_SHADOW_TO_OPACITY #ifdef ALPHA_SCISSOR_USED +#ifdef MODE_RENDER_MATERIAL + if (alpha < alpha_scissor_threshold) { + alpha = 0.0; + } else { + alpha = 1.0; + } +#else if (alpha < alpha_scissor_threshold) { discard; } +#endif // MODE_RENDER_MATERIAL #endif // ALPHA_SCISSOR_USED // alpha hash can be used in unison with alpha antialiasing #ifdef ALPHA_HASH_USED vec3 object_pos = (inverse(read_model_matrix) * inv_view_matrix * vec4(vertex, 1.0)).xyz; +#ifdef MODE_RENDER_MATERIAL + if (alpha < compute_alpha_hash_threshold(object_pos, alpha_hash_scale)) { + alpha = 0.0; + } else { + alpha = 1.0; + } +#else if (alpha < compute_alpha_hash_threshold(object_pos, alpha_hash_scale)) { discard; } +#endif // MODE_RENDER_MATERIAL #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) +#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED) && !defined(MODE_RENDER_MATERIAL) alpha = 1.0; #endif @@ -1314,10 +1330,21 @@ void fragment_shader(in SceneData scene_data) { #endif #ifdef ENABLE_CLIP_ALPHA +#ifdef MODE_RENDER_MATERIAL + if (albedo.a < 0.99) { + //used for doublepass and shadowmapping + albedo.a = 0.0; + alpha = 0.0; + } else { + albedo.a = 1.0; + alpha = 1.0; + } +#else if (albedo.a < 0.99) { //used for doublepass and shadowmapping discard; } +#endif // MODE_RENDER_MATERIAL #endif /////////////////////// FOG ////////////////////// @@ -2521,9 +2548,17 @@ void fragment_shader(in SceneData scene_data) { alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); #if defined(ALPHA_SCISSOR_USED) +#ifdef MODE_RENDER_MATERIAL + if (alpha < alpha_scissor_threshold) { + alpha = 0.0; + } else { + alpha = 1.0; + } +#else if (alpha < alpha_scissor_threshold) { discard; } +#endif // MODE_RENDER_MATERIAL #endif // ALPHA_SCISSOR_USED #endif // !MODE_RENDER_DEPTH diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index a3c264b82366..2061f4b6d923 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -984,21 +984,37 @@ void main() { #ifndef USE_SHADOW_TO_OPACITY #ifdef ALPHA_SCISSOR_USED +#ifdef MODE_RENDER_MATERIAL + if (alpha < alpha_scissor_threshold) { + alpha = 0.0; + } else { + alpha = 1.0; + } +#else if (alpha < alpha_scissor_threshold) { discard; } +#endif // MODE_RENDER_MATERIAL #endif // ALPHA_SCISSOR_USED // alpha hash can be used in unison with alpha antialiasing #ifdef ALPHA_HASH_USED vec3 object_pos = (inverse(read_model_matrix) * inv_view_matrix * vec4(vertex, 1.0)).xyz; +#ifdef MODE_RENDER_MATERIAL + if (alpha < compute_alpha_hash_threshold(object_pos, alpha_hash_scale)) { + alpha = 0.0; + } else { + alpha = 1.0; + } +#else if (alpha < compute_alpha_hash_threshold(object_pos, alpha_hash_scale)) { discard; } +#endif // MODE_RENDER_MATERIAL #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) +#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED) && !defined(MODE_RENDER_MATERIAL) alpha = 1.0; #endif @@ -1042,10 +1058,21 @@ void main() { #endif #ifdef ENABLE_CLIP_ALPHA +#ifdef MODE_RENDER_MATERIAL + if (albedo.a < 0.99) { + //used for doublepass and shadowmapping + albedo.a = 0.0; + alpha = 0.0; + } else { + albedo.a = 1.0; + alpha = 1.0; + } +#else if (albedo.a < 0.99) { //used for doublepass and shadowmapping discard; } +#endif // MODE_RENDER_MATERIAL #endif /////////////////////// FOG ////////////////////// @@ -1739,9 +1766,17 @@ void main() { alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); #if defined(ALPHA_SCISSOR_USED) +#ifdef MODE_RENDER_MATERIAL + if (alpha < alpha_scissor_threshold) { + alpha = 0.0; + } else { + alpha = 1.0; + } +#else if (alpha < alpha_scissor_threshold) { discard; } +#endif // MODE_RENDER_MATERIAL #endif // !ALPHA_SCISSOR_USED #endif // !MODE_RENDER_DEPTH diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index e84bc399bfd1..972b88734fa8 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -32,6 +32,8 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/io/resource_loader.h" +#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h" +#include "servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h" #include "servers/rendering/storage/variant_converters.h" #include "texture_storage.h" @@ -2033,6 +2035,23 @@ void MaterialStorage::get_shader_parameter_list(RID p_shader, List } } +RS::CullMode MaterialStorage::shader_get_cull_mode(RID p_shader) const { + const RendererRD::MaterialStorage::Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_NULL_V(shader, RS::CULL_MODE_DISABLED); + if (shader->type == ShaderType::SHADER_TYPE_3D && shader->data) { + RendererSceneRenderImplementation::SceneShaderForwardClustered::ShaderData *sd_clustered = dynamic_cast(shader->data); + if (sd_clustered) { + return (RS::CullMode)sd_clustered->cull_mode; + } + + RendererSceneRenderImplementation::SceneShaderForwardMobile::ShaderData *sd_mobile = dynamic_cast(shader->data); + if (sd_mobile) { + return (RS::CullMode)sd_mobile->cull_mode; + } + } + return RS::CULL_MODE_DISABLED; +} + void MaterialStorage::shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) { Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_NULL(shader); diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h index d1fde9b6beb9..3342f7f5b7f4 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h @@ -414,6 +414,7 @@ class MaterialStorage : public RendererMaterialStorage { virtual void shader_set_path_hint(RID p_shader, const String &p_path) override; virtual String shader_get_code(RID p_shader) const override; virtual void get_shader_parameter_list(RID p_shader, List *p_param_list) const override; + virtual RS::CullMode shader_get_cull_mode(RID p_shader) const override; virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override; virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override; diff --git a/servers/rendering/storage/material_storage.h b/servers/rendering/storage/material_storage.h index a5935cc90f72..08fba4be4314 100644 --- a/servers/rendering/storage/material_storage.h +++ b/servers/rendering/storage/material_storage.h @@ -64,6 +64,7 @@ class RendererMaterialStorage { virtual void shader_set_path_hint(RID p_shader, const String &p_path) = 0; virtual String shader_get_code(RID p_shader) const = 0; virtual void get_shader_parameter_list(RID p_shader, List *p_param_list) const = 0; + virtual RS::CullMode shader_get_cull_mode(RID p_shader) const = 0; virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) = 0; virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const = 0; diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 23dbc821135b..8efcfebcc5f4 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -221,6 +221,12 @@ class RenderingServer : public Object { SHADER_MAX }; + enum CullMode { + CULL_MODE_DISABLED, + CULL_MODE_FRONT, + CULL_MODE_BACK, + }; + virtual RID shader_create() = 0; virtual RID shader_create_from_code(const String &p_code, const String &p_path_hint = String()) = 0;