From 63b7b7773c2a839c1b549753260accd945aa3d30 Mon Sep 17 00:00:00 2001 From: Morris Tabor <80684659+mortarroad@users.noreply.github.com> Date: Thu, 18 Mar 2021 13:23:48 +0100 Subject: [PATCH] Fix draw order of transparent materials with multiple directional lights --- drivers/gles3/rasterizer_scene_gles3.cpp | 68 +++++++++++++++++++++--- drivers/gles3/rasterizer_scene_gles3.h | 1 + 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 41e3165eb62..9863100cb28 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -4130,6 +4130,26 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.tonemap_shader.set_conditional(TonemapShaderGLES3::V_FLIP, false); } +bool RasterizerSceneGLES3::_element_needs_directional_add(RenderList::Element *e) { + // return whether this element should take part in directional add + if (e->sort_key & SORT_KEY_UNSHADED_FLAG) { + return false; + } + + for (int i = 0; i < state.directional_light_count; i++) { + LightInstance *l = directional_lights[i]; + // any unbaked and unculled light? + if (e->instance->baked_light && l->light_ptr->bake_mode == VS::LightBakeMode::LIGHT_BAKE_ALL) { + continue; + } + if ((e->instance->layer_mask & l->light_ptr->cull_mask) == 0) { + continue; + } + return true; + } + return false; // no visible unbaked light +} + void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { //first of all, make a new render pass @@ -4609,14 +4629,50 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const render_list.sort_by_reverse_depth_and_priority(true); - if (state.directional_light_count == 0) { - directional_light = NULL; + if (state.directional_light_count <= 1) { + if (state.directional_light_count == 1) { + directional_light = directional_lights[0]; + _setup_directional_light(0, p_cam_transform.affine_inverse(), use_shadows); + } else { + directional_light = NULL; + } _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, sky, false, true, false, false, use_shadows); } else { - for (int i = 0; i < state.directional_light_count; i++) { - directional_light = directional_lights[i]; - _setup_directional_light(i, p_cam_transform.affine_inverse(), use_shadows); - _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, sky, false, true, false, i > 0, use_shadows); + // special handling for multiple directional lights + + // first chunk_start + int chunk_split = render_list.max_elements - render_list.alpha_element_count; + + while (chunk_split < render_list.max_elements) { + int chunk_start = chunk_split; + bool first = true; + bool chunk_directional_add = false; + uint32_t chunk_priority = 0; + + // determine chunk end + for (; chunk_split < render_list.max_elements; chunk_split++) { + bool directional_add = _element_needs_directional_add(render_list.elements[chunk_split]); + uint32_t priority = uint32_t(render_list.elements[chunk_split]->sort_key >> RenderList::SORT_KEY_PRIORITY_SHIFT); + if (first) { + chunk_directional_add = directional_add; + chunk_priority = priority; + first = false; + } + if ((directional_add != chunk_directional_add) || (priority != chunk_priority)) { + break; + } + } + + if (chunk_directional_add) { + for (int i = 0; i < state.directional_light_count; i++) { + directional_light = directional_lights[i]; + _setup_directional_light(i, p_cam_transform.affine_inverse(), use_shadows); + _render_list(&render_list.elements[chunk_start], chunk_split - chunk_start, p_cam_transform, p_cam_projection, sky, false, true, false, i > 0, use_shadows); + } + } else { + directional_light = NULL; + _render_list(&render_list.elements[chunk_start], chunk_split - chunk_start, p_cam_transform, p_cam_projection, sky, false, true, false, false, use_shadows); + } } } diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 4b8ba4d5fe9..53156e6cce6 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -867,6 +867,7 @@ public: void _prepare_depth_texture(); void _bind_depth_texture(); + bool _element_needs_directional_add(RenderList::Element *e); virtual void render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); virtual bool free(RID p_rid);