Browse Source

Implement 3D shadows in the GL Compatibility renderer

clayjohn 2 years ago
parent
commit
cb7200b028

+ 10 - 0
drivers/gles3/effects/copy_effects.cpp

@@ -134,6 +134,16 @@ void CopyEffects::copy_screen() {
 	draw_screen_triangle();
 	draw_screen_triangle();
 }
 }
 
 
+void CopyEffects::copy_cube_to_rect(const Rect2 &p_rect) {
+	bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_CUBE_TO_OCTAHEDRAL);
+	if (!success) {
+		return;
+	}
+
+	copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
+	draw_screen_quad();
+}
+
 // Intended for efficiently mipmapping textures.
 // Intended for efficiently mipmapping textures.
 void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
 void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
 	GLuint framebuffers[2];
 	GLuint framebuffers[2];

+ 1 - 0
drivers/gles3/effects/copy_effects.h

@@ -63,6 +63,7 @@ public:
 	// These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array.
 	// These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array.
 	void copy_to_rect(const Rect2 &p_rect);
 	void copy_to_rect(const Rect2 &p_rect);
 	void copy_screen();
 	void copy_screen();
+	void copy_cube_to_rect(const Rect2 &p_rect);
 	void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
 	void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
 	void gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size);
 	void gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size);
 	void set_color(const Color &p_color, const Rect2i &p_region);
 	void set_color(const Color &p_color, const Rect2i &p_region);

File diff suppressed because it is too large
+ 797 - 259
drivers/gles3/rasterizer_scene_gles3.cpp


+ 66 - 13
drivers/gles3/rasterizer_scene_gles3.h

@@ -59,7 +59,6 @@ enum RenderListType {
 enum PassMode {
 enum PassMode {
 	PASS_MODE_COLOR,
 	PASS_MODE_COLOR,
 	PASS_MODE_COLOR_TRANSPARENT,
 	PASS_MODE_COLOR_TRANSPARENT,
-	PASS_MODE_COLOR_ADDITIVE,
 	PASS_MODE_SHADOW,
 	PASS_MODE_SHADOW,
 	PASS_MODE_DEPTH,
 	PASS_MODE_DEPTH,
 };
 };
@@ -75,6 +74,8 @@ enum SceneUniformLocation {
 	SCENE_SPOTLIGHT_UNIFORM_LOCATION,
 	SCENE_SPOTLIGHT_UNIFORM_LOCATION,
 	SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
 	SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
 	SCENE_MULTIVIEW_UNIFORM_LOCATION,
 	SCENE_MULTIVIEW_UNIFORM_LOCATION,
+	SCENE_POSITIONAL_SHADOW_UNIFORM_LOCATION,
+	SCENE_DIRECTIONAL_SHADOW_UNIFORM_LOCATION,
 };
 };
 
 
 enum SkyUniformLocation {
 enum SkyUniformLocation {
@@ -109,6 +110,7 @@ struct RenderDataGLES3 {
 	const PagedArray<RID> *reflection_probes = nullptr;
 	const PagedArray<RID> *reflection_probes = nullptr;
 	RID environment;
 	RID environment;
 	RID camera_attributes;
 	RID camera_attributes;
+	RID shadow_atlas;
 	RID reflection_probe;
 	RID reflection_probe;
 	int reflection_probe_pass = 0;
 	int reflection_probe_pass = 0;
 
 
@@ -116,10 +118,16 @@ struct RenderDataGLES3 {
 	float screen_mesh_lod_threshold = 0.0;
 	float screen_mesh_lod_threshold = 0.0;
 
 
 	uint32_t directional_light_count = 0;
 	uint32_t directional_light_count = 0;
+	uint32_t directional_shadow_count = 0;
+
 	uint32_t spot_light_count = 0;
 	uint32_t spot_light_count = 0;
 	uint32_t omni_light_count = 0;
 	uint32_t omni_light_count = 0;
 
 
 	RenderingMethod::RenderInfo *render_info = nullptr;
 	RenderingMethod::RenderInfo *render_info = nullptr;
+
+	/* Shadow data */
+	const RendererSceneRender::RenderShadowData *render_shadows = nullptr;
+	int render_shadow_count = 0;
 };
 };
 
 
 class RasterizerCanvasGLES3;
 class RasterizerCanvasGLES3;
@@ -173,11 +181,36 @@ private:
 		float size;
 		float size;
 
 
 		uint32_t enabled; // For use by SkyShaders
 		uint32_t enabled; // For use by SkyShaders
-		float pad[2];
+		float pad;
+		float shadow_opacity;
 		float specular;
 		float specular;
 	};
 	};
 	static_assert(sizeof(DirectionalLightData) % 16 == 0, "DirectionalLightData size must be a multiple of 16 bytes");
 	static_assert(sizeof(DirectionalLightData) % 16 == 0, "DirectionalLightData size must be a multiple of 16 bytes");
 
 
+	struct ShadowData {
+		float shadow_matrix[16];
+
+		float light_position[3];
+		float shadow_normal_bias;
+
+		float pad[3];
+		float shadow_atlas_pixel_size;
+	};
+	static_assert(sizeof(ShadowData) % 16 == 0, "ShadowData size must be a multiple of 16 bytes");
+
+	struct DirectionalShadowData {
+		float direction[3];
+		float shadow_atlas_pixel_size;
+		float shadow_normal_bias[4];
+		float shadow_split_offsets[4];
+		float shadow_matrices[4][16];
+		float fade_from;
+		float fade_to;
+		uint32_t blend_splits; // Not exposed to the shader.
+		uint32_t pad;
+	};
+	static_assert(sizeof(DirectionalShadowData) % 16 == 0, "DirectionalShadowData size must be a multiple of 16 bytes");
+
 	class GeometryInstanceGLES3;
 	class GeometryInstanceGLES3;
 
 
 	// Cached data for drawing surfaces
 	// Cached data for drawing surfaces
@@ -221,6 +254,8 @@ private:
 		uint32_t surface_index = 0;
 		uint32_t surface_index = 0;
 		uint32_t lod_index = 0;
 		uint32_t lod_index = 0;
 		uint32_t index_count = 0;
 		uint32_t index_count = 0;
+		int32_t light_pass_index = -1;
+		bool finished_base_pass = false;
 
 
 		void *surface = nullptr;
 		void *surface = nullptr;
 		GLES3::SceneShaderData *shader = nullptr;
 		GLES3::SceneShaderData *shader = nullptr;
@@ -245,14 +280,23 @@ private:
 		bool using_projectors = false;
 		bool using_projectors = false;
 		bool using_softshadows = false;
 		bool using_softshadows = false;
 
 
-		uint32_t omni_light_count = 0;
-		LocalVector<RID> omni_lights;
-		uint32_t spot_light_count = 0;
-		LocalVector<RID> spot_lights;
+		struct LightPass {
+			int32_t light_id = -1; // Position in the light uniform buffer.
+			int32_t shadow_id = -1; // Position in the shadow uniform buffer.
+			RID light_instance_rid;
+			bool is_omni = false;
+		};
+
+		LocalVector<LightPass> light_passes;
+
+		uint32_t paired_omni_light_count = 0;
+		uint32_t paired_spot_light_count = 0;
+		LocalVector<RID> paired_omni_lights;
+		LocalVector<RID> paired_spot_lights;
 		LocalVector<uint32_t> omni_light_gl_cache;
 		LocalVector<uint32_t> omni_light_gl_cache;
 		LocalVector<uint32_t> spot_light_gl_cache;
 		LocalVector<uint32_t> spot_light_gl_cache;
 
 
-		//used during setup
+		// Used during setup.
 		GeometryInstanceSurface *surface_caches = nullptr;
 		GeometryInstanceSurface *surface_caches = nullptr;
 		SelfList<GeometryInstanceGLES3> dirty_list_element;
 		SelfList<GeometryInstanceGLES3> dirty_list_element;
 
 
@@ -336,10 +380,11 @@ private:
 
 
 			float fog_light_color[3];
 			float fog_light_color[3];
 			float fog_sun_scatter;
 			float fog_sun_scatter;
+
+			float shadow_bias;
+			float pad;
 			uint32_t camera_visible_layers;
 			uint32_t camera_visible_layers;
-			uint32_t pad1;
-			uint32_t pad2;
-			uint32_t pad3;
+			bool pancake_shadows;
 		};
 		};
 		static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
 		static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
 
 
@@ -378,16 +423,22 @@ private:
 
 
 		LightData *omni_lights = nullptr;
 		LightData *omni_lights = nullptr;
 		LightData *spot_lights = nullptr;
 		LightData *spot_lights = nullptr;
+		ShadowData *positional_shadows = nullptr;
 
 
 		InstanceSort<GLES3::LightInstance> *omni_light_sort;
 		InstanceSort<GLES3::LightInstance> *omni_light_sort;
 		InstanceSort<GLES3::LightInstance> *spot_light_sort;
 		InstanceSort<GLES3::LightInstance> *spot_light_sort;
 		GLuint omni_light_buffer = 0;
 		GLuint omni_light_buffer = 0;
 		GLuint spot_light_buffer = 0;
 		GLuint spot_light_buffer = 0;
+		GLuint positional_shadow_buffer = 0;
 		uint32_t omni_light_count = 0;
 		uint32_t omni_light_count = 0;
 		uint32_t spot_light_count = 0;
 		uint32_t spot_light_count = 0;
+		RS::ShadowQuality positional_shadow_quality = RS::ShadowQuality::SHADOW_QUALITY_SOFT_LOW;
 
 
 		DirectionalLightData *directional_lights = nullptr;
 		DirectionalLightData *directional_lights = nullptr;
 		GLuint directional_light_buffer = 0;
 		GLuint directional_light_buffer = 0;
+		DirectionalShadowData *directional_shadows = nullptr;
+		GLuint directional_shadow_buffer = 0;
+		RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality::SHADOW_QUALITY_SOFT_LOW;
 	} scene_state;
 	} scene_state;
 
 
 	struct RenderListParameters {
 	struct RenderListParameters {
@@ -462,9 +513,11 @@ private:
 
 
 	RenderList render_list[RENDER_LIST_MAX];
 	RenderList render_list[RENDER_LIST_MAX];
 
 
-	void _setup_lights(const RenderDataGLES3 *p_render_data, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_omni_light_count, uint32_t &r_spot_light_count);
-	void _setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows);
+	void _setup_lights(const RenderDataGLES3 *p_render_data, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_omni_light_count, uint32_t &r_spot_light_count, uint32_t &r_directional_shadow_count);
+	void _setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows, float p_shadow_bias = 0.0);
 	void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false);
 	void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false);
+	void _render_shadows(const RenderDataGLES3 *p_render_data);
+	void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, RenderingMethod::RenderInfo *p_render_info = nullptr);
 
 
 	template <PassMode p_pass_mode>
 	template <PassMode p_pass_mode>
 	_FORCE_INLINE_ void _render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass = false);
 	_FORCE_INLINE_ void _render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass = false);
@@ -477,7 +530,7 @@ protected:
 	float screen_space_roughness_limiter_amount = 0.25;
 	float screen_space_roughness_limiter_amount = 0.25;
 	float screen_space_roughness_limiter_limit = 0.18;
 	float screen_space_roughness_limiter_limit = 0.18;
 
 
-	void _render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
+	void _render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas);
 
 
 	/* Camera Attributes */
 	/* Camera Attributes */
 
 

+ 20 - 0
drivers/gles3/shaders/copy.glsl

@@ -6,6 +6,7 @@ mode_copy_section = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY
 mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
 mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
 mode_mipmap = #define MODE_MIPMAP
 mode_mipmap = #define MODE_MIPMAP
 mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
 mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
+mode_cube_to_octahedral = #define CUBE_TO_OCTAHEDRAL \n#define USE_COPY_SECTION
 
 
 #[specializations]
 #[specializations]
 
 
@@ -50,8 +51,20 @@ uniform vec4 color_in;
 uniform highp vec2 pixel_size;
 uniform highp vec2 pixel_size;
 #endif
 #endif
 
 
+#ifdef CUBE_TO_OCTAHEDRAL
+uniform samplerCube source_cube; // texunit:0
+
+vec3 oct_to_vec3(vec2 e) {
+	vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
+	float t = max(-v.z, 0.0);
+	v.xy += t * -sign(v.xy);
+	return normalize(v);
+}
+#else
 uniform sampler2D source; // texunit:0
 uniform sampler2D source; // texunit:0
 
 
+#endif
+
 layout(location = 0) out vec4 frag_color;
 layout(location = 0) out vec4 frag_color;
 
 
 void main() {
 void main() {
@@ -90,4 +103,11 @@ void main() {
 	frag_color += (F + G + L + K) * lesser_weight;
 	frag_color += (F + G + L + K) * lesser_weight;
 	frag_color += (G + H + M + L) * lesser_weight;
 	frag_color += (G + H + M + L) * lesser_weight;
 #endif
 #endif
+
+#ifdef CUBE_TO_OCTAHEDRAL
+	// Treat the UV coordinates as 0-1 encoded octahedral coordinates.
+	vec3 dir = oct_to_vec3(uv_interp * 2.0 - 1.0);
+	frag_color = texture(source_cube, dir);
+
+#endif
 }
 }

+ 494 - 43
drivers/gles3/shaders/scene.glsl

@@ -1,10 +1,8 @@
 /* clang-format off */
 /* clang-format off */
 #[modes]
 #[modes]
 
 
-mode_color = #define BASE_PASS
-mode_color_instancing = #define BASE_PASS \n#define USE_INSTANCING
-mode_additive = #define USE_ADDITIVE_LIGHTING
-mode_additive_instancing = #define USE_ADDITIVE_LIGHTING \n#define USE_INSTANCING
+mode_color = 
+mode_color_instancing = \n#define USE_INSTANCING
 mode_depth = #define MODE_RENDER_DEPTH
 mode_depth = #define MODE_RENDER_DEPTH
 mode_depth_instancing = #define MODE_RENDER_DEPTH \n#define USE_INSTANCING
 mode_depth_instancing = #define MODE_RENDER_DEPTH \n#define USE_INSTANCING
 
 
@@ -17,6 +15,19 @@ DISABLE_LIGHT_SPOT = false
 DISABLE_FOG = false
 DISABLE_FOG = false
 USE_RADIANCE_MAP = true
 USE_RADIANCE_MAP = true
 USE_MULTIVIEW = false
 USE_MULTIVIEW = false
+RENDER_SHADOWS = false
+RENDER_SHADOWS_LINEAR = false
+SHADOW_MODE_PCF_5 = false
+SHADOW_MODE_PCF_13 = false
+LIGHT_USE_PSSM2 = false
+LIGHT_USE_PSSM4 = false
+LIGHT_USE_PSSM_BLEND = false
+BASE_PASS = true
+USE_ADDITIVE_LIGHTING = false
+// We can only use one type of light per additive pass. This means that if USE_ADDITIVE_LIGHTING is defined, and
+// these are false, we are doing a directional light pass.
+ADDITIVE_OMNI = false
+ADDITIVE_SPOT = false
 
 
 
 
 #[vertex]
 #[vertex]
@@ -33,6 +44,12 @@ USE_MULTIVIEW = false
 #endif
 #endif
 #endif
 #endif
 
 
+#ifdef MODE_UNSHADED
+#ifdef USE_ADDITIVE_LIGHTING
+#undef USE_ADDITIVE_LIGHTING
+#endif
+#endif // MODE_UNSHADED
+
 /*
 /*
 from RenderingServer:
 from RenderingServer:
 ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
 ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
@@ -151,13 +168,56 @@ layout(std140) uniform SceneData { // ubo:2
 
 
 	vec3 fog_light_color;
 	vec3 fog_light_color;
 	float fog_sun_scatter;
 	float fog_sun_scatter;
+
+	float shadow_bias;
+	float pad;
 	uint camera_visible_layers;
 	uint camera_visible_layers;
-	uint pad3;
-	uint pad4;
-	uint pad5;
+	bool pancake_shadows;
 }
 }
 scene_data;
 scene_data;
 
 
+#ifdef USE_ADDITIVE_LIGHTING
+
+#if defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
+struct PositionalShadowData {
+	highp mat4 shadow_matrix;
+	highp vec3 light_position;
+	highp float shadow_normal_bias;
+	vec3 pad;
+	highp float shadow_atlas_pixel_size;
+};
+
+layout(std140) uniform PositionalShadows { // ubo:9
+	PositionalShadowData positional_shadows[MAX_LIGHT_DATA_STRUCTS];
+};
+
+uniform lowp uint positional_shadow_index;
+
+#else // ADDITIVE_DIRECTIONAL
+
+struct DirectionalShadowData {
+	highp vec3 direction;
+	highp float shadow_atlas_pixel_size;
+	highp vec4 shadow_normal_bias;
+	highp vec4 shadow_split_offsets;
+	highp mat4 shadow_matrix1;
+	highp mat4 shadow_matrix2;
+	highp mat4 shadow_matrix3;
+	highp mat4 shadow_matrix4;
+	mediump float fade_from;
+	mediump float fade_to;
+	mediump vec2 pad;
+};
+
+layout(std140) uniform DirectionalShadows { // ubo:10
+	DirectionalShadowData directional_shadows[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+};
+
+uniform lowp uint directional_shadow_index;
+
+#endif // !(defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT))
+#endif // USE_ADDITIVE_LIGHTING
+
 #ifdef USE_MULTIVIEW
 #ifdef USE_MULTIVIEW
 layout(std140) uniform MultiviewData { // ubo:8
 layout(std140) uniform MultiviewData { // ubo:8
 	highp mat4 projection_matrix_view[MAX_VIEWS];
 	highp mat4 projection_matrix_view[MAX_VIEWS];
@@ -201,6 +261,19 @@ out vec3 tangent_interp;
 out vec3 binormal_interp;
 out vec3 binormal_interp;
 #endif
 #endif
 
 
+#ifdef USE_ADDITIVE_LIGHTING
+out highp vec4 shadow_coord;
+
+#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
+out highp vec4 shadow_coord2;
+#endif
+
+#ifdef LIGHT_USE_PSSM4
+out highp vec4 shadow_coord3;
+out highp vec4 shadow_coord4;
+#endif //LIGHT_USE_PSSM4
+#endif
+
 #ifdef MATERIAL_UNIFORMS_USED
 #ifdef MATERIAL_UNIFORMS_USED
 
 
 /* clang-format off */
 /* clang-format off */
@@ -351,6 +424,50 @@ void main() {
 	binormal_interp = binormal;
 	binormal_interp = binormal;
 #endif
 #endif
 
 
+	// Calculate shadows.
+#ifdef USE_ADDITIVE_LIGHTING
+#if defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
+	// Apply normal bias at draw time to avoid issues with scaling non-fused geometry.
+	vec3 light_rel_vec = positional_shadows[positional_shadow_index].light_position - vertex_interp;
+	float light_length = length(light_rel_vec);
+	float aNdotL = abs(dot(normalize(normal_interp), normalize(light_rel_vec)));
+	vec3 normal_offset = (1.0 - aNdotL) * positional_shadows[positional_shadow_index].shadow_normal_bias * light_length * normal_interp;
+
+#ifdef ADDITIVE_SPOT
+	// Calculate coord here so we can take advantage of prefetch.
+	shadow_coord = positional_shadows[positional_shadow_index].shadow_matrix * vec4(vertex_interp + normal_offset, 1.0);
+#endif
+
+#ifdef ADDITIVE_OMNI
+	// Can't interpolate unit direction nicely, so forget about prefetch.
+	shadow_coord = vec4(vertex_interp + normal_offset, 1.0);
+#endif
+#else // ADDITIVE_DIRECTIONAL
+	vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(directional_shadows[directional_shadow_index].direction, -normalize(normal_interp))));
+	vec3 normal_offset = base_normal_bias * directional_shadows[directional_shadow_index].shadow_normal_bias.x;
+	shadow_coord = directional_shadows[directional_shadow_index].shadow_matrix1 * vec4(vertex_interp + normal_offset, 1.0);
+
+#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
+	normal_offset = base_normal_bias * directional_shadows[directional_shadow_index].shadow_normal_bias.y;
+	shadow_coord2 = directional_shadows[directional_shadow_index].shadow_matrix2 * vec4(vertex_interp + normal_offset, 1.0);
+#endif
+
+#ifdef LIGHT_USE_PSSM4
+	normal_offset = base_normal_bias * directional_shadows[directional_shadow_index].shadow_normal_bias.z;
+	shadow_coord3 = directional_shadows[directional_shadow_index].shadow_matrix3 * vec4(vertex_interp + normal_offset, 1.0);
+	normal_offset = base_normal_bias * directional_shadows[directional_shadow_index].shadow_normal_bias.w;
+	shadow_coord4 = directional_shadows[directional_shadow_index].shadow_matrix4 * vec4(vertex_interp + normal_offset, 1.0);
+#endif //LIGHT_USE_PSSM4
+
+#endif // !(defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT))
+#endif // USE_ADDITIVE_LIGHTING
+
+#if defined(RENDER_SHADOWS) && !defined(RENDER_SHADOWS_LINEAR)
+	// This is an optimized version of normalize(vertex_interp) * scene_data.shadow_bias / length(vertex_interp).
+	float light_length_sq = dot(vertex_interp, vertex_interp);
+	vertex_interp += vertex_interp * scene_data.shadow_bias / light_length_sq;
+#endif
+
 #if defined(OVERRIDE_POSITION)
 #if defined(OVERRIDE_POSITION)
 	gl_Position = position;
 	gl_Position = position;
 #else
 #else
@@ -372,17 +489,22 @@ void main() {
 #endif
 #endif
 #endif
 #endif
 
 
+#ifdef MODE_UNSHADED
+#ifdef USE_ADDITIVE_LIGHTING
+#undef USE_ADDITIVE_LIGHTING
+#endif
+#endif // MODE_UNSHADED
+
 #ifndef MODE_RENDER_DEPTH
 #ifndef MODE_RENDER_DEPTH
 #include "tonemap_inc.glsl"
 #include "tonemap_inc.glsl"
 #endif
 #endif
 #include "stdlib_inc.glsl"
 #include "stdlib_inc.glsl"
 
 
-/* texture unit usage, N is max_texture_unity-N
+/* texture unit usage, N is max_texture_unit-N
 
 
 1-color correction // In tonemap_inc.glsl
 1-color correction // In tonemap_inc.glsl
 2-radiance
 2-radiance
-3-directional_shadow
-4-positional_shadow
+3-shadow
 5-screen
 5-screen
 6-depth
 6-depth
 
 
@@ -422,6 +544,19 @@ in vec3 normal_interp;
 
 
 in highp vec3 vertex_interp;
 in highp vec3 vertex_interp;
 
 
+#ifdef USE_ADDITIVE_LIGHTING
+in highp vec4 shadow_coord;
+
+#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
+in highp vec4 shadow_coord2;
+#endif
+
+#ifdef LIGHT_USE_PSSM4
+in highp vec4 shadow_coord3;
+in highp vec4 shadow_coord4;
+#endif //LIGHT_USE_PSSM4
+#endif
+
 #ifdef USE_RADIANCE_MAP
 #ifdef USE_RADIANCE_MAP
 
 
 #define RADIANCE_MAX_LOD 5.0
 #define RADIANCE_MAX_LOD 5.0
@@ -483,10 +618,11 @@ layout(std140) uniform SceneData { // ubo:2
 
 
 	vec3 fog_light_color;
 	vec3 fog_light_color;
 	float fog_sun_scatter;
 	float fog_sun_scatter;
+
+	float shadow_bias;
+	float pad;
 	uint camera_visible_layers;
 	uint camera_visible_layers;
-	uint pad3;
-	uint pad4;
-	uint pad5;
+	bool pancake_shadows;
 }
 }
 scene_data;
 scene_data;
 
 
@@ -505,15 +641,17 @@ multiview_data;
 
 
 /* clang-format on */
 /* clang-format on */
 
 
+#ifndef MODE_RENDER_DEPTH
 // Directional light data.
 // Directional light data.
-#ifndef DISABLE_LIGHT_DIRECTIONAL
+#if !defined(DISABLE_LIGHT_DIRECTIONAL) || (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT))
 
 
 struct DirectionalLightData {
 struct DirectionalLightData {
 	mediump vec3 direction;
 	mediump vec3 direction;
 	mediump float energy;
 	mediump float energy;
 	mediump vec3 color;
 	mediump vec3 color;
 	mediump float size;
 	mediump float size;
-	mediump vec3 pad;
+	mediump vec2 pad;
+	mediump float shadow_opacity;
 	mediump float specular;
 	mediump float specular;
 };
 };
 
 
@@ -521,10 +659,15 @@ layout(std140) uniform DirectionalLights { // ubo:7
 	DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
 	DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
 };
 };
 
 
+#if defined(USE_ADDITIVE_LIGHTING) && (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT))
+// Directional shadows can be in the base pass or in the additive passes
+uniform highp sampler2DShadow directional_shadow_atlas; // texunit:-3
+#endif // defined(USE_ADDITIVE_LIGHTING) && (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT))
+
 #endif // !DISABLE_LIGHT_DIRECTIONAL
 #endif // !DISABLE_LIGHT_DIRECTIONAL
 
 
 // Omni and spot light data.
 // Omni and spot light data.
-#if !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
+#if !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
 
 
 struct LightData { // This structure needs to be as packed as possible.
 struct LightData { // This structure needs to be as packed as possible.
 	highp vec3 position;
 	highp vec3 position;
@@ -542,27 +685,119 @@ struct LightData { // This structure needs to be as packed as possible.
 	mediump float shadow_opacity;
 	mediump float shadow_opacity;
 };
 };
 
 
-#ifndef DISABLE_LIGHT_OMNI
+#if !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI)
 layout(std140) uniform OmniLightData { // ubo:5
 layout(std140) uniform OmniLightData { // ubo:5
 	LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
 	LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
 };
 };
+#ifdef BASE_PASS
 uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
 uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
 uniform uint omni_light_count;
 uniform uint omni_light_count;
-#endif
+#endif // BASE_PASS
+#endif // DISABLE_LIGHT_OMNI
 
 
-#ifndef DISABLE_LIGHT_SPOT
+#if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
 layout(std140) uniform SpotLightData { // ubo:6
 layout(std140) uniform SpotLightData { // ubo:6
 	LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
 	LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
 };
 };
+#ifdef BASE_PASS
 uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
 uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
 uniform uint spot_light_count;
 uniform uint spot_light_count;
-#endif
+#endif // BASE_PASS
+#endif // DISABLE_LIGHT_SPOT
+#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
 
 
 #ifdef USE_ADDITIVE_LIGHTING
 #ifdef USE_ADDITIVE_LIGHTING
-uniform highp samplerCubeShadow positional_shadow; // texunit:-4
+#ifdef ADDITIVE_OMNI
+uniform highp samplerCubeShadow omni_shadow_texture; // texunit:-3
+uniform lowp uint omni_light_index;
+#endif
+#ifdef ADDITIVE_SPOT
+uniform highp sampler2DShadow spot_shadow_texture; // texunit:-3
+uniform lowp uint spot_light_index;
+#endif
+
+#if defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
+struct PositionalShadowData {
+	highp mat4 shadow_matrix;
+	highp vec3 light_position;
+	highp float shadow_normal_bias;
+	vec3 pad;
+	highp float shadow_atlas_pixel_size;
+};
+
+layout(std140) uniform PositionalShadows { // ubo:9
+	PositionalShadowData positional_shadows[MAX_LIGHT_DATA_STRUCTS];
+};
+
+uniform lowp uint positional_shadow_index;
+#else // ADDITIVE_DIRECTIONAL
+struct DirectionalShadowData {
+	highp vec3 direction;
+	highp float shadow_atlas_pixel_size;
+	highp vec4 shadow_normal_bias;
+	highp vec4 shadow_split_offsets;
+	highp mat4 shadow_matrix1;
+	highp mat4 shadow_matrix2;
+	highp mat4 shadow_matrix3;
+	highp mat4 shadow_matrix4;
+	mediump float fade_from;
+	mediump float fade_to;
+	mediump vec2 pad;
+};
+
+layout(std140) uniform DirectionalShadows { // ubo:10
+	DirectionalShadowData directional_shadows[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+};
+
+uniform lowp uint directional_shadow_index;
+#endif // !(defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT))
+
+#if !defined(ADDITIVE_OMNI)
+float sample_shadow(highp sampler2DShadow shadow, float shadow_pixel_size, vec4 pos) {
+	float avg = textureProj(shadow, pos);
+#ifdef SHADOW_MODE_PCF_13
+	pos /= pos.w;
+	avg += textureProj(shadow, vec4(pos.xy + vec2(shadow_pixel_size * 2.0, 0.0), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(-shadow_pixel_size * 2.0, 0.0), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, shadow_pixel_size * 2.0), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, -shadow_pixel_size * 2.0), pos.zw));
+
+	// Early bail if distant samples are fully shaded (or none are shaded) to improve performance.
+	if (avg <= 0.000001) {
+		// None shaded at all.
+		return 0.0;
+	} else if (avg >= 4.999999) {
+		// All fully shaded.
+		return 1.0;
+	}
+
+	avg += textureProj(shadow, vec4(pos.xy + vec2(shadow_pixel_size, 0.0), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(-shadow_pixel_size, 0.0), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, shadow_pixel_size), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, -shadow_pixel_size), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(shadow_pixel_size, shadow_pixel_size), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(-shadow_pixel_size, shadow_pixel_size), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(shadow_pixel_size, -shadow_pixel_size), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(-shadow_pixel_size, -shadow_pixel_size), pos.zw));
+	return avg * (1.0 / 13.0);
 #endif
 #endif
 
 
-#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
+#ifdef SHADOW_MODE_PCF_5
+	pos /= pos.w;
+	avg += textureProj(shadow, vec4(pos.xy + vec2(shadow_pixel_size, 0.0), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(-shadow_pixel_size, 0.0), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, shadow_pixel_size), pos.zw));
+	avg += textureProj(shadow, vec4(pos.xy + vec2(0.0, -shadow_pixel_size), pos.zw));
+	return avg * (1.0 / 5.0);
+
+#endif
+
+	return avg;
+}
+#endif //!defined(ADDITIVE_OMNI)
+#endif // USE_ADDITIVE_LIGHTING
+
+#endif // !MODE_RENDER_DEPTH
 
 
 #ifdef USE_MULTIVIEW
 #ifdef USE_MULTIVIEW
 uniform highp sampler2DArray depth_buffer; // texunit:-6
 uniform highp sampler2DArray depth_buffer; // texunit:-6
@@ -589,8 +824,8 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
 	// see https://google.github.io/filament/Filament.md.html
 	// see https://google.github.io/filament/Filament.md.html
 	return mix(vec3(dielectric), albedo, vec3(metallic));
 	return mix(vec3(dielectric), albedo, vec3(metallic));
 }
 }
-
-#if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
+#ifndef MODE_RENDER_DEPTH
+#if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) || defined(USE_ADDITIVE_LIGHTING)
 
 
 float D_GGX(float cos_theta_m, float alpha) {
 float D_GGX(float cos_theta_m, float alpha) {
 	float a = cos_theta_m * alpha;
 	float a = cos_theta_m * alpha;
@@ -787,7 +1022,7 @@ float get_omni_spot_attenuation(float distance, float inv_range, float decay) {
 	return nd * pow(max(distance, 0.0001), -decay);
 	return nd * pow(max(distance, 0.0001), -decay);
 }
 }
 
 
-#ifndef DISABLE_LIGHT_OMNI
+#if !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI)
 void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
 void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 		vec3 backlight,
 		vec3 backlight,
@@ -813,6 +1048,8 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
 		size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
 		size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
 	}
 	}
 
 
+	omni_attenuation *= shadow;
+
 	light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
 	light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 			backlight,
 			backlight,
@@ -831,7 +1068,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
 }
 }
 #endif // !DISABLE_LIGHT_OMNI
 #endif // !DISABLE_LIGHT_OMNI
 
 
-#ifndef DISABLE_LIGHT_SPOT
+#if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
 void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
 void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 		vec3 backlight,
 		vec3 backlight,
@@ -864,6 +1101,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
 		size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
 		size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
 	}
 	}
 
 
+	spot_attenuation *= shadow;
+
 	light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
 	light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 			backlight,
 			backlight,
@@ -879,11 +1118,10 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
 #endif
 #endif
 			diffuse_light, specular_light);
 			diffuse_light, specular_light);
 }
 }
-#endif // !DISABLE_LIGHT_SPOT
+#endif // !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
 
 
 #endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
 #endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
 
 
-#ifndef MODE_RENDER_DEPTH
 vec4 fog_process(vec3 vertex) {
 vec4 fog_process(vec3 vertex) {
 	vec3 fog_color = scene_data.fog_light_color;
 	vec3 fog_color = scene_data.fog_light_color;
 
 
@@ -1191,10 +1429,7 @@ void main() {
 #endif
 #endif
 	}
 	}
 
 
-#endif // BASE_PASS
-
 #ifndef DISABLE_LIGHT_DIRECTIONAL
 #ifndef DISABLE_LIGHT_DIRECTIONAL
-	//diffuse_light = normal; //
 	for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
 	for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
 		light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, true, 1.0, f0, roughness, metallic, 1.0, albedo, alpha,
 		light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, true, 1.0, f0, roughness, metallic, 1.0, albedo, alpha,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
@@ -1220,7 +1455,7 @@ void main() {
 		if (i >= omni_light_count) {
 		if (i >= omni_light_count) {
 			break;
 			break;
 		}
 		}
-		light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 0.0, albedo, alpha,
+		light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 				backlight,
 				backlight,
 #endif
 #endif
@@ -1243,7 +1478,7 @@ void main() {
 		if (i >= spot_light_count) {
 		if (i >= spot_light_count) {
 			break;
 			break;
 		}
 		}
-		light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 0.0, albedo, alpha,
+		light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 				backlight,
 				backlight,
 #endif
 #endif
@@ -1261,7 +1496,7 @@ void main() {
 				diffuse_light, specular_light);
 				diffuse_light, specular_light);
 	}
 	}
 #endif // !DISABLE_LIGHT_SPOT
 #endif // !DISABLE_LIGHT_SPOT
-
+#endif // BASE_PASS
 #endif // !MODE_UNSHADED
 #endif // !MODE_UNSHADED
 
 
 #endif // !MODE_RENDER_DEPTH
 #endif // !MODE_RENDER_DEPTH
@@ -1287,9 +1522,14 @@ void main() {
 #endif // USE_SHADOW_TO_OPACITY
 #endif // USE_SHADOW_TO_OPACITY
 
 
 #ifdef MODE_RENDER_DEPTH
 #ifdef MODE_RENDER_DEPTH
-//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
-#else // !MODE_RENDER_DEPTH
+#ifdef RENDER_SHADOWS_LINEAR
+	// Linearize the depth buffer if rendering cubemap shadows.
+	gl_FragDepth = (length(vertex) + scene_data.shadow_bias) / scene_data.z_far;
+#endif
 
 
+// Nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
+#else // !MODE_RENDER_DEPTH
+#ifdef BASE_PASS
 #ifdef MODE_UNSHADED
 #ifdef MODE_UNSHADED
 	frag_color = vec4(albedo, alpha);
 	frag_color = vec4(albedo, alpha);
 #else
 #else
@@ -1300,21 +1540,15 @@ void main() {
 	ambient_light *= 1.0 - metallic;
 	ambient_light *= 1.0 - metallic;
 
 
 	frag_color = vec4(diffuse_light + specular_light, alpha);
 	frag_color = vec4(diffuse_light + specular_light, alpha);
-#ifdef BASE_PASS
 	frag_color.rgb += emission + ambient_light;
 	frag_color.rgb += emission + ambient_light;
-#endif
-#endif //MODE_UNSHADED
+#endif //!MODE_UNSHADED
 
 
 #ifndef FOG_DISABLED
 #ifndef FOG_DISABLED
 	fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
 	fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
 
 
 #ifndef DISABLE_FOG
 #ifndef DISABLE_FOG
 	if (scene_data.fog_enabled) {
 	if (scene_data.fog_enabled) {
-#ifdef BASE_PASS
 		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
 		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
-#else
-		frag_color.rgb *= (1.0 - fog.a);
-#endif // BASE_PASS
 	}
 	}
 #endif // !DISABLE_FOG
 #endif // !DISABLE_FOG
 #endif // !FOG_DISABLED
 #endif // !FOG_DISABLED
@@ -1331,6 +1565,223 @@ void main() {
 #ifdef USE_COLOR_CORRECTION
 #ifdef USE_COLOR_CORRECTION
 	frag_color.rgb = apply_color_correction(frag_color.rgb, color_correction);
 	frag_color.rgb = apply_color_correction(frag_color.rgb, color_correction);
 #endif
 #endif
+#else // !BASE_PASS
+	frag_color = vec4(0.0, 0.0, 0.0, alpha);
+#endif // !BASE_PASS
+
+/* ADDITIVE LIGHTING PASS */
+#ifdef USE_ADDITIVE_LIGHTING
+	diffuse_light = vec3(0.0);
+	specular_light = vec3(0.0);
+
+#if !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
+
+// Orthogonal shadows
+#if !defined(LIGHT_USE_PSSM2) && !defined(LIGHT_USE_PSSM4)
+	float directional_shadow = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
+#endif // !defined(LIGHT_USE_PSSM2) && !defined(LIGHT_USE_PSSM4)
+
+// PSSM2 shadows
+#ifdef LIGHT_USE_PSSM2
+	float depth_z = -vertex.z;
+	vec4 light_split_offsets = directional_shadows[directional_shadow_index].shadow_split_offsets;
+	//take advantage of prefetch
+	float shadow1 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
+	float shadow2 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord2);
+	float directional_shadow = 1.0;
+
+	if (depth_z < light_split_offsets.y) {
+		float pssm_fade = 0.0;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+		float directional_shadow2 = 1.0;
+		float pssm_blend = 0.0;
+		bool use_blend = true;
+#endif
+		if (depth_z < light_split_offsets.x) {
+			float pssm_fade = 0.0;
+			directional_shadow = shadow1;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+			directional_shadow2 = shadow2;
+			pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
+#endif
+		} else {
+			directional_shadow = shadow2;
+			pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
+#ifdef LIGHT_USE_PSSM_BLEND
+			use_blend = false;
+#endif
+		}
+#ifdef LIGHT_USE_PSSM_BLEND
+		if (use_blend) {
+			directional_shadow = mix(directional_shadow, directional_shadow2, pssm_blend);
+		}
+#endif
+		directional_shadow = mix(directional_shadow, 1.0, pssm_fade);
+	}
+
+#endif //LIGHT_USE_PSSM2
+// PSSM4 shadows
+#ifdef LIGHT_USE_PSSM4
+	float depth_z = -vertex.z;
+	vec4 light_split_offsets = directional_shadows[directional_shadow_index].shadow_split_offsets;
+
+	float shadow1 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
+	float shadow2 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord2);
+	float shadow3 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord3);
+	float shadow4 = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord4);
+	float directional_shadow = 1.0;
+
+	if (depth_z < light_split_offsets.w) {
+		float pssm_fade = 0.0;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+		float directional_shadow2 = 1.0;
+		float pssm_blend = 0.0;
+		bool use_blend = true;
+#endif
+		if (depth_z < light_split_offsets.y) {
+			if (depth_z < light_split_offsets.x) {
+				directional_shadow = shadow1;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+				directional_shadow2 = shadow2;
+
+				pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
+#endif
+			} else {
+				directional_shadow = shadow2;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+				directional_shadow2 = shadow3;
+
+				pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
+#endif
+			}
+		} else {
+			if (depth_z < light_split_offsets.z) {
+				directional_shadow = shadow3;
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+				directional_shadow2 = shadow4;
+				pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z);
+#endif
+
+			} else {
+				directional_shadow = shadow4;
+				pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z);
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+				use_blend = false;
+#endif
+			}
+		}
+#if defined(LIGHT_USE_PSSM_BLEND)
+		if (use_blend) {
+			directional_shadow = mix(directional_shadow, directional_shadow2, pssm_blend);
+		}
+#endif
+		directional_shadow = mix(directional_shadow, 1.0, pssm_fade);
+	}
+
+#endif //LIGHT_USE_PSSM4
+	directional_shadow = mix(directional_shadow, 1.0, smoothstep(directional_shadows[directional_shadow_index].fade_from, directional_shadows[directional_shadow_index].fade_to, vertex.z));
+	directional_shadow = mix(1.0, directional_shadow, directional_lights[directional_shadow_index].shadow_opacity);
+
+	light_compute(normal, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].size, directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, directional_shadow, f0, roughness, metallic, 1.0, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+			backlight,
+#endif
+#ifdef LIGHT_RIM_USED
+			rim, rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+			clearcoat, clearcoat_roughness, normalize(normal_interp),
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+			binormal,
+			tangent, anisotropy,
+#endif
+			diffuse_light,
+			specular_light);
+#endif // !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
+
+#ifdef ADDITIVE_OMNI
+	vec3 light_ray = ((positional_shadows[positional_shadow_index].shadow_matrix * vec4(shadow_coord.xyz, 1.0))).xyz;
+
+	float omni_shadow = texture(omni_shadow_texture, vec4(light_ray, length(light_ray) * omni_lights[omni_light_index].inv_radius));
+	omni_shadow = mix(1.0, omni_shadow, omni_lights[omni_light_index].shadow_opacity);
+
+	light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+			backlight,
+#endif
+#ifdef LIGHT_RIM_USED
+			rim,
+			rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+			clearcoat, clearcoat_roughness, normalize(normal_interp),
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+			binormal, tangent, anisotropy,
+#endif
+			diffuse_light, specular_light);
+#endif // ADDITIVE_OMNI
+
+#ifdef ADDITIVE_SPOT
+	float spot_shadow = sample_shadow(spot_shadow_texture, positional_shadows[positional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
+	spot_shadow = mix(1.0, spot_shadow, spot_lights[spot_light_index].shadow_opacity);
+
+	light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+			backlight,
+#endif
+#ifdef LIGHT_RIM_USED
+			rim,
+			rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+			clearcoat, clearcoat_roughness, normalize(normal_interp),
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+			tangent,
+			binormal, anisotropy,
+#endif
+			diffuse_light, specular_light);
+
+#endif // ADDITIVE_SPOT
+
+	diffuse_light *= albedo;
+	diffuse_light *= 1.0 - metallic;
+	vec3 additive_light_color = diffuse_light + specular_light;
+
+#ifndef FOG_DISABLED
+	fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
+
+#ifndef DISABLE_FOG
+	if (scene_data.fog_enabled) {
+		additive_light_color *= (1.0 - fog.a);
+	}
+#endif // !DISABLE_FOG
+#endif // !FOG_DISABLED
+
+	// Tonemap before writing as we are writing to an sRGB framebuffer
+	additive_light_color *= exposure;
+	additive_light_color = apply_tonemapping(additive_light_color, white);
+	additive_light_color = linear_to_srgb(additive_light_color);
+
+#ifdef USE_BCS
+	additive_light_color = apply_bcs(additive_light_color, bcs);
+#endif
+
+#ifdef USE_COLOR_CORRECTION
+	additive_light_color = apply_color_correction(additive_light_color, color_correction);
+#endif
+
+	frag_color.rgb += additive_light_color;
+#endif // USE_ADDITIVE_LIGHTING
 
 
 #endif //!MODE_RENDER_DEPTH
 #endif //!MODE_RENDER_DEPTH
 }
 }

+ 471 - 5
drivers/gles3/storage/light_storage.cpp

@@ -31,6 +31,8 @@
 #ifdef GLES3_ENABLED
 #ifdef GLES3_ENABLED
 
 
 #include "light_storage.h"
 #include "light_storage.h"
+#include "../rasterizer_gles3.h"
+#include "../rasterizer_scene_gles3.h"
 #include "config.h"
 #include "config.h"
 #include "texture_storage.h"
 #include "texture_storage.h"
 
 
@@ -358,6 +360,20 @@ RID LightStorage::light_instance_create(RID p_light) {
 void LightStorage::light_instance_free(RID p_light_instance) {
 void LightStorage::light_instance_free(RID p_light_instance) {
 	LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
 	LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
 	ERR_FAIL_NULL(light_instance);
 	ERR_FAIL_NULL(light_instance);
+
+	// Remove from shadow atlases.
+	for (const RID &E : light_instance->shadow_atlases) {
+		ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(E);
+		ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_light_instance));
+		uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
+		uint32_t q = (key >> QUADRANT_SHIFT) & 0x3;
+		uint32_t s = key & SHADOW_INDEX_MASK;
+
+		shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
+
+		shadow_atlas->shadow_owners.erase(p_light_instance);
+	}
+
 	light_instance_owner.free(p_light_instance);
 	light_instance_owner.free(p_light_instance);
 }
 }
 
 
@@ -376,9 +392,26 @@ void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_a
 }
 }
 
 
 void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
 void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
+	LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+	ERR_FAIL_NULL(light_instance);
+
+	ERR_FAIL_INDEX(p_pass, 6);
+
+	light_instance->shadow_transform[p_pass].camera = p_projection;
+	light_instance->shadow_transform[p_pass].transform = p_transform;
+	light_instance->shadow_transform[p_pass].farplane = p_far;
+	light_instance->shadow_transform[p_pass].split = p_split;
+	light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale;
+	light_instance->shadow_transform[p_pass].range_begin = p_range_begin;
+	light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size;
+	light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale;
 }
 }
 
 
 void LightStorage::light_instance_mark_visible(RID p_light_instance) {
 void LightStorage::light_instance_mark_visible(RID p_light_instance) {
+	LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+	ERR_FAIL_NULL(light_instance);
+
+	light_instance->last_scene_pass = RasterizerSceneGLES3::get_singleton()->get_scene_pass();
 }
 }
 
 
 /* PROBE API */
 /* PROBE API */
@@ -598,33 +631,466 @@ void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transfo
 /* SHADOW ATLAS API */
 /* SHADOW ATLAS API */
 
 
 RID LightStorage::shadow_atlas_create() {
 RID LightStorage::shadow_atlas_create() {
-	return RID();
+	return shadow_atlas_owner.make_rid(ShadowAtlas());
 }
 }
 
 
 void LightStorage::shadow_atlas_free(RID p_atlas) {
 void LightStorage::shadow_atlas_free(RID p_atlas) {
+	shadow_atlas_set_size(p_atlas, 0);
+	shadow_atlas_owner.free(p_atlas);
 }
 }
 
 
 void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
 void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
+	ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
+	ERR_FAIL_NULL(shadow_atlas);
+	ERR_FAIL_COND(p_size < 0);
+	p_size = next_power_of_2(p_size);
+
+	if (p_size == shadow_atlas->size && p_16_bits == shadow_atlas->use_16_bits) {
+		return;
+	}
+
+	for (uint32_t i = 0; i < 4; i++) {
+		// Clear all subdivisions and free shadows.
+		for (uint32_t j = 0; j < shadow_atlas->quadrants[i].textures.size(); j++) {
+			glDeleteTextures(1, &shadow_atlas->quadrants[i].textures[j]);
+			glDeleteFramebuffers(1, &shadow_atlas->quadrants[i].fbos[j]);
+		}
+		shadow_atlas->quadrants[i].textures.clear();
+		shadow_atlas->quadrants[i].fbos.clear();
+
+		shadow_atlas->quadrants[i].shadows.clear();
+		shadow_atlas->quadrants[i].shadows.resize(shadow_atlas->quadrants[i].subdivision * shadow_atlas->quadrants[i].subdivision);
+	}
+
+	// Erase shadow atlas reference from lights.
+	for (const KeyValue<RID, uint32_t> &E : shadow_atlas->shadow_owners) {
+		LightInstance *li = light_instance_owner.get_or_null(E.key);
+		ERR_CONTINUE(!li);
+		li->shadow_atlases.erase(p_atlas);
+	}
+
+	if (shadow_atlas->debug_texture != 0) {
+		glDeleteTextures(1, &shadow_atlas->debug_texture);
+	}
+
+	if (shadow_atlas->debug_fbo != 0) {
+		glDeleteFramebuffers(1, &shadow_atlas->debug_fbo);
+	}
+
+	// Clear owners.
+	shadow_atlas->shadow_owners.clear();
+
+	shadow_atlas->size = p_size;
+	shadow_atlas->use_16_bits = p_16_bits;
 }
 }
 
 
 void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
 void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
+	ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
+	ERR_FAIL_NULL(shadow_atlas);
+	ERR_FAIL_INDEX(p_quadrant, 4);
+	ERR_FAIL_INDEX(p_subdivision, 16384);
+
+	uint32_t subdiv = next_power_of_2(p_subdivision);
+	if (subdiv & 0xaaaaaaaa) { // sqrt(subdiv) must be integer.
+		subdiv <<= 1;
+	}
+
+	subdiv = int(Math::sqrt((float)subdiv));
+
+	if (shadow_atlas->quadrants[p_quadrant].subdivision == subdiv) {
+		return;
+	}
+
+	// Erase all data from quadrant.
+	for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) {
+		if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) {
+			shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
+			LightInstance *li = light_instance_owner.get_or_null(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
+			ERR_CONTINUE(!li);
+			li->shadow_atlases.erase(p_atlas);
+		}
+	}
+
+	for (uint32_t j = 0; j < shadow_atlas->quadrants[p_quadrant].textures.size(); j++) {
+		glDeleteTextures(1, &shadow_atlas->quadrants[p_quadrant].textures[j]);
+		glDeleteFramebuffers(1, &shadow_atlas->quadrants[p_quadrant].fbos[j]);
+	}
+
+	shadow_atlas->quadrants[p_quadrant].textures.clear();
+	shadow_atlas->quadrants[p_quadrant].fbos.clear();
+
+	shadow_atlas->quadrants[p_quadrant].shadows.clear();
+	shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv);
+	shadow_atlas->quadrants[p_quadrant].subdivision = subdiv;
+
+	// Cache the smallest subdiv (for faster allocation in light update).
+
+	shadow_atlas->smallest_subdiv = 1 << 30;
+
+	for (int i = 0; i < 4; i++) {
+		if (shadow_atlas->quadrants[i].subdivision) {
+			shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision);
+		}
+	}
+
+	if (shadow_atlas->smallest_subdiv == 1 << 30) {
+		shadow_atlas->smallest_subdiv = 0;
+	}
+
+	// Re-sort the size orders, simple bubblesort for 4 elements.
+
+	int swaps = 0;
+	do {
+		swaps = 0;
+
+		for (int i = 0; i < 3; i++) {
+			if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) {
+				SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]);
+				swaps++;
+			}
+		}
+	} while (swaps > 0);
+}
+
+bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) {
+	ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
+	ERR_FAIL_NULL_V(shadow_atlas, false);
+
+	LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+	ERR_FAIL_NULL_V(li, false);
+
+	if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) {
+		return false;
+	}
+
+	uint32_t quad_size = shadow_atlas->size >> 1;
+	int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage));
+
+	int valid_quadrants[4];
+	int valid_quadrant_count = 0;
+	int best_size = -1; // Best size found.
+	int best_subdiv = -1; // Subdiv for the best size.
+
+	// Find the quadrants this fits into, and the best possible size it can fit into.
+	for (int i = 0; i < 4; i++) {
+		int q = shadow_atlas->size_order[i];
+		int sd = shadow_atlas->quadrants[q].subdivision;
+		if (sd == 0) {
+			continue; // Unused.
+		}
+
+		int max_fit = quad_size / sd;
+
+		if (best_size != -1 && max_fit > best_size) {
+			break; // Too large.
+		}
+
+		valid_quadrants[valid_quadrant_count++] = q;
+		best_subdiv = sd;
+
+		if (max_fit >= desired_fit) {
+			best_size = max_fit;
+		}
+	}
+
+	ERR_FAIL_COND_V(valid_quadrant_count == 0, false);
+
+	uint64_t tick = OS::get_singleton()->get_ticks_msec();
+
+	uint32_t old_key = SHADOW_INVALID;
+	uint32_t old_quadrant = SHADOW_INVALID;
+	uint32_t old_shadow = SHADOW_INVALID;
+	int old_subdivision = -1;
+
+	bool should_realloc = false;
+	bool should_redraw = false;
+
+	if (shadow_atlas->shadow_owners.has(p_light_instance)) {
+		old_key = shadow_atlas->shadow_owners[p_light_instance];
+		old_quadrant = (old_key >> QUADRANT_SHIFT) & 0x3;
+		old_shadow = old_key & SHADOW_INDEX_MASK;
+
+		// Only re-allocate if a better option is available, and enough time has passed.
+		should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
+		should_redraw = shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].version != p_light_version;
+
+		if (!should_realloc) {
+			shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = p_light_version;
+			// Already existing, see if it should redraw or it's just OK.
+			return should_redraw;
+		}
+
+		old_subdivision = shadow_atlas->quadrants[old_quadrant].subdivision;
+	}
+
+	bool is_omni = li->light_type == RS::LIGHT_OMNI;
+	bool found_shadow = false;
+	int new_quadrant = -1;
+	int new_shadow = -1;
+
+	found_shadow = _shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, is_omni, new_quadrant, new_shadow);
+
+	// For new shadows if we found an atlas.
+	// Or for existing shadows that found a better atlas.
+	if (found_shadow) {
+		if (old_quadrant != SHADOW_INVALID) {
+			shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = 0;
+			shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].owner = RID();
+		}
+
+		uint32_t new_key = new_quadrant << QUADRANT_SHIFT;
+		new_key |= new_shadow;
+
+		ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
+		_shadow_atlas_invalidate_shadow(sh, p_atlas, shadow_atlas, new_quadrant, new_shadow);
+
+		sh->owner = p_light_instance;
+		sh->owner_is_omni = is_omni;
+		sh->alloc_tick = tick;
+		sh->version = p_light_version;
+
+		li->shadow_atlases.insert(p_atlas);
+
+		// Update it in map.
+		shadow_atlas->shadow_owners[p_light_instance] = new_key;
+		// Make it dirty, as it should redraw anyway.
+		return true;
+	}
+
+	return should_redraw;
 }
 }
 
 
-bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
+bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, bool is_omni, int &r_quadrant, int &r_shadow) {
+	for (int i = p_quadrant_count - 1; i >= 0; i--) {
+		int qidx = p_in_quadrants[i];
+
+		if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) {
+			return false;
+		}
+
+		// Look for an empty space.
+		int sc = shadow_atlas->quadrants[qidx].shadows.size();
+		const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr();
+
+		// We have a free space in this quadrant, allocate a texture and use it.
+		if (sc > (int)shadow_atlas->quadrants[qidx].textures.size()) {
+			GLuint fbo_id = 0;
+			glGenFramebuffers(1, &fbo_id);
+			glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
+
+			GLuint texture_id = 0;
+			glGenTextures(1, &texture_id);
+			glActiveTexture(GL_TEXTURE0);
+
+			int size = (shadow_atlas->size >> 1) / shadow_atlas->quadrants[qidx].subdivision;
+
+			GLenum format = shadow_atlas->use_16_bits ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT24;
+			GLenum type = shadow_atlas->use_16_bits ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
+
+			if (is_omni) {
+				glBindTexture(GL_TEXTURE_CUBE_MAP, texture_id);
+				for (int id = 0; id < 6; id++) {
+					glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + id, 0, format, size / 2, size / 2, 0, GL_DEPTH_COMPONENT, type, nullptr);
+				}
+
+				glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+				glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+
+				glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
+				glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
+
+				glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X, texture_id, 0);
+
+#ifdef DEBUG_ENABLED
+				GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+				if (status != GL_FRAMEBUFFER_COMPLETE) {
+					ERR_PRINT("Could not create omni light shadow framebuffer, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
+				}
+#endif
+				glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+			} else {
+				glBindTexture(GL_TEXTURE_2D, texture_id);
+
+				glTexImage2D(GL_TEXTURE_2D, 0, format, size, size, 0, GL_DEPTH_COMPONENT, type, nullptr);
+
+				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
+				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
+
+				glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture_id, 0);
+
+				glBindTexture(GL_TEXTURE_2D, 0);
+			}
+			glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+			r_quadrant = qidx;
+			r_shadow = shadow_atlas->quadrants[qidx].textures.size();
+
+			shadow_atlas->quadrants[qidx].textures.push_back(texture_id);
+			shadow_atlas->quadrants[qidx].fbos.push_back(fbo_id);
+
+			return true;
+		}
+
+		int found_used_idx = -1; // Found existing one, must steal it.
+		uint64_t min_pass = 0; // Pass of the existing one, try to use the least recently used one (LRU fashion).
+
+		for (int j = 0; j < sc; j++) {
+			LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
+			ERR_CONTINUE(!sli);
+
+			if (sli->last_scene_pass != RasterizerSceneGLES3::get_singleton()->get_scene_pass()) {
+				// Was just allocated, don't kill it so soon, wait a bit.
+				if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
+					continue;
+				}
+
+				if (found_used_idx == -1 || sli->last_scene_pass < min_pass) {
+					found_used_idx = j;
+					min_pass = sli->last_scene_pass;
+				}
+			}
+		}
+
+		if (found_used_idx != -1) {
+			r_quadrant = qidx;
+			r_shadow = found_used_idx;
+
+			return true;
+		}
+	}
+
 	return false;
 	return false;
 }
 }
 
 
+void LightStorage::_shadow_atlas_invalidate_shadow(ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx) {
+	if (p_shadow->owner.is_valid()) {
+		LightInstance *sli = light_instance_owner.get_or_null(p_shadow->owner);
+
+		p_shadow_atlas->shadow_owners.erase(p_shadow->owner);
+		p_shadow->version = 0;
+		p_shadow->owner = RID();
+		sli->shadow_atlases.erase(p_atlas);
+	}
+}
+
 void LightStorage::shadow_atlas_update(RID p_atlas) {
 void LightStorage::shadow_atlas_update(RID p_atlas) {
+	// Do nothing as there is no shadow atlas texture.
 }
 }
 
 
-void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
+/* DIRECTIONAL SHADOW */
+
+// Create if necessary and clear.
+void LightStorage::update_directional_shadow_atlas() {
+	if (directional_shadow.depth == 0 && directional_shadow.size > 0) {
+		glGenFramebuffers(1, &directional_shadow.fbo);
+		glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo);
+
+		glGenTextures(1, &directional_shadow.depth);
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
+
+		GLenum format = directional_shadow.use_16_bits ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT24;
+		GLenum type = directional_shadow.use_16_bits ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
+
+		glTexImage2D(GL_TEXTURE_2D, 0, format, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, type, nullptr);
+
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
+
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0);
+	}
+	glDepthMask(GL_TRUE);
+	glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo);
+	RasterizerGLES3::clear_depth(1.0);
+	glClear(GL_DEPTH_BUFFER_BIT);
+
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glBindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 }
 
 
-int LightStorage::get_directional_light_shadow_size(RID p_light_intance) {
-	return 0;
+void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
+	p_size = nearest_power_of_2_templated(p_size);
+
+	if (directional_shadow.size == p_size && directional_shadow.use_16_bits == p_16_bits) {
+		return;
+	}
+
+	directional_shadow.size = p_size;
+	directional_shadow.use_16_bits = p_16_bits;
+
+	if (directional_shadow.depth != 0) {
+		glDeleteTextures(1, &directional_shadow.depth);
+		directional_shadow.depth = 0;
+		glDeleteFramebuffers(1, &directional_shadow.fbo);
+		directional_shadow.fbo = 0;
+	}
 }
 }
 
 
 void LightStorage::set_directional_shadow_count(int p_count) {
 void LightStorage::set_directional_shadow_count(int p_count) {
+	directional_shadow.light_count = p_count;
+	directional_shadow.current_light = 0;
+}
+
+static Rect2i _get_directional_shadow_rect(int p_size, int p_shadow_count, int p_shadow_index) {
+	int split_h = 1;
+	int split_v = 1;
+
+	while (split_h * split_v < p_shadow_count) {
+		if (split_h == split_v) {
+			split_h <<= 1;
+		} else {
+			split_v <<= 1;
+		}
+	}
+
+	Rect2i rect(0, 0, p_size, p_size);
+	rect.size.width /= split_h;
+	rect.size.height /= split_v;
+
+	rect.position.x = rect.size.width * (p_shadow_index % split_h);
+	rect.position.y = rect.size.height * (p_shadow_index / split_h);
+
+	return rect;
+}
+
+Rect2i LightStorage::get_directional_shadow_rect() {
+	return _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, directional_shadow.current_light);
+}
+
+int LightStorage::get_directional_light_shadow_size(RID p_light_instance) {
+	ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0);
+
+	Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0);
+
+	LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+	ERR_FAIL_NULL_V(light_instance, 0);
+
+	switch (light_directional_get_shadow_mode(light_instance->light)) {
+		case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
+			break; //none
+		case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS:
+			r.size.height /= 2;
+			break;
+		case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS:
+			r.size /= 2;
+			break;
+	}
+
+	return MAX(r.size.width, r.size.height);
 }
 }
 
 
 #endif // !GLES3_ENABLED
 #endif // !GLES3_ENABLED

+ 378 - 23
drivers/gles3/storage/light_storage.h

@@ -73,6 +73,19 @@ struct Light {
 
 
 /* Light instance */
 /* Light instance */
 struct LightInstance {
 struct LightInstance {
+	struct ShadowTransform {
+		Projection camera;
+		Transform3D transform;
+		float farplane;
+		float split;
+		float bias_scale;
+		float shadow_texel_size;
+		float range_begin;
+		Rect2 atlas_rect;
+		Vector2 uv_scale;
+	};
+
+	ShadowTransform shadow_transform[6];
 	RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
 	RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
 
 
 	AABB aabb;
 	AABB aabb;
@@ -80,10 +93,6 @@ struct LightInstance {
 	RID light;
 	RID light;
 	Transform3D transform;
 	Transform3D transform;
 
 
-	Vector3 light_vector;
-	Vector3 spot_vector;
-	float linear_att = 0.0;
-
 	uint64_t shadow_pass = 0;
 	uint64_t shadow_pass = 0;
 	uint64_t last_scene_pass = 0;
 	uint64_t last_scene_pass = 0;
 	uint64_t last_scene_shadow_pass = 0;
 	uint64_t last_scene_shadow_pass = 0;
@@ -93,7 +102,10 @@ struct LightInstance {
 
 
 	Rect2 directional_rect;
 	Rect2 directional_rect;
 
 
-	uint32_t gl_id = -1;
+	HashSet<RID> shadow_atlases; // Shadow atlases where this light is registered.
+
+	int32_t gl_id = -1;
+	int32_t shadow_id = -1;
 
 
 	LightInstance() {}
 	LightInstance() {}
 };
 };
@@ -144,6 +156,14 @@ struct Lightmap {
 };
 };
 
 
 class LightStorage : public RendererLightStorage {
 class LightStorage : public RendererLightStorage {
+public:
+	enum ShadowAtlastQuadrant {
+		QUADRANT_SHIFT = 27,
+		OMNI_LIGHT_FLAG = 1 << 26,
+		SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1,
+		SHADOW_INVALID = 0xFFFFFFFF
+	};
+
 private:
 private:
 	static LightStorage *singleton;
 	static LightStorage *singleton;
 
 
@@ -162,6 +182,63 @@ private:
 
 
 	mutable RID_Owner<Lightmap, true> lightmap_owner;
 	mutable RID_Owner<Lightmap, true> lightmap_owner;
 
 
+	/* SHADOW ATLAS */
+
+	// Note: The ShadowAtlas in the OpenGL is virtual. Each light gets assigned its
+	// own texture which is the same size as it would be if it were in a real atlas.
+	// This allows us to maintain the same behavior as the other renderers.
+
+	struct ShadowAtlas {
+		struct Quadrant {
+			uint32_t subdivision = 0;
+
+			struct Shadow {
+				RID owner;
+				bool owner_is_omni = false;
+				uint64_t version = 0;
+				uint64_t alloc_tick = 0;
+
+				Shadow() {}
+			};
+
+			Vector<Shadow> shadows;
+			LocalVector<GLuint> textures;
+			LocalVector<GLuint> fbos;
+
+			Quadrant() {}
+		} quadrants[4];
+
+		// Ordered from smallest (worst) shadow size to largest (best).
+		int size_order[4] = { 0, 1, 2, 3 };
+		uint32_t smallest_subdiv = 0;
+
+		int size = 0;
+		bool use_16_bits = true;
+
+		GLuint debug_texture = 0;
+		GLuint debug_fbo = 0;
+
+		HashMap<RID, uint32_t> shadow_owners;
+	};
+
+	uint64_t shadow_atlas_realloc_tolerance_msec = 500;
+	RID_Owner<ShadowAtlas> shadow_atlas_owner;
+
+	void _shadow_atlas_invalidate_shadow(ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx);
+	bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, bool p_omni, int &r_quadrant, int &r_shadow);
+
+	/* DIRECTIONAL SHADOW */
+
+	struct DirectionalShadow {
+		GLuint depth = 0;
+		GLuint fbo = 0;
+
+		int light_count = 0;
+		int size = 0;
+		bool use_16_bits = true;
+		int current_light = 0;
+	} directional_shadow;
+
 public:
 public:
 	static LightStorage *get_singleton();
 	static LightStorage *get_singleton();
 
 
@@ -307,15 +384,169 @@ public:
 	virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
 	virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
 	virtual void light_instance_mark_visible(RID p_light_instance) override;
 	virtual void light_instance_mark_visible(RID p_light_instance) override;
 
 
+	_FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->light;
+	}
+
+	_FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->transform;
+	}
+
+	_FORCE_INLINE_ AABB light_instance_get_base_aabb(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->aabb;
+	}
+
+	_FORCE_INLINE_ void light_instance_set_cull_mask(RID p_light_instance, uint32_t p_cull_mask) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		li->cull_mask = p_cull_mask;
+	}
+
+	_FORCE_INLINE_ uint32_t light_instance_get_cull_mask(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->cull_mask;
+	}
+
+	_FORCE_INLINE_ GLuint light_instance_get_shadow_texture(RID p_light_instance, RID p_shadow_atlas) {
+#ifdef DEBUG_ENABLED
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
+#endif
+		ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
+		ERR_FAIL_NULL_V(shadow_atlas, 0);
+#ifdef DEBUG_ENABLED
+		ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
+#endif
+		uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
+
+		uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3;
+		uint32_t shadow = key & SHADOW_INDEX_MASK;
+
+		ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), 0);
+
+		return shadow_atlas_get_quadrant_shadow_texture(p_shadow_atlas, quadrant, shadow);
+	}
+
+	_FORCE_INLINE_ bool light_instance_has_shadow_atlas(RID p_light_instance, RID p_shadow_atlas) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_atlases.has(p_shadow_atlas);
+	}
+
+	_FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) {
+#ifdef DEBUG_ENABLED
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
+#endif
+		ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
+		ERR_FAIL_NULL_V(shadow_atlas, 0);
+#ifdef DEBUG_ENABLED
+		ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
+#endif
+		uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
+
+		uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3;
+
+		uint32_t quadrant_size = shadow_atlas->size >> 1;
+
+		uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+
+		return float(1.0) / shadow_size;
+	}
+
+	_FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].camera;
+	}
+
+	_FORCE_INLINE_ Transform3D light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].transform;
+	}
+	_FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].bias_scale;
+	}
+	_FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].farplane;
+	}
+	_FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].range_begin;
+	}
+
+	_FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].uv_scale;
+	}
+
+	_FORCE_INLINE_ void light_instance_set_directional_shadow_atlas_rect(RID p_light_instance, int p_index, const Rect2 p_atlas_rect) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		li->shadow_transform[p_index].atlas_rect = p_atlas_rect;
+	}
+
+	_FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].atlas_rect;
+	}
+
+	_FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].split;
+	}
+
+	_FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].shadow_texel_size;
+	}
+
+	_FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		li->last_pass = p_pass;
+	}
+
+	_FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->last_pass;
+	}
+
+	_FORCE_INLINE_ void light_instance_set_shadow_pass(RID p_light_instance, uint64_t p_pass) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		li->last_scene_shadow_pass = p_pass;
+	}
+
+	_FORCE_INLINE_ uint64_t light_instance_get_shadow_pass(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->last_scene_shadow_pass;
+	}
+
+	_FORCE_INLINE_ void light_instance_set_directional_rect(RID p_light_instance, const Rect2 &p_directional_rect) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		li->directional_rect = p_directional_rect;
+	}
+
+	_FORCE_INLINE_ Rect2 light_instance_get_directional_rect(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->directional_rect;
+	}
+
 	_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
 	_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
 		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
 		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
 		return li->light_type;
 		return li->light_type;
 	}
 	}
-	_FORCE_INLINE_ uint32_t light_instance_get_gl_id(RID p_light_instance) {
+
+	_FORCE_INLINE_ int32_t light_instance_get_gl_id(RID p_light_instance) {
 		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
 		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
 		return li->gl_id;
 		return li->gl_id;
 	}
 	}
 
 
+	_FORCE_INLINE_ int32_t light_instance_get_shadow_id(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_id;
+	}
+
 	/* PROBE API */
 	/* PROBE API */
 
 
 	virtual RID reflection_probe_allocate() override;
 	virtual RID reflection_probe_allocate() override;
@@ -389,23 +620,6 @@ public:
 	virtual void lightmap_set_probe_capture_update_speed(float p_speed) override;
 	virtual void lightmap_set_probe_capture_update_speed(float p_speed) override;
 	virtual float lightmap_get_probe_capture_update_speed() const override;
 	virtual float lightmap_get_probe_capture_update_speed() const override;
 
 
-	/* LIGHT SHADOW MAPPING */
-	/*
-	struct CanvasOccluder {
-		RID self;
-
-		GLuint vertex_id; // 0 means, unconfigured
-		GLuint index_id; // 0 means, unconfigured
-		LocalVector<Vector2> lines;
-		int len;
-	};
-
-	RID_Owner<CanvasOccluder> canvas_occluder_owner;
-
-	RID canvas_light_occluder_create();
-	void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector<Vector2> &p_lines);
-	*/
-
 	/* LIGHTMAP INSTANCE */
 	/* LIGHTMAP INSTANCE */
 
 
 	virtual RID lightmap_instance_create(RID p_lightmap) override;
 	virtual RID lightmap_instance_create(RID p_lightmap) override;
@@ -413,6 +627,7 @@ public:
 	virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
 	virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
 
 
 	/* SHADOW ATLAS API */
 	/* SHADOW ATLAS API */
+	bool owns_shadow_atlas(RID p_rid) { return shadow_atlas_owner.owns(p_rid); };
 
 
 	virtual RID shadow_atlas_create() override;
 	virtual RID shadow_atlas_create() override;
 	virtual void shadow_atlas_free(RID p_atlas) override;
 	virtual void shadow_atlas_free(RID p_atlas) override;
@@ -420,11 +635,151 @@ public:
 	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
 	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
 	virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
 	virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
 
 
+	_FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_instance) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, false);
+		return atlas->shadow_owners.has(p_light_instance);
+	}
+	_FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_instance) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, -1);
+		return atlas->shadow_owners[p_light_instance];
+	}
+
+	_FORCE_INLINE_ int shadow_atlas_get_size(RID p_atlas) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, 0);
+		return atlas->size;
+	}
+
+	_FORCE_INLINE_ GLuint shadow_atlas_get_debug_fb(RID p_atlas) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, 0);
+
+		if (atlas->debug_fbo != 0) {
+			return atlas->debug_fbo;
+		}
+		glGenFramebuffers(1, &atlas->debug_fbo);
+		glBindFramebuffer(GL_FRAMEBUFFER, atlas->debug_fbo);
+
+		if (atlas->debug_texture == 0) {
+			atlas->debug_texture = shadow_atlas_get_debug_texture(p_atlas);
+		}
+
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D, atlas->debug_texture);
+
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, atlas->debug_texture, 0);
+
+		glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+		return atlas->debug_fbo;
+	}
+
+	_FORCE_INLINE_ GLuint shadow_atlas_get_debug_texture(RID p_atlas) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, 0);
+
+		if (atlas->debug_texture != 0) {
+			return atlas->debug_texture;
+		}
+
+		glGenTextures(1, &atlas->debug_texture);
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D, atlas->debug_texture);
+
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, atlas->size, atlas->size, 0, GL_RED, GL_UNSIGNED_INT, nullptr);
+
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
+
+		glBindTexture(GL_TEXTURE_2D, 0);
+
+		return atlas->debug_texture;
+	}
+
+	_FORCE_INLINE_ int shadow_atlas_get_quadrant_shadows_length(RID p_atlas, uint32_t p_quadrant) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, 0);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
+		return atlas->quadrants[p_quadrant].shadows.size();
+	}
+
+	_FORCE_INLINE_ uint32_t shadow_atlas_get_quadrant_shadows_allocated(RID p_atlas, uint32_t p_quadrant) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, 0);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
+		return atlas->quadrants[p_quadrant].textures.size();
+	}
+
+	_FORCE_INLINE_ uint32_t shadow_atlas_get_quadrant_subdivision(RID p_atlas, uint32_t p_quadrant) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, 0);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
+		return atlas->quadrants[p_quadrant].subdivision;
+	}
+
+	_FORCE_INLINE_ GLuint shadow_atlas_get_quadrant_shadow_texture(RID p_atlas, uint32_t p_quadrant, uint32_t p_shadow) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, 0);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_shadow, atlas->quadrants[p_quadrant].textures.size(), 0);
+		return atlas->quadrants[p_quadrant].textures[p_shadow];
+	}
+
+	_FORCE_INLINE_ GLuint shadow_atlas_get_quadrant_shadow_fb(RID p_atlas, uint32_t p_quadrant, uint32_t p_shadow) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, 0);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_shadow, atlas->quadrants[p_quadrant].fbos.size(), 0);
+		return atlas->quadrants[p_quadrant].fbos[p_shadow];
+	}
+
+	_FORCE_INLINE_ int shadow_atlas_get_quadrant_shadow_size(RID p_atlas, uint32_t p_quadrant) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, 0);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
+		return (atlas->size >> 1) / atlas->quadrants[p_quadrant].subdivision;
+	}
+
+	_FORCE_INLINE_ bool shadow_atlas_get_quadrant_shadow_is_omni(RID p_atlas, uint32_t p_quadrant, uint32_t p_shadow) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_NULL_V(atlas, false);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, false);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_shadow, (uint32_t)atlas->quadrants[p_quadrant].shadows.size(), false);
+		return atlas->quadrants[p_quadrant].shadows[p_shadow].owner_is_omni;
+	}
+
 	virtual void shadow_atlas_update(RID p_atlas) override;
 	virtual void shadow_atlas_update(RID p_atlas) override;
 
 
 	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
 	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
 	virtual int get_directional_light_shadow_size(RID p_light_intance) override;
 	virtual int get_directional_light_shadow_size(RID p_light_intance) override;
 	virtual void set_directional_shadow_count(int p_count) override;
 	virtual void set_directional_shadow_count(int p_count) override;
+
+	Rect2i get_directional_shadow_rect();
+	void update_directional_shadow_atlas();
+
+	_FORCE_INLINE_ GLuint directional_shadow_get_texture() {
+		return directional_shadow.depth;
+	}
+
+	_FORCE_INLINE_ int directional_shadow_get_size() {
+		return directional_shadow.size;
+	}
+
+	_FORCE_INLINE_ GLuint direction_shadow_get_fb() {
+		return directional_shadow.fbo;
+	}
+
+	_FORCE_INLINE_ void directional_shadow_increase_current_light() {
+		directional_shadow.current_light++;
+	}
 };
 };
 
 
 } // namespace GLES3
 } // namespace GLES3

+ 0 - 4
scene/3d/light_3d.cpp

@@ -172,10 +172,6 @@ AABB Light3D::get_aabb() const {
 PackedStringArray Light3D::get_configuration_warnings() const {
 PackedStringArray Light3D::get_configuration_warnings() const {
 	PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
 	PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
 
 
-	if (has_shadow() && OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
-		warnings.push_back(RTR("Shadows are not supported when using the GL Compatibility backend yet. Support will be added in a future release."));
-	}
-
 	if (!get_scale().is_equal_approx(Vector3(1, 1, 1))) {
 	if (!get_scale().is_equal_approx(Vector3(1, 1, 1))) {
 		warnings.push_back(RTR("A light's scale does not affect the visual size of the light."));
 		warnings.push_back(RTR("A light's scale does not affect the visual size of the light."));
 	}
 	}

+ 6 - 7
servers/rendering/renderer_rd/storage_rd/light_storage.h

@@ -677,8 +677,7 @@ public:
 		return li->shadow_transform[p_index].camera;
 		return li->shadow_transform[p_index].camera;
 	}
 	}
 
 
-	_FORCE_INLINE_ Transform3D
-	light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
+	_FORCE_INLINE_ Transform3D light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
 		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
 		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
 		return li->shadow_transform[p_index].transform;
 		return li->shadow_transform[p_index].transform;
 	}
 	}
@@ -1005,15 +1004,15 @@ public:
 	virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
 	virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
 	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
 	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
 	virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override;
 	virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override;
-	_FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) {
+	_FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_instance) {
 		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
 		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
 		ERR_FAIL_NULL_V(atlas, false);
 		ERR_FAIL_NULL_V(atlas, false);
-		return atlas->shadow_owners.has(p_light_intance);
+		return atlas->shadow_owners.has(p_light_instance);
 	}
 	}
-	_FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_intance) {
+	_FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_instance) {
 		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
 		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
 		ERR_FAIL_NULL_V(atlas, -1);
 		ERR_FAIL_NULL_V(atlas, -1);
-		return atlas->shadow_owners[p_light_intance];
+		return atlas->shadow_owners[p_light_instance];
 	}
 	}
 
 
 	_FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
 	_FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
@@ -1053,7 +1052,7 @@ public:
 	/* DIRECTIONAL SHADOW */
 	/* DIRECTIONAL SHADOW */
 
 
 	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
 	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
-	virtual int get_directional_light_shadow_size(RID p_light_intance) override;
+	virtual int get_directional_light_shadow_size(RID p_light_instance) override;
 	virtual void set_directional_shadow_count(int p_count) override;
 	virtual void set_directional_shadow_count(int p_count) override;
 
 
 	Rect2i get_directional_shadow_rect();
 	Rect2i get_directional_shadow_rect();

Some files were not shown because too many files changed in this diff