From 3aaefb957b38bdd5c17d9acea61b1d1ba7b4492d Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Wed, 24 Feb 2021 16:03:46 +0000 Subject: [PATCH] GLES2 fix for consistent light ordering with BVH Due to multi pass approach to lighting in GLES2, in some situations the rendered result can look different if lights are presented in a different order. The order (aside from directional lights) seems to be simply copied from the culling routine (octree or bvh) which is essentially arbitrary. While octree is usually consistent with order, bvh uses a trickle optimize which may result in lights occurring in different order from frame to frame. This PR adds an extra layer of sorting on GLES2 lights in order to get some kind of order consistency. --- drivers/gles2/rasterizer_scene_gles2.cpp | 29 ++++++++++++++++++++++++ drivers/gles2/rasterizer_scene_gles2.h | 8 +++++++ 2 files changed, 37 insertions(+) diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 6c2fff9eb1c..0b02ee15cf0 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -899,6 +899,10 @@ RID RasterizerSceneGLES2::light_instance_create(RID p_light) { light_instance->light_index = 0xFFFF; + // an ever increasing counter for each light added, + // used for sorting lights for a consistent render + light_instance->light_counter = _light_counter++; + if (!light_instance->light_ptr) { memdelete(light_instance); ERR_FAIL_V_MSG(RID(), "Condition ' !light_instance->light_ptr ' is true."); @@ -3285,6 +3289,30 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const index++; } + // for fog transmission, we want some kind of consistent ordering of lights + // add any more conditions here in which we need consistent light ordering + // (perhaps we always should have it, but don't know yet) + if (env && env->fog_transmit_enabled) { + + struct _LightSort { + + bool operator()(LightInstance *A, LightInstance *B) const { + return A->light_counter > B->light_counter; + } + }; + + int num_lights_to_sort = render_light_instance_count - render_directional_lights; + + if (num_lights_to_sort) { + SortArray sorter; + sorter.sort(&render_light_instances[render_directional_lights], num_lights_to_sort); + // rejig indices + for (int i = render_directional_lights; i < render_light_instance_count; i++) { + render_light_instances[i]->light_index = i; + } + } + } + } else { render_light_instances = NULL; render_directional_lights = 0; @@ -4086,4 +4114,5 @@ void RasterizerSceneGLES2::finalize() { } RasterizerSceneGLES2::RasterizerSceneGLES2() { + _light_counter = 0; } diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index c5e9d55d9a5..3f6205dc301 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -88,6 +88,10 @@ public: uint32_t current_refprobe_index; uint32_t current_shader_index; +private: + uint32_t _light_counter; + +public: RasterizerStorageGLES2 *storage; struct State { @@ -528,6 +532,10 @@ public: Rect2 directional_rect; + // an ever increasing counter for each light added, + // used for sorting lights for a consistent render + uint32_t light_counter; + Set shadow_atlases; // atlases where this light is registered };