Fix draw order of transparent materials with multiple directional lights

This commit is contained in:
Morris Tabor 2021-03-18 13:23:48 +01:00
parent acbd1e8b02
commit 63b7b7773c
2 changed files with 63 additions and 6 deletions

View file

@ -4130,6 +4130,26 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
state.tonemap_shader.set_conditional(TonemapShaderGLES3::V_FLIP, false); 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) { 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 //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); render_list.sort_by_reverse_depth_and_priority(true);
if (state.directional_light_count == 0) { if (state.directional_light_count <= 1) {
directional_light = NULL; 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); _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 { } else {
for (int i = 0; i < state.directional_light_count; i++) { // special handling for multiple directional lights
directional_light = directional_lights[i];
_setup_directional_light(i, p_cam_transform.affine_inverse(), use_shadows); // first chunk_start
_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); 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);
}
} }
} }

View file

@ -867,6 +867,7 @@ public:
void _prepare_depth_texture(); void _prepare_depth_texture();
void _bind_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_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 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); virtual bool free(RID p_rid);