Juan Linietsky пре 5 година
родитељ
комит
9d7b7f931b

+ 2 - 2
core/math/camera_matrix.cpp

@@ -512,7 +512,7 @@ CameraMatrix CameraMatrix::operator*(const CameraMatrix &p_matrix) const {
 	return new_matrix;
 }
 
-void CameraMatrix::set_depth_correction() {
+void CameraMatrix::set_depth_correction(bool p_flip_y) {
 
 	real_t *m = &matrix[0][0];
 
@@ -521,7 +521,7 @@ void CameraMatrix::set_depth_correction() {
 	m[2] = 0.0;
 	m[3] = 0.0;
 	m[4] = 0.0;
-	m[5] = -1;
+	m[5] = p_flip_y ? -1 : 1;
 	m[6] = 0.0;
 	m[7] = 0.0;
 	m[8] = 0.0;

+ 1 - 1
core/math/camera_matrix.h

@@ -50,7 +50,7 @@ struct CameraMatrix {
 	void set_identity();
 	void set_zero();
 	void set_light_bias();
-	void set_depth_correction();
+	void set_depth_correction(bool p_flip_y = true);
 	void set_light_atlas_rect(const Rect2 &p_rect);
 	void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
 	void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist);

+ 19 - 2
servers/visual/rasterizer.h

@@ -38,6 +38,7 @@
 #include "core/self_list.h"
 
 class RasterizerScene {
+
 public:
 	/* SHADOW ATLAS API */
 
@@ -218,10 +219,15 @@ public:
 	virtual void light_instance_mark_visible(RID p_light_instance) = 0;
 	virtual bool light_instances_can_render_shadow_cube() const { return true; }
 
+	virtual RID reflection_atlas_create() = 0;
+	virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0;
+
 	virtual RID reflection_probe_instance_create(RID p_probe) = 0;
 	virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0;
+	virtual void reflection_probe_release_atlas_index(RID p_instance) = 0;
 	virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0;
-	virtual void reflection_probe_instance_begin_render(RID p_instance) = 0;
+	virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0;
+	virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0;
 	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
 
 	virtual RID gi_probe_instance_create() = 0;
@@ -229,7 +235,7 @@ public:
 	virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0;
 	virtual void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) = 0;
 
-	virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
+	virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
 	virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0;
 
 	virtual void set_scene_pass(uint64_t p_pass) = 0;
@@ -246,6 +252,9 @@ public:
 };
 
 class RasterizerStorage {
+
+	Color default_clear_color;
+
 public:
 	/* TEXTURE API */
 
@@ -620,6 +629,14 @@ public:
 
 	static RasterizerStorage *base_singleton;
 
+	void set_default_clear_color(const Color &p_color) {
+		default_clear_color = p_color;
+	}
+
+	Color get_default_clear_color() const {
+		return default_clear_color;
+	}
+
 	RasterizerStorage();
 	virtual ~RasterizerStorage() {}
 };

+ 83 - 32
servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp

@@ -614,6 +614,30 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements,
 		uint32_t spot_count = 0;
 		uint32_t decal_count = 0;
 
+		if (!e->instance->reflection_probe_instances.empty()) {
+
+			uint32_t rpi_count = e->instance->reflection_probe_instances.size();
+			const RID *rpi_ptrs = e->instance->reflection_probe_instances.ptr();
+
+			for (uint32_t j = 0; j < rpi_count; j++) {
+				if (render_pass != reflection_probe_instance_get_render_pass(rpi_ptrs[j])) {
+					continue; //not rendered this frame
+				}
+
+				RID base = reflection_probe_instance_get_probe(rpi_ptrs[j]);
+
+				uint32_t mask = storage->reflection_probe_get_cull_mask(base);
+				if (!(mask & id.mask)) {
+					continue; //masked
+				}
+
+				if (reflection_count < 8) {
+					id.omni_light_indices[omni_count] = reflection_probe_instance_get_render_index(rpi_ptrs[j]);
+					reflection_count++;
+				}
+			}
+		}
+
 		if (!e->instance->light_instances.empty()) {
 			uint32_t light_count = e->instance->light_instances.size();
 			const RID *light_ptrs = e->instance->light_instances.ptr();
@@ -832,12 +856,12 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l
 	}
 }
 
-void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas) {
+void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas) {
 
 	//CameraMatrix projection = p_cam_projection;
 	//projection.flip_y(); // Vulkan and modern APIs use Y-Down
 	CameraMatrix correction;
-	correction.set_depth_correction();
+	correction.set_depth_correction(!p_reflection_probe.is_valid());
 	CameraMatrix projection = correction * p_cam_projection;
 
 	//store camera into ubo
@@ -909,7 +933,17 @@ void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_env
 		}
 
 	} else {
-		if (p_render_target.is_valid()) {
+
+		if (p_reflection_probe.is_valid() && !storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
+			scene_state.ubo.use_ambient_light = true;
+			Color clear_color = storage->get_default_clear_color();
+			clear_color = clear_color.to_linear();
+			scene_state.ubo.ambient_light_color_energy[0] = clear_color.r;
+			scene_state.ubo.ambient_light_color_energy[1] = clear_color.g;
+			scene_state.ubo.ambient_light_color_energy[2] = clear_color.b;
+			scene_state.ubo.ambient_light_color_energy[3] = 1.0;
+
+		} else if (p_render_target.is_valid()) {
 			scene_state.ubo.use_ambient_light = true;
 			Color clear_color = storage->render_target_get_clear_request_color(p_render_target);
 			clear_color = clear_color.to_linear();
@@ -1284,11 +1318,11 @@ void RasterizerSceneForwardRD::_draw_sky(RD::DrawListID p_draw_list, RD::Framebu
 
 void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment) {
 
-	for (uint32_t i = 0; i < p_reflection_probe_cull_count; i++) {
+	for (int i = 0; i < p_reflection_probe_cull_count; i++) {
 
 		RID rpi = p_reflection_probe_cull_result[i];
 
-		if (i >= scene_state.max_reflections) {
+		if (i >= (int)scene_state.max_reflections) {
 			reflection_probe_instance_set_render_index(rpi, 0); //invalid, but something needs to be set
 			continue;
 		}
@@ -1304,14 +1338,14 @@ void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_r
 		reflection_ubo.box_extents[0] = extents.x;
 		reflection_ubo.box_extents[1] = extents.y;
 		reflection_ubo.box_extents[2] = extents.z;
-		reflection_ubo.box_extents[3] = 0;
+		reflection_ubo.index = reflection_probe_instance_get_atlas_index(rpi);
 
 		Vector3 origin_offset = storage->reflection_probe_get_origin_offset(base_probe);
 
 		reflection_ubo.box_offset[0] = origin_offset.x;
 		reflection_ubo.box_offset[1] = origin_offset.y;
 		reflection_ubo.box_offset[2] = origin_offset.z;
-		reflection_ubo.box_offset[3] = 0;
+		reflection_ubo.mask = storage->reflection_probe_get_cull_mask(base_probe);
 
 		float intensity = storage->reflection_probe_get_intensity(base_probe);
 		bool interior = storage->reflection_probe_is_interior(base_probe);
@@ -1350,6 +1384,8 @@ void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_r
 		Transform transform = reflection_probe_instance_get_transform(rpi);
 		Transform proj = (p_camera_inverse_transform * transform).inverse();
 		store_transform(proj, reflection_ubo.local_matrix);
+
+		reflection_probe_instance_set_render_pass(rpi, render_pass);
 	}
 
 	if (p_reflection_probe_cull_count) {
@@ -1357,7 +1393,7 @@ void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_r
 	}
 }
 
-void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas) {
+void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows) {
 
 	uint32_t light_count = 0;
 	scene_state.ubo.directional_light_count = 0;
@@ -1406,7 +1442,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig
 				light_data.shadow_color[1] = shadow_col.g;
 				light_data.shadow_color[2] = shadow_col.b;
 
-				light_data.shadow_enabled = storage->light_has_shadow(base);
+				light_data.shadow_enabled = p_using_shadows && storage->light_has_shadow(base);
 
 				if (light_data.shadow_enabled) {
 
@@ -1481,7 +1517,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig
 
 				Color shadow_color = storage->light_get_shadow_color(base);
 
-				bool has_shadow = storage->light_has_shadow(base);
+				bool has_shadow = p_using_shadows && storage->light_has_shadow(base);
 				light_data.shadow_color_enabled[0] = CLAMP(uint32_t(shadow_color.r * 255), 0, 255);
 				light_data.shadow_color_enabled[1] = CLAMP(uint32_t(shadow_color.g * 255), 0, 255);
 				light_data.shadow_color_enabled[2] = CLAMP(uint32_t(shadow_color.b * 255), 0, 255);
@@ -1492,7 +1528,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig
 				light_data.atlas_rect[2] = 0;
 				light_data.atlas_rect[3] = 0;
 
-				if (storage->light_has_shadow(base) && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) {
+				if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) {
 					// fill in the shadow information
 
 					Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas);
@@ -1540,7 +1576,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig
 	}
 }
 
-void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
+void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
 
 	RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)p_buffer_data;
 
@@ -1569,8 +1605,14 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
 		glBindTexture(GL_TEXTURE_2D, reflection_atlas->color);
 	}
 #endif
+
+	bool using_shadows = true;
+
 	if (p_reflection_probe.is_valid()) {
 		scene_state.ubo.reflection_multiplier = 0.0;
+		if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_reflection_probe))) {
+			using_shadows = false;
+		}
 	} else {
 		scene_state.ubo.reflection_multiplier = 1.0;
 	}
@@ -1605,13 +1647,17 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
 		opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass);
 		alpha_framebuffer = opaque_framebuffer;
 
+		if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
+			p_environment = RID(); //no environment on interiors
+		}
+
 	} else {
 		ERR_FAIL(); //bug?
 	}
 
-	_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas);
+	_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows);
 	_setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment);
-	_setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas);
+	_setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas);
 
 #if 0
 	for (int i = 0; i < p_light_cull_count; i++) {
@@ -1983,12 +2029,15 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
 			} break;
 		}
 	} else {
-		if (render_target.is_valid()) {
+
+		if (p_reflection_probe.is_valid() && !storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
+			clear_color = storage->get_default_clear_color();
+		} else if (render_target.is_valid()) {
 			clear_color = storage->render_target_get_clear_request_color(render_target);
 		}
 	}
 
-	_setup_render_base_uniform_set(RID(), RID(), RID(), RID(), radiance_cubemap, p_shadow_atlas, RID());
+	_setup_render_base_uniform_set(RID(), RID(), RID(), RID(), radiance_cubemap, p_shadow_atlas, p_reflection_atlas);
 
 	render_list.sort_by_key(false);
 
@@ -2236,7 +2285,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase **
 	scene_state.ubo.z_far = p_zfar;
 	scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
 
-	_setup_environment(RID(), RID(), p_projection, p_transform, true, Vector2(1, 1), RID());
+	_setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID());
 
 	render_list.clear();
 
@@ -2363,8 +2412,22 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
 	}
 
 	{
+
+		RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID();
 		RD::Uniform u;
 		u.binding = 11;
+		u.type = RD::UNIFORM_TYPE_TEXTURE;
+		if (ref_texture.is_valid()) {
+			u.ids.push_back(ref_texture);
+		} else {
+			u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK));
+		}
+		uniforms.push_back(u);
+	}
+
+	{
+		RD::Uniform u;
+		u.binding = 12;
 		u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
 		u.ids.push_back(scene_state.light_buffer);
 		uniforms.push_back(u);
@@ -2372,7 +2435,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
 
 	{
 		RD::Uniform u;
-		u.binding = 12;
+		u.binding = 13;
 		u.type = RD::UNIFORM_TYPE_TEXTURE;
 		if (p_shadow_atlas.is_valid()) {
 			u.ids.push_back(shadow_atlas_get_texture(p_shadow_atlas));
@@ -2384,7 +2447,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
 
 	{
 		RD::Uniform u;
-		u.binding = 13;
+		u.binding = 14;
 		u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
 		u.ids.push_back(scene_state.directional_light_buffer);
 		uniforms.push_back(u);
@@ -2392,7 +2455,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer
 
 	{
 		RD::Uniform u;
-		u.binding = 14;
+		u.binding = 15;
 		u.type = RD::UNIFORM_TYPE_TEXTURE;
 		if (directional_shadow_get_texture().is_valid()) {
 			u.ids.push_back(directional_shadow_get_texture());
@@ -2425,18 +2488,6 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag
 			defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
 		}
 
-		uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
-
-		if (textures_per_stage <= 16) {
-			//ARM pretty much, and very old Intel GPUs under Linux
-			scene_state.max_reflection_probes_per_instance = 4; //sad
-		} else {
-			//maximum 8
-			scene_state.max_reflection_probes_per_instance = 8;
-		}
-
-		defines += "\n#define MAX_REFLECTION_PROBES " + itos(scene_state.max_reflection_probes_per_instance) + "\n";
-
 		uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
 
 		{ //reflections

+ 7 - 5
servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h

@@ -209,8 +209,10 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 	/* Scene State UBO */
 
 	struct ReflectionData { //should always be 128 bytes
-		float box_extents[4];
-		float box_offset[4];
+		float box_extents[3];
+		float index;
+		float box_offset[3];
+		uint32_t mask;
 		float params[4]; // intensity, 0, interior , boxproject
 		float ambient[4]; // ambient color, energy
 		float local_matrix[16]; // up to here for spot and omni, rest is for directional
@@ -480,8 +482,8 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 		PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
 	};
 
-	void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas);
-	void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas);
+	void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas);
+	void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows);
 	void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment);
 
 	void _fill_instances(RenderList::Element **p_elements, int p_element_count);
@@ -494,7 +496,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
 	void _draw_sky(RD::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, float p_alpha);
 
 protected:
-	virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
+	virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
 	virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip);
 
 public:

+ 209 - 82
servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp

@@ -4,38 +4,17 @@
 
 void RasterizerSceneRD::_clear_reflection_data(ReflectionData &rd) {
 
-	if (rd.radiance.is_valid()) {
-		//if size changes, everything must be cleared
-		RD::get_singleton()->free(rd.radiance);
-		//everything else gets dependency, erase, so just clean it up
-		rd.radiance = RID();
-		rd.layers.clear();
-		rd.radiance_base_cubemap = RID();
-	}
+	rd.layers.clear();
+	rd.radiance_base_cubemap = RID();
 }
 
-void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, bool p_quality) {
+void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer) {
 	//recreate radiance and all data
-	int mipmaps = Image::get_image_required_mipmaps(p_size, p_size, Image::FORMAT_RGBAH) + 1;
-	if (!p_quality) {
-		//use less mipmaps
-		mipmaps = MIN(8, mipmaps);
-	}
 
+	int mipmaps = p_mipmaps;
 	uint32_t w = p_size, h = p_size;
 
-	if (sky_use_cubemap_array) {
-		//array (higher quality, 6 times more memory)
-		RD::TextureFormat tf;
-		tf.array_layers = roughness_layers * 6;
-		tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
-		tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY;
-		tf.mipmaps = mipmaps;
-		tf.width = w;
-		tf.height = h;
-		tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
-
-		rd.radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
+	if (p_use_array) {
 
 		for (int i = 0; i < roughness_layers; i++) {
 			ReflectionData::Layer layer;
@@ -47,7 +26,7 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size,
 				mm.size.width = mmw;
 				mm.size.height = mmh;
 				for (int k = 0; k < 6; k++) {
-					mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.radiance, i * 6 + k, j);
+					mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j);
 					Vector<RID> fbtex;
 					fbtex.push_back(mm.views[k]);
 					mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
@@ -62,17 +41,6 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size,
 
 	} else {
 		//regular cubemap, lower quality (aliasing, less memory)
-		RD::TextureFormat tf;
-		tf.array_layers = 6;
-		tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
-		tf.type = RD::TEXTURE_TYPE_CUBE;
-		tf.mipmaps = roughness_layers;
-		tf.width = w;
-		tf.height = h;
-		tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
-
-		rd.radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
 		ReflectionData::Layer layer;
 		uint32_t mmw = w;
 		uint32_t mmh = h;
@@ -82,7 +50,7 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size,
 			mm.size.width = mmw;
 			mm.size.height = mmh;
 			for (int k = 0; k < 6; k++) {
-				mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.radiance, k, j);
+				mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j);
 				Vector<RID> fbtex;
 				fbtex.push_back(mm.views[k]);
 				mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
@@ -95,11 +63,14 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size,
 		rd.layers.push_back(layer);
 	}
 
-	rd.radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.radiance, 0, 0, RD::TEXTURE_SLICE_CUBEMAP);
+	rd.radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP);
 }
 
 void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality) {
 
+#ifndef _MSC_VER
+#warning TODO, should probably use this algorithm instead. Volunteers? - https://www.ppsloan.org/publications/ggx_filtering.pdf	 / https://github.com/dariomanesku/cmft
+#endif
 	if (sky_use_cubemap_array) {
 
 		if (p_quality) {
@@ -148,9 +119,9 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID
 	}
 }
 
-void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_quality, int p_cube_side) {
+void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side) {
 
-	if (sky_use_cubemap_array) {
+	if (p_use_arrays) {
 
 		if (p_quality) {
 			//render directly to the layers
@@ -220,6 +191,10 @@ void RasterizerSceneRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) {
 	}
 	sky->radiance_size = p_radiance_size;
 	_sky_invalidate(sky);
+	if (sky->radiance.is_valid()) {
+		RD::get_singleton()->free(sky->radiance);
+		sky->radiance = RID();
+	}
 	_clear_reflection_data(sky->reflection);
 }
 
@@ -242,6 +217,10 @@ void RasterizerSceneRD::sky_set_texture(RID p_sky, RID p_panorama) {
 
 	if (sky->panorama.is_valid()) {
 		sky->panorama = RID();
+		if (sky->radiance.is_valid()) {
+			RD::get_singleton()->free(sky->radiance);
+			sky->radiance = RID();
+		}
 		_clear_reflection_data(sky->reflection);
 	}
 
@@ -260,8 +239,45 @@ void RasterizerSceneRD::_update_dirty_skys() {
 
 		//update sky configuration if texture is missing
 
-		if (sky->reflection.radiance.is_null()) {
-			_update_reflection_data(sky->reflection, sky->radiance_size, sky->mode == VS::SKY_MODE_QUALITY);
+		if (sky->radiance.is_null()) {
+			int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1;
+			if (sky->mode != VS::SKY_MODE_QUALITY) {
+				//use less mipmaps
+				mipmaps = MIN(8, mipmaps);
+			}
+
+			uint32_t w = sky->radiance_size, h = sky->radiance_size;
+
+			if (sky_use_cubemap_array) {
+				//array (higher quality, 6 times more memory)
+				RD::TextureFormat tf;
+				tf.array_layers = roughness_layers * 6;
+				tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+				tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY;
+				tf.mipmaps = mipmaps;
+				tf.width = w;
+				tf.height = h;
+				tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+				sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+				_update_reflection_data(sky->reflection, sky->radiance_size, mipmaps, true, sky->radiance, 0);
+
+			} else {
+				//regular cubemap, lower quality (aliasing, less memory)
+				RD::TextureFormat tf;
+				tf.array_layers = 6;
+				tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+				tf.type = RD::TEXTURE_TYPE_CUBE;
+				tf.mipmaps = roughness_layers;
+				tf.width = w;
+				tf.height = h;
+				tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+				sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+				_update_reflection_data(sky->reflection, sky->radiance_size, mipmaps, false, sky->radiance, 0);
+			}
 		}
 
 		RID panorama_texture = storage->texture_get_rd_texture(sky->panorama);
@@ -295,7 +311,7 @@ RID RasterizerSceneRD::sky_get_radiance_texture_rd(RID p_sky) const {
 	Sky *sky = sky_owner.getornull(p_sky);
 	ERR_FAIL_COND_V(!sky, RID());
 
-	return sky->reflection.radiance;
+	return sky->radiance;
 }
 
 RID RasterizerSceneRD::environment_create() {
@@ -469,6 +485,42 @@ bool RasterizerSceneRD::is_environment(RID p_env) const {
 
 ////////////////////////////////////////////////////////////
 
+RID RasterizerSceneRD::reflection_atlas_create() {
+
+	ReflectionAtlas ra;
+	ra.count = GLOBAL_GET("rendering/quality/reflection_atlas/reflection_count");
+	ra.size = GLOBAL_GET("rendering/quality/reflection_atlas/reflection_size");
+
+	return reflection_atlas_owner.make_rid(ra);
+}
+
+void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
+
+	ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas);
+	ERR_FAIL_COND(!ra);
+
+	if (ra->size == p_reflection_size && ra->count == p_reflection_count) {
+		return; //no changes
+	}
+
+	if (ra->reflection.is_valid()) {
+		//clear and invalidate everything
+		RD::get_singleton()->free(ra->reflection);
+		ra->reflection = RID();
+
+		for (int i = 0; i < ra->reflections.size(); i++) {
+			if (ra->reflections[i].owner.is_null()) {
+				continue;
+			}
+			reflection_probe_release_atlas_index(ra->reflections[i].owner);
+			//rp->atlasindex clear
+		}
+
+		ra->reflections.clear();
+	}
+}
+
+////////////////////////
 RID RasterizerSceneRD::reflection_probe_instance_create(RID p_probe) {
 	ReflectionProbeInstance rpi;
 	rpi.probe = p_probe;
@@ -483,6 +535,22 @@ void RasterizerSceneRD::reflection_probe_instance_set_transform(RID p_instance,
 	rpi->dirty = true;
 }
 
+void RasterizerSceneRD::reflection_probe_release_atlas_index(RID p_instance) {
+
+	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+	ERR_FAIL_COND(!rpi);
+
+	if (rpi->atlas.is_null()) {
+		return; //nothing to release
+	}
+	ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+	ERR_FAIL_COND(!atlas);
+	ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size());
+	atlas->reflections.write[rpi->atlas_index].owner = RID();
+	rpi->atlas_index = -1;
+	rpi->atlas = RID();
+}
+
 bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) {
 
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
@@ -496,52 +564,93 @@ bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) {
 		return true;
 	}
 
-	if (rpi->current_resolution != storage->reflection_probe_get_resolution(rpi->probe)) {
-		return true;
-	}
-
 	if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS) {
 		return true;
 	}
 
-	return false;
+	return rpi->atlas_index == -1;
 }
 
-void RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance) {
+bool RasterizerSceneRD::reflection_probe_instance_has_reflection(RID p_instance) {
 
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
-	ERR_FAIL_COND(!rpi);
-	rpi->rendering = true;
-	rpi->processing_side = 0;
+	ERR_FAIL_COND_V(!rpi, false);
 
-	int probe_resolution = storage->reflection_probe_get_resolution(rpi->probe);
-	if (rpi->current_resolution != probe_resolution) {
-		//need to re-create everything
-		_clear_reflection_data(rpi->reflection);
-		_update_reflection_data(rpi->reflection, probe_resolution, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE);
+	return rpi->atlas.is_valid();
+}
 
-		rpi->current_resolution = probe_resolution;
+bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
 
-		if (rpi->depth_buffer.is_valid()) {
-			RD::get_singleton()->free(rpi->depth_buffer);
-		}
+	ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_reflection_atlas);
+
+	ERR_FAIL_COND_V(!atlas, false);
+
+	if (atlas->reflection.is_null()) {
 		{
+			//reflection atlas was unused, create:
 			RD::TextureFormat tf;
-			tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
-			tf.width = probe_resolution;
-			tf.height = probe_resolution;
-			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+			tf.array_layers = 6 * atlas->count;
+			tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+			tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY;
+			tf.mipmaps = roughness_layers;
+			tf.width = atlas->size;
+			tf.height = atlas->size;
+			tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+			atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView());
+		}
+		{
 
-			rpi->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::TextureFormat tf;
+			tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
+			tf.width = atlas->size;
+			tf.height = atlas->size;
+			tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+			atlas->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
 		}
+		atlas->reflections.resize(atlas->count);
+		for (int i = 0; i < atlas->count; i++) {
+			_update_reflection_data(atlas->reflections.write[i].data, atlas->size, roughness_layers, false, atlas->reflection, i * 6);
+			for (int j = 0; j < 6; j++) {
+				Vector<RID> fb;
+				fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]);
+				fb.push_back(atlas->depth_buffer);
+				atlas->reflections.write[i].fbs[j] = RD::get_singleton()->framebuffer_create(fb);
+			}
+		}
+	}
 
-		for (int i = 0; i < 6; i++) {
-			Vector<RID> fb;
-			fb.push_back(rpi->reflection.layers[0].mipmaps[0].views[i]);
-			fb.push_back(rpi->depth_buffer);
-			rpi->render_fb[i] = RD::get_singleton()->framebuffer_create(fb);
+	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+	ERR_FAIL_COND_V(!rpi, false);
+
+	if (rpi->atlas_index == -1) {
+		for (int i = 0; i < atlas->reflections.size(); i++) {
+			if (atlas->reflections[i].owner.is_null()) {
+				rpi->atlas_index = i;
+				break;
+			}
+		}
+		//find the one used last
+		if (rpi->atlas_index == -1) {
+			//everything is in use, find the one least used via LRU
+			uint64_t pass_min = 0;
+
+			for (int i = 0; i < atlas->reflections.size(); i++) {
+				ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.getornull(atlas->reflections[i].owner);
+				if (rpi2->last_pass < pass_min) {
+					pass_min = rpi2->last_pass;
+					rpi->atlas_index = i;
+				}
+			}
 		}
 	}
+
+	rpi->atlas = p_reflection_atlas;
+	rpi->rendering = true;
+	rpi->dirty = false;
+	rpi->processing_side = 0;
+
+	return true;
 }
 
 bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instance) {
@@ -549,15 +658,22 @@ bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instanc
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
 	ERR_FAIL_COND_V(!rpi, false);
 	ERR_FAIL_COND_V(!rpi->rendering, false);
+	ERR_FAIL_COND_V(rpi->atlas.is_null(), false);
+
+	ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+	if (!atlas || rpi->atlas_index == -1) {
+		//does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering)
+		rpi->rendering = false;
+		return false;
+	}
 
-	_create_reflection_from_base_mipmap(rpi->reflection, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side);
+	_create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side);
 
 	rpi->processing_side++;
 
 	if (rpi->processing_side == 6) {
 		rpi->rendering = false;
 		rpi->processing_side = 0;
-
 		return true;
 	} else {
 		return false;
@@ -568,7 +684,9 @@ uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_insta
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
 	ERR_FAIL_COND_V(!rpi, 0);
 
-	return rpi->current_resolution;
+	ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+	ERR_FAIL_COND_V(!atlas, 0);
+	return atlas->size;
 }
 
 RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) {
@@ -576,7 +694,9 @@ RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance,
 	ERR_FAIL_COND_V(!rpi, RID());
 	ERR_FAIL_INDEX_V(p_index, 6, RID());
 
-	return rpi->render_fb[p_index];
+	ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+	ERR_FAIL_COND_V(!atlas, RID());
+	return atlas->reflections[rpi->atlas_index].fbs[p_index];
 }
 
 ///////////////////////////////////////////////////////////
@@ -591,8 +711,8 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) {
 	ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
 	ERR_FAIL_COND(!shadow_atlas);
 	ERR_FAIL_COND(p_size < 0);
-
 	p_size = next_power_of_2(p_size);
+	p_size = MAX(p_size, 1 << roughness_layers);
 
 	if (p_size == shadow_atlas->size)
 		return;
@@ -1097,12 +1217,12 @@ bool RasterizerSceneRD::is_using_radiance_cubemap_array() const {
 	return sky_use_cubemap_array;
 }
 
-void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
+void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
 
 	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
 	ERR_FAIL_COND(!rb && p_render_buffers.is_valid());
 
-	_render_scene(rb->data, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_probe, p_reflection_probe_pass);
+	_render_scene(rb ? rb->data : (RenderBufferData *)NULL, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
 }
 
 void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
@@ -1289,14 +1409,21 @@ bool RasterizerSceneRD::free(RID p_rid) {
 	} else if (environment_owner.owns(p_rid)) {
 		//not much to delete, just free it
 		environment_owner.free(p_rid);
+	} else if (reflection_atlas_owner.owns(p_rid)) {
+		reflection_atlas_set_size(p_rid, 0, 0);
+		reflection_atlas_owner.free(p_rid);
 	} else if (reflection_probe_instance_owner.owns(p_rid)) {
 		//not much to delete, just free it
 		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid);
-		_clear_reflection_data(rpi->reflection);
+		reflection_probe_release_atlas_index(p_rid);
 		reflection_probe_instance_owner.free(p_rid);
 	} else if (sky_owner.owns(p_rid)) {
 		_update_dirty_skys();
 		Sky *sky = sky_owner.getornull(p_rid);
+		if (sky->radiance.is_valid()) {
+			RD::get_singleton()->free(sky->radiance);
+			sky->radiance = RID();
+		}
 		_clear_reflection_data(sky->reflection);
 		sky_owner.free(p_rid);
 	} else if (light_instance_owner.owns(p_rid)) {
@@ -1340,7 +1467,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
 	sky_ggx_samples_quality = GLOBAL_GET("rendering/quality/reflections/ggx_samples");
 	sky_ggx_samples_realtime = GLOBAL_GET("rendering/quality/reflections/ggx_samples_realtime");
 	sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections");
-	sky_use_cubemap_array = false;
+	//	sky_use_cubemap_array = false;
 }
 
 RasterizerSceneRD::~RasterizerSceneRD() {

+ 57 - 15
servers/visual/rasterizer_rd/rasterizer_scene_rd.h

@@ -15,7 +15,7 @@ protected:
 	};
 	virtual RenderBufferData *_create_render_buffer_data() = 0;
 
-	virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
+	virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
 	virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip) = 0;
 
 private:
@@ -24,7 +24,6 @@ private:
 	RasterizerStorageRD *storage;
 
 	struct ReflectionData {
-		RID radiance;
 
 		struct Layer {
 			struct Mipmap {
@@ -40,13 +39,14 @@ private:
 	};
 
 	void _clear_reflection_data(ReflectionData &rd);
-	void _update_reflection_data(ReflectionData &rd, int p_size, bool p_quality);
+	void _update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer);
 	void _create_reflection_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality);
-	void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_quality, int p_cube_side);
+	void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side);
 	void _update_reflection_mipmaps(ReflectionData &rd, bool p_quality);
 
 	/* SKY */
 	struct Sky {
+		RID radiance;
 		int radiance_size = 256;
 		VS::SkyMode mode = VS::SKY_MODE_QUALITY;
 		RID panorama;
@@ -66,22 +66,41 @@ private:
 
 	mutable RID_Owner<Sky> sky_owner;
 
-	/* REFLECTION PROBE INSTANCE */
+	/* REFLECTION ATLAS */
 
-	struct ReflectionProbeInstance {
+	struct ReflectionAtlas {
 
-		RID probe;
+		int count = 0;
+		int size = 0;
 
-		ReflectionData reflection;
+		RID reflection;
 		RID depth_buffer;
-		RID render_fb[6];
 
-		int current_resolution = 0;
+		struct Reflection {
+			RID owner;
+			ReflectionData data;
+			RID fbs[6];
+		};
+
+		Vector<Reflection> reflections;
+	};
+
+	RID_Owner<ReflectionAtlas> reflection_atlas_owner;
+
+	/* REFLECTION PROBE INSTANCE */
+
+	struct ReflectionProbeInstance {
+
+		RID probe;
+		int atlas_index = -1;
+		RID atlas;
 
 		bool dirty = true;
 		bool rendering = false;
 		int processing_side = 0;
 
+		uint32_t render_step = 0;
+		uint64_t last_pass = 0;
 		uint32_t render_index = 0;
 
 		Transform transform;
@@ -453,10 +472,20 @@ public:
 		return li->light_type;
 	}
 
+	virtual RID reflection_atlas_create();
+	virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count);
+	_FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) {
+		ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_ref_atlas);
+		ERR_FAIL_COND_V(!atlas, RID());
+		return atlas->reflection;
+	}
+
 	virtual RID reflection_probe_instance_create(RID p_probe);
 	virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform);
+	virtual void reflection_probe_release_atlas_index(RID p_instance);
 	virtual bool reflection_probe_instance_needs_redraw(RID p_instance);
-	virtual void reflection_probe_instance_begin_render(RID p_instance);
+	virtual bool reflection_probe_instance_has_reflection(RID p_instance);
+	virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas);
 	virtual bool reflection_probe_instance_postprocess_step(RID p_instance);
 
 	uint32_t reflection_probe_instance_get_resolution(RID p_instance);
@@ -482,6 +511,19 @@ public:
 		return rpi->render_index;
 	}
 
+	_FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
+		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+		ERR_FAIL_COND(!rpi);
+		rpi->last_pass = p_render_pass;
+	}
+
+	_FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) {
+		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+		ERR_FAIL_COND_V(!rpi, 0);
+
+		return rpi->last_pass;
+	}
+
 	_FORCE_INLINE_ Transform reflection_probe_instance_get_transform(RID p_instance) {
 		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
 		ERR_FAIL_COND_V(!rpi, Transform());
@@ -489,11 +531,11 @@ public:
 		return rpi->transform;
 	}
 
-	_FORCE_INLINE_ RID reflection_probe_instance_get_texture(RID p_instance) {
+	_FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) {
 		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
-		ERR_FAIL_COND_V(!rpi, RID());
+		ERR_FAIL_COND_V(!rpi, -1);
 
-		return rpi->reflection.radiance;
+		return rpi->atlas_index;
 	}
 
 	RID gi_probe_instance_create() { return RID(); }
@@ -504,7 +546,7 @@ public:
 	RID render_buffers_create();
 	void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa);
 
-	void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
+	void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
 
 	void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
 

+ 91 - 108
servers/visual/rasterizer_rd/shaders/scene_forward.glsl

@@ -710,6 +710,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
 
 
 
+
 void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo,float roughness, float metallic, float specular,float p_blob_intensity,
 #ifdef LIGHT_TRANSMISSION_USED
 	vec3 transmission,
@@ -781,6 +782,86 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
 		diffuse_light, specular_light);
 }
 
+void reflection_process(uint ref_index, vec3 vertex, vec3 normal,float roughness,vec3 ambient_light,vec3 specular_light,inout vec4 ambient_accum, inout vec4 reflection_accum) {
+
+	vec3 box_extents = reflections.data[ref_index].box_extents;
+	vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz;
+
+	if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box
+		return;
+	}
+
+	vec3 ref_vec = normalize(reflect(vertex, normal));
+
+	vec3 inner_pos = abs(local_pos / box_extents);
+	float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
+	//make blend more rounded
+	blend = mix(length(inner_pos), blend, blend);
+	blend *= blend;
+	blend = max(0.0, 1.0 - blend);
+
+	if (reflections.data[ref_index].params.x > 0.0) { // compute reflection
+
+		vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz;
+
+		if (reflections.data[ref_index].params.w > 0.5) { //box project
+
+			vec3 nrdir = normalize(local_ref_vec);
+			vec3 rbmax = (box_extents - local_pos) / nrdir;
+			vec3 rbmin = (-box_extents - local_pos) / nrdir;
+
+			vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0)));
+
+			float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
+			vec3 posonbox = local_pos + nrdir * fa;
+			local_ref_vec = posonbox - reflections.data[ref_index].box_offset;
+		}
+
+		vec4 reflection;
+
+		reflection.rgb = textureLod(samplerCubeArray(reflection_atlas,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec,reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb;
+
+		if (reflections.data[ref_index].params.z < 0.5) {
+			reflection.rgb = mix(specular_light, reflection.rgb, blend);
+		}
+
+		reflection.rgb *= reflections.data[ref_index].params.x;
+		reflection.a = blend;
+		reflection.rgb *= reflection.a;
+
+		reflection_accum += reflection;
+	}
+
+#ifndef USE_LIGHTMAP
+	if (reflections.data[ref_index].ambient.a > 0.0) { //compute ambient using skybox
+
+		vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz;
+
+		vec4 ambient_out;
+
+		ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec,reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb;
+
+		ambient_out.a = blend;
+		ambient_out.rgb = mix(reflections.data[ref_index].ambient.rgb, ambient_out.rgb, reflections.data[ref_index].ambient.a);
+		if (reflections.data[ref_index].params.z < 0.5) {
+			ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
+		}
+
+		ambient_out.rgb *= ambient_out.a;
+		ambient_accum += ambient_out;
+	} else {
+
+		vec4 ambient_out;
+		ambient_out.a = blend;
+		ambient_out.rgb = reflections.data[ref_index].ambient.rgb;
+		if (reflections.data[ref_index].params.z < 0.5) {
+			ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
+		}
+		ambient_out.rgb *= ambient_out.a;
+		ambient_accum += ambient_out;
+	}
+#endif //USE_LIGHTMAP
+}
 void main() {
 
 #ifdef MODE_DUAL_PARABOLOID
@@ -976,126 +1057,28 @@ FRAGMENT_SHADER_CODE
 
 	//lightmap capture
 
-#if 0
+
 	{ // process reflections
 
 
 		vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
 		vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
 
-		for (uint i = 0; i < MAX_REFLECTION_PROBES; i++) {
-			if (i >= draw_data.reflection_probe_count) {
-				break;
-			}
+		uint reflection_probe_count = instances.data[instance_index].flags & INSTANCE_FLAGS_FORWARD_MASK;
 
-			uint ref_index;
-			if (i<4) {
-				if (i<2) {
-					ref_index=draw_data.reflection_probe_indices[0];
-				} else {
-					ref_index=draw_data.reflection_probe_indices[1];
-				}
-			} else {
-				if (i<6) {
-					ref_index=draw_data.reflection_probe_indices[2];
-				} else {
-					ref_index=draw_data.reflection_probe_indices[3];
-				}
-			}
-			ref_index>>=(i&1)*16;
-			ref_index&=0xFFFF;
-
-			vec3 box_extents = reflections.data[ref_index].box_extents.xyz;
-			vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz;
-
-			if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box
-				continue;
-			}
-
-			vec3 ref_vec = normalize(reflect(vertex, normal));
-
-			vec3 inner_pos = abs(local_pos / box_extents);
-			float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
-			//make blend more rounded
-			blend = mix(length(inner_pos), blend, blend);
-			blend *= blend;
-			blend = max(0.0, 1.0 - blend);
-
-			if (reflections.data[ref_index].params.x > 0.0) { // compute reflection
-
-				vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz;
-
-				if (reflections.data[ref_index].params.w > 0.5) { //box project
-
-					vec3 nrdir = normalize(local_ref_vec);
-					vec3 rbmax = (box_extents - local_pos) / nrdir;
-					vec3 rbmin = (-box_extents - local_pos) / nrdir;
+		for (uint i = 0; i < reflection_probe_count; i++) {
 
-					vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0)));
 
-					float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
-					vec3 posonbox = local_pos + nrdir * fa;
-					local_ref_vec = posonbox - reflections.data[ref_index].box_offset.xyz;
-				}
-
-				vec4 reflection;
-
-#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-
-				float lod,layer_blend;
-				layer_blend = modf(roughness * MAX_ROUGHNESS_LOD, lod);
-				reflection.rgb = texture(samplerCubeArray(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, lod)).rgb;
-				reflection.rgb = mix(reflection.rgb,texture(samplerCubeArray(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, lod+1)).rgb,layer_blend);
+			uint ref_index = instances.data[instance_index].reflection_probe_indices[i>>1];
 
-#else
-				reflection.rgb = textureLod(samplerCube(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), local_ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
-
-#endif
-
-				if (reflections.data[ref_index].params.z < 0.5) {
-					reflection.rgb = mix(specular_light, reflection.rgb, blend);
-				}
-
-				reflection.rgb *= reflections.data[ref_index].params.x;
-				reflection.a = blend;
-				reflection.rgb *= reflection.a;
-
-				reflection_accum += reflection;
+			if (bool(i&1)) {
+				ref_index>>=16;
+			} else {
+				ref_index&=0xFFFF;
 			}
 
-#ifndef USE_LIGHTMAP
-			if (reflections.data[ref_index].ambient.a > 0.0) { //compute ambient using skybox
-
-				vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz;
-
-				vec4 ambient_out;
 
-#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-				ambient_out.rgb = texture(samplerCubeArray(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, MAX_ROUGHNESS_LOD)).rgb;
-#else
-				ambient_out.rgb = textureLod(samplerCube(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), local_amb_vec, MAX_ROUGHNESS_LOD).rgb;
-#endif //USE_RADIANCE_CUBEMAP_ARRAY
-
-				ambient_out.a = blend;
-				ambient_out.rgb = mix(reflections.data[ref_index].ambient.rgb, ambient_out.rgb, reflections.data[ref_index].ambient.a);
-				if (reflections.data[ref_index].params.z < 0.5) {
-					ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
-				}
-
-				ambient_out.rgb *= ambient_out.a;
-				ambient_accum += ambient_out;
-			} else {
-
-				vec4 ambient_out;
-				ambient_out.a = blend;
-				ambient_out.rgb = reflections.data[ref_index].ambient.rgb;
-				if (reflections.data[ref_index].params.z < 0.5) {
-					ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
-				}
-				ambient_out.rgb *= ambient_out.a;
-				ambient_accum += ambient_out;
-			}
-#endif //USE_LIGHTMAP
+			reflection_process(ref_index,vertex,normal,roughness,ambient_light,specular_light,ambient_accum,reflection_accum);
 
 		}
 
@@ -1111,7 +1094,7 @@ FRAGMENT_SHADER_CODE
 
 
 	}
-#endif //0
+
 	{
 
 #if defined(DIFFUSE_TOON)

+ 9 - 6
servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl

@@ -145,8 +145,10 @@ layout(set=0,binding=9,std430)  buffer Instances {
 
 struct ReflectionData {
 
-	vec4 box_extents;
-	vec4 box_offset;
+	vec3 box_extents;
+	float index;
+	vec3 box_offset;
+	uint mask;
 	vec4 params; // intensity, 0, interior , boxproject
 	vec4 ambient; // ambient color, energy
 	mat4 local_matrix; // up to here for spot and omni, rest is for directional
@@ -157,6 +159,7 @@ layout(set=0,binding=10,std140) uniform ReflectionProbeData {
 	ReflectionData data[MAX_REFLECTION_DATA_STRUCTS];
 } reflections;
 
+layout(set=0,binding=11) uniform textureCubeArray reflection_atlas;
 
 struct LightData { //this structure needs to be 128 bits
 
@@ -172,11 +175,11 @@ struct LightData { //this structure needs to be 128 bits
 	mat4 shadow_matrix;
 };
 
-layout(set=0,binding=11,std140) uniform Lights {
+layout(set=0,binding=12,std140) uniform Lights {
 	LightData data[MAX_LIGHT_DATA_STRUCTS];
 } lights;
 
-layout(set=0,binding=12) uniform texture2D shadow_atlas;
+layout(set=0,binding=13) uniform texture2D shadow_atlas;
 
 struct DirectionalLightData {
 
@@ -198,11 +201,11 @@ struct DirectionalLightData {
 
 };
 
-layout(set=0,binding=13,std140) uniform DirectionalLights {
+layout(set=0,binding=14,std140) uniform DirectionalLights {
 	DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
 } directional_lights;
 
-layout(set=0,binding=14) uniform texture2D directional_shadow_atlas;
+layout(set=0,binding=15) uniform texture2D directional_shadow_atlas;
 
 /*
 layout(set=0,binding=15,std430)  buffer Skeletons {

+ 37 - 23
servers/visual/visual_server_scene.cpp

@@ -268,7 +268,7 @@ RID VisualServerScene::scenario_create() {
 	VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4);
 	VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4);
 	VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8);
-
+	scenario->reflection_atlas = VSG::scene_render->reflection_atlas_create();
 	return scenario_rid;
 }
 
@@ -293,6 +293,13 @@ void VisualServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_
 	scenario->fallback_environment = p_environment;
 }
 
+void VisualServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) {
+
+	Scenario *scenario = scenario_owner.getornull(p_scenario);
+	ERR_FAIL_COND(!scenario);
+	VSG::scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count);
+}
+
 /* INSTANCING API */
 
 void VisualServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) {
@@ -510,6 +517,8 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) {
 				}
 			} break;
 			case VS::INSTANCE_REFLECTION_PROBE: {
+				InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
+				VSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance);
 
 			} break;
 			case VS::INSTANCE_GI_PROBE: {
@@ -1808,7 +1817,7 @@ void VisualServerScene::render_camera(RID p_render_buffers, Ref<ARVRInterface> &
 	_render_scene(p_render_buffers, cam_transform, camera_matrix, false, camera->env, p_scenario, p_shadow_atlas, RID(), -1);
 };
 
-void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe) {
+void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows) {
 	// Note, in stereo rendering:
 	// - p_cam_transform will be a transform in the middle of our two eyes
 	// - p_cam_projection is a wider frustrum that encompasses both eyes
@@ -1894,8 +1903,10 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
 							reflection_probe->reflection_dirty = false;
 						}
 
-						reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance;
-						reflection_probe_cull_count++;
+						if (VSG::scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) {
+							reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance;
+							reflection_probe_cull_count++;
+						}
 					}
 				}
 			}
@@ -2015,7 +2026,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
 			//check shadow..
 
 			if (light) {
-				if (p_shadow_atlas.is_valid() && VSG::storage->light_has_shadow(E->get()->base)) {
+				if (p_using_shadows && p_shadow_atlas.is_valid() && VSG::storage->light_has_shadow(E->get()->base)) {
 					lights_with_shadow[directional_shadow_count++] = E->get();
 				}
 				//add to list
@@ -2031,7 +2042,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
 		}
 	}
 
-	{ //setup shadow maps
+	if (p_using_shadows) { //setup shadow maps
 
 		//SortArray<Instance*,_InstanceLightsort> sorter;
 		//sorter.sort(light_cull_result,light_cull_count);
@@ -2148,7 +2159,7 @@ void VisualServerScene::_render_scene(RID p_render_buffers, const Transform p_ca
 
 	/* PROCESS GEOMETRY AND DRAW SCENE */
 
-	VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, p_reflection_probe, p_reflection_probe_pass);
+	VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
 }
 
 void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) {
@@ -2162,7 +2173,7 @@ void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario,
 		environment = scenario->environment;
 	else
 		environment = scenario->fallback_environment;
-	VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, RID(), 0);
+	VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0);
 #endif
 }
 
@@ -2176,18 +2187,28 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int
 
 	if (p_step == 0) {
 
-		VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance);
+		if (!VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) {
+			return true; //all full
+		}
 	}
 
 	if (p_step >= 0 && p_step < 6) {
 
 		static const Vector3 view_normals[6] = {
-			Vector3(-1, 0, 0),
 			Vector3(+1, 0, 0),
-			Vector3(0, -1, 0),
+			Vector3(-1, 0, 0),
 			Vector3(0, +1, 0),
+			Vector3(0, -1, 0),
+			Vector3(0, 0, +1),
+			Vector3(0, 0, -1)
+		};
+		static const Vector3 view_up[6] = {
+			Vector3(0, -1, 0),
+			Vector3(0, -1, 0),
+			Vector3(0, 0, +1),
 			Vector3(0, 0, -1),
-			Vector3(0, 0, +1)
+			Vector3(0, -1, 0),
+			Vector3(0, -1, 0)
 		};
 
 		Vector3 extents = VSG::storage->reflection_probe_get_extents(p_instance->base);
@@ -2203,15 +2224,6 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int
 		CameraMatrix cm;
 		cm.set_perspective(90, 1, 0.01, max_distance);
 
-		static const Vector3 view_up[6] = {
-			Vector3(0, -1, 0),
-			Vector3(0, -1, 0),
-			Vector3(0, 0, -1),
-			Vector3(0, 0, +1),
-			Vector3(0, -1, 0),
-			Vector3(0, -1, 0)
-		};
-
 		Transform local_view;
 		local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]);
 
@@ -2219,12 +2231,13 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int
 
 		RID shadow_atlas;
 
-		if (VSG::storage->reflection_probe_renders_shadows(p_instance->base)) {
+		bool use_shadows = VSG::storage->reflection_probe_renders_shadows(p_instance->base);
+		if (use_shadows) {
 
 			shadow_atlas = scenario->reflection_probe_shadow_atlas;
 		}
 
-		_prepare_scene(xform, cm, false, RID(), VSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance);
+		_prepare_scene(xform, cm, false, RID(), VSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows);
 		_render_scene(RID(), xform, cm, false, RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step);
 
 	} else {
@@ -3465,6 +3478,7 @@ bool VisualServerScene::free(RID p_rid) {
 			instance_set_scenario(scenario->instances.first()->self()->self, RID());
 		}
 		VSG::scene_render->free(scenario->reflection_probe_shadow_atlas);
+		VSG::scene_render->free(scenario->reflection_atlas);
 		scenario_owner.free(p_rid);
 		memdelete(scenario);
 

+ 3 - 1
servers/visual/visual_server_scene.h

@@ -115,6 +115,7 @@ public:
 		RID environment;
 		RID fallback_environment;
 		RID reflection_probe_shadow_atlas;
+		RID reflection_atlas;
 
 		SelfList<Instance>::List instances;
 
@@ -131,6 +132,7 @@ public:
 	virtual void scenario_set_debug(RID p_scenario, VS::ScenarioDebugMode p_debug_mode);
 	virtual void scenario_set_environment(RID p_scenario, RID p_environment);
 	virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment);
+	virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count);
 
 	/* INSTANCING API */
 
@@ -475,7 +477,7 @@ public:
 
 	_FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario);
 
-	void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe);
+	void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true);
 	void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
 	void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas);
 

+ 3 - 3
servers/visual/visual_server_viewport.cpp

@@ -83,7 +83,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
 	bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front
 	int scenario_canvas_max_layer = 0;
 
-	Color bgcolor = clear_color;
+	Color bgcolor = VSG::storage->get_default_clear_color();
 
 	if (!p_viewport->hide_canvas && !p_viewport->disable_environment && VSG::scene->scenario_owner.owns(p_viewport->scenario)) {
 
@@ -295,7 +295,7 @@ void VisualServerViewport::draw_viewports() {
 #endif
 
 	if (Engine::get_singleton()->is_editor_hint()) {
-		clear_color = GLOBAL_GET("rendering/environment/default_clear_color");
+		set_default_clear_color(GLOBAL_GET("rendering/environment/default_clear_color"));
 	}
 
 	//sort viewports
@@ -719,7 +719,7 @@ bool VisualServerViewport::free(RID p_rid) {
 }
 
 void VisualServerViewport::set_default_clear_color(const Color &p_color) {
-	clear_color = p_color;
+	VSG::storage->set_default_clear_color(p_color);
 }
 
 VisualServerViewport::VisualServerViewport() {

+ 0 - 1
servers/visual/visual_server_viewport.h

@@ -148,7 +148,6 @@ public:
 	Vector<Viewport *> active_viewports;
 
 private:
-	Color clear_color;
 	void _draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye);
 	void _draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye = ARVRInterface::EYE_MONO);
 

+ 3 - 0
servers/visual_server.cpp

@@ -2302,6 +2302,9 @@ VisualServer::VisualServer() {
 	GLOBAL_DEF("rendering/quality/reflections/ggx_samples.mobile", 128);
 	GLOBAL_DEF("rendering/quality/reflections/ggx_samples_realtime", 64);
 	GLOBAL_DEF("rendering/quality/reflections/ggx_samples_realtime.mobile", 16);
+	GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size", 256);
+	GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size.mobile", 128);
+	GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_count", 64);
 
 	GLOBAL_DEF("rendering/quality/shading/force_vertex_shading", false);
 	GLOBAL_DEF("rendering/quality/shading/force_vertex_shading.mobile", true);