Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix draw order of transparent materials with multiple directional lights #47129

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 62 additions & 6 deletions drivers/gles3/rasterizer_scene_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions drivers/gles3/rasterizer_scene_gles3.h
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,7 @@ class RasterizerSceneGLES3 : public RasterizerScene {
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);
Expand Down