瀏覽代碼

Reflection probe support in GLES2 back-end.

Juan Linietsky 7 年之前
父節點
當前提交
f2ed26d71e

+ 1 - 0
drivers/dummy/rasterizer_dummy.h

@@ -517,6 +517,7 @@ public:
 	void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {}
 	void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {}
 	void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {}
+	void reflection_probe_set_resolution(RID p_probe, int p_resolution) {}
 
 	AABB reflection_probe_get_aabb(RID p_probe) const { return AABB(); }
 	VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const { return VisualServer::REFLECTION_PROBE_UPDATE_ONCE; }

+ 319 - 22
drivers/gles2/rasterizer_scene_gles2.cpp

@@ -437,29 +437,182 @@ void RasterizerSceneGLES2::reflection_atlas_set_subdivision(RID p_ref_atlas, int
 ////////////////////////////////////////////////////
 
 RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) {
-	return RID();
+
+	RasterizerStorageGLES2::ReflectionProbe *probe = storage->reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!probe, RID());
+
+	ReflectionProbeInstance *rpi = memnew(ReflectionProbeInstance);
+
+	rpi->probe_ptr = probe;
+	rpi->self = reflection_probe_instance_owner.make_rid(rpi);
+	rpi->probe = p_probe;
+	rpi->reflection_atlas_index = -1;
+	rpi->render_step = -1;
+	rpi->last_pass = 0;
+	rpi->current_resolution = 0;
+	rpi->dirty = true;
+
+	rpi->last_pass = 0;
+	rpi->index = 0;
+
+	for (int i = 0; i < 6; i++) {
+		glGenFramebuffers(1, &rpi->fbo[i]);
+	}
+
+	glGenFramebuffers(1, &rpi->fbo_blur);
+	glGenRenderbuffers(1, &rpi->depth);
+	glGenTextures(1, &rpi->cubemap);
+
+	return rpi->self;
 }
 
 void RasterizerSceneGLES2::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) {
+
+	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+	ERR_FAIL_COND(!rpi);
+	rpi->transform = p_transform;
 }
 
 void RasterizerSceneGLES2::reflection_probe_release_atlas_index(RID p_instance) {
 }
 
 bool RasterizerSceneGLES2::reflection_probe_instance_needs_redraw(RID p_instance) {
-	return false;
+	const ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+	ERR_FAIL_COND_V(!rpi, false);
+
+	bool need_redraw = rpi->probe_ptr->resolution != rpi->current_resolution || rpi->dirty || rpi->probe_ptr->update_mode == VS::REFLECTION_PROBE_UPDATE_ALWAYS;
+	rpi->dirty = false;
+	return need_redraw;
 }
 
 bool RasterizerSceneGLES2::reflection_probe_instance_has_reflection(RID p_instance) {
-	return false;
+	return true;
 }
 
 bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
-	return false;
+
+	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+	ERR_FAIL_COND_V(!rpi, false);
+
+	rpi->render_step = 0;
+
+	if (rpi->probe_ptr->resolution != rpi->current_resolution) {
+
+		//update cubemap if resolution changed
+		int size = rpi->probe_ptr->resolution;
+		rpi->current_resolution = size;
+
+		int lod = 0;
+
+		GLenum internal_format = GL_RGBA;
+		GLenum format = GL_RGBA;
+		GLenum type = GL_UNSIGNED_BYTE;
+
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap);
+
+		// Set the initial (empty) mipmaps, all need to be set for this to work in GLES2, even if later wont be used.
+		while (size >= 1) {
+
+			for (int i = 0; i < 6; i++) {
+				glTexImage2D(_cube_side_enum[i], lod, internal_format, size, size, 0, format, type, NULL);
+				if (size == rpi->current_resolution) {
+					//adjust framebuffer
+					glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]);
+					glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0);
+					glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth);
+					glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
+					glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth);
+
+#ifdef DEBUG_ENABLED
+					GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+					ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE);
+#endif
+				}
+			}
+
+			lod++;
+
+			size >>= 1;
+		}
+
+		glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+		glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	}
+
+	return true;
 }
 
 bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_instance) {
-	return false;
+
+	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+	ERR_FAIL_COND_V(!rpi, false);
+
+	int size = rpi->probe_ptr->resolution;
+
+	{
+		glBindBuffer(GL_ARRAY_BUFFER, 0);
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+		glDisable(GL_CULL_FACE);
+		glDisable(GL_DEPTH_TEST);
+		glDisable(GL_SCISSOR_TEST);
+		glDisable(GL_BLEND);
+		glDepthMask(GL_FALSE);
+
+		for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+			glDisableVertexAttribArray(i);
+		}
+	}
+
+	//vdc cache
+	glActiveTexture(GL_TEXTURE1);
+	glBindTexture(GL_TEXTURE_2D, storage->resources.radical_inverse_vdc_cache_tex);
+
+	glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo_blur);
+	// now render to the framebuffer, mipmap level for mipmap level
+	int lod = 1;
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap);
+	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //use linear, no mipmaps so it does not read from what is being written to
+
+	size >>= 1;
+	int mipmaps = 6;
+	int mm_level = mipmaps - 1;
+
+	storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false);
+	storage->shaders.cubemap_filter.bind();
+
+	//blur
+	while (size >= 1) {
+
+		for (int i = 0; i < 6; i++) {
+			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, lod);
+
+			glViewport(0, 0, size, size);
+			storage->bind_quad_array();
+			storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i);
+			float roughness = CLAMP(lod / (float)(mipmaps - 1), 0, 1);
+			storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness);
+			storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false);
+
+			glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+		}
+
+		size >>= 1;
+
+		mm_level--;
+
+		lod++;
+	}
+
+	// restore ranges
+
+	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+	glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+	return true;
 }
 
 /* ENVIRONMENT API */
@@ -779,17 +932,37 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
 
 	e->material_index = e->material->index;
 
-	e->refprobe_0_index = 0xFF; //refprobe disabled by default
-	e->refprobe_1_index = 0xFF; //refprobe disabled by default
+	e->refprobe_0_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default
+	e->refprobe_1_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default
 
 	if (!p_depth_pass) {
 
 		e->depth_layer = e->instance->depth_layer;
 		e->priority = p_material->render_priority;
 
-		//if (e->instance->reflection_probe_instances.size() > 0 ) {
-		//	RasterizerStorageGLES2::
-		//}
+		int rpsize = e->instance->reflection_probe_instances.size();
+		if (rpsize > 0) {
+			bool first = true;
+			for (int i = 0; i < rpsize; i++) {
+				ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(e->instance->reflection_probe_instances[i]);
+				if (rpi->last_pass != render_pass) {
+					continue;
+				}
+				if (first) {
+					e->refprobe_0_index = rpi->index;
+					first = false;
+				} else {
+					e->refprobe_1_index = rpi->index;
+					break;
+				}
+			}
+
+			if (e->refprobe_0_index > e->refprobe_1_index) { //if both are valid, swap them to keep order as best as possible
+				uint16_t tmp = e->refprobe_0_index;
+				e->refprobe_0_index = e->refprobe_1_index;
+				e->refprobe_1_index = tmp;
+			}
+		}
 
 		//add directional lights
 
@@ -1505,7 +1678,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
 			}
 
 			state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, p_light->light_ptr->directional_blend_splits);
-			if (p_light->light_ptr->shadow) {
+			if (!state.render_no_shadows && p_light->light_ptr->shadow) {
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
 				glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
@@ -1517,7 +1690,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
 		case VS::LIGHT_OMNI: {
 
 			state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, true);
-			if (shadow_atlas && p_light->light_ptr->shadow) {
+			if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) {
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
 				glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
@@ -1528,7 +1701,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
 		case VS::LIGHT_SPOT: {
 
 			state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, true);
-			if (shadow_atlas && p_light->light_ptr->shadow) {
+			if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) {
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
 				glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
@@ -1562,7 +1735,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
 
 			CameraMatrix matrices[4];
 
-			if (light_ptr->shadow && directional_shadow.depth) {
+			if (!state.render_no_shadows && light_ptr->shadow && directional_shadow.depth) {
 
 				int shadow_count = 0;
 				Color split_offsets;
@@ -1657,7 +1830,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
 			attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
 			state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation);
 
-			if (light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) {
+			if (!state.render_no_shadows && light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) {
 
 				uint32_t key = shadow_atlas->shadow_owners[light->self];
 
@@ -1719,7 +1892,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
 			state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle);
 			state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range);
 
-			if (light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) {
+			if (!state.render_no_shadows && light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) {
 				uint32_t key = shadow_atlas->shadow_owners[light->self];
 
 				uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03;
@@ -1768,13 +1941,60 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
 	}
 }
 
+void RasterizerSceneGLES2::_setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env) {
+
+	if (p_refprobe1) {
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_USE_BOX_PROJECT, p_refprobe1->probe_ptr->box_projection);
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_BOX_EXTENTS, p_refprobe1->probe_ptr->extents);
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_BOX_OFFSET, p_refprobe1->probe_ptr->origin_offset);
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_EXTERIOR, !p_refprobe1->probe_ptr->interior);
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_INTENSITY, p_refprobe1->probe_ptr->intensity);
+
+		Color ambient;
+		if (p_refprobe1->probe_ptr->interior) {
+			ambient = p_refprobe1->probe_ptr->interior_ambient * p_refprobe1->probe_ptr->interior_ambient_energy;
+			ambient.a = p_refprobe1->probe_ptr->interior_ambient_probe_contrib;
+		} else if (p_env) {
+			ambient = p_env->ambient_color * p_env->ambient_energy;
+			ambient.a = p_env->ambient_sky_contribution;
+		}
+
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_AMBIENT, ambient);
+
+		Transform proj = (p_view_transform.inverse() * p_refprobe1->transform).affine_inverse();
+
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_LOCAL_MATRIX, proj);
+	}
+
+	if (p_refprobe2) {
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_USE_BOX_PROJECT, p_refprobe2->probe_ptr->box_projection);
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_EXTENTS, p_refprobe2->probe_ptr->extents);
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_OFFSET, p_refprobe2->probe_ptr->origin_offset);
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_EXTERIOR, !p_refprobe2->probe_ptr->interior);
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_INTENSITY, p_refprobe2->probe_ptr->intensity);
+
+		Color ambient;
+		if (p_refprobe2->probe_ptr->interior) {
+			ambient = p_refprobe2->probe_ptr->interior_ambient * p_refprobe2->probe_ptr->interior_ambient_energy;
+			ambient.a = p_refprobe2->probe_ptr->interior_ambient_probe_contrib;
+		} else if (p_env) {
+			ambient = p_env->ambient_color * p_env->ambient_energy;
+			ambient.a = p_env->ambient_sky_contribution;
+		}
+
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_AMBIENT, ambient);
+
+		Transform proj = (p_view_transform.inverse() * p_refprobe2->transform).affine_inverse();
+
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_LOCAL_MATRIX, proj);
+	}
+}
+
 void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow) {
 
 	ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
 
-	Vector2 screen_pixel_size;
-	screen_pixel_size.x = 1.0 / storage->frame.current_rt->width;
-	screen_pixel_size.y = 1.0 / storage->frame.current_rt->height;
+	Vector2 screen_pixel_size = state.screen_pixel_size;
 
 	bool use_radiance_map = false;
 	if (!p_shadow && p_base_env) {
@@ -1797,6 +2017,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
 	bool prev_base_pass = false;
 	LightInstance *prev_light = NULL;
 	bool prev_vertex_lit = false;
+	ReflectionProbeInstance *prev_refprobe_1 = NULL;
+	ReflectionProbeInstance *prev_refprobe_2 = NULL;
 
 	int prev_blend_mode = -2; //will always catch the first go
 
@@ -1815,6 +2037,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
 		bool accum_pass = *e->use_accum_ptr;
 		*e->use_accum_ptr = true; //set to accum for next time this is found
 		LightInstance *light = NULL;
+		ReflectionProbeInstance *refprobe_1 = NULL;
+		ReflectionProbeInstance *refprobe_2 = NULL;
 
 		if (!p_shadow) {
 
@@ -1911,6 +2135,27 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, vertex_lit);
 				prev_vertex_lit = vertex_lit;
 			}
+
+			if (!unshaded && !accum_pass && e->refprobe_0_index != RenderList::MAX_REFLECTION_PROBES) {
+				refprobe_1 = reflection_probe_instances[e->refprobe_0_index];
+			}
+			if (!unshaded && !accum_pass && e->refprobe_1_index != RenderList::MAX_REFLECTION_PROBES) {
+				refprobe_2 = reflection_probe_instances[e->refprobe_1_index];
+			}
+
+			if (refprobe_1 != prev_refprobe_1 || refprobe_2 != prev_refprobe_2) {
+				state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, refprobe_1 != NULL);
+				state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, refprobe_2 != NULL);
+				if (refprobe_1 != NULL && refprobe_1 != prev_refprobe_1) {
+					glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4);
+					glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_1->cubemap);
+				}
+				if (refprobe_2 != NULL && refprobe_2 != prev_refprobe_2) {
+					glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5);
+					glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_2->cubemap);
+				}
+				rebind = true;
+			}
 		}
 
 		bool instancing = e->instancing;
@@ -1975,6 +2220,10 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
 				if (light) {
 					_setup_light(light, shadow_atlas, p_view_transform);
 				}
+
+				if (refprobe_1 || refprobe_2) {
+					_setup_refprobes(refprobe_1, refprobe_2, p_view_transform, p_env);
+				}
 			}
 
 			state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, view_transform_inverse);
@@ -1997,6 +2246,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
 		prev_skeleton = skeleton;
 		prev_instancing = instancing;
 		prev_light = light;
+		prev_refprobe_1 = refprobe_1;
+		prev_refprobe_2 = refprobe_2;
 	}
 
 	_setup_light_type(NULL, NULL); //clear light stuff
@@ -2007,6 +2258,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
 	state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false);
 	state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false);
 	state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, false);
+	state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, false);
+	state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, false);
 }
 
 void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy) {
@@ -2101,6 +2354,36 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C
 
 void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
 
+	GLuint current_fb = 0;
+	Environment *env = NULL;
+
+	int viewport_width, viewport_height;
+
+	if (p_reflection_probe.is_valid()) {
+		ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe);
+		ERR_FAIL_COND(!probe);
+		state.render_no_shadows = !probe->probe_ptr->enable_shadows;
+
+		if (!probe->probe_ptr->interior) { //use env only if not interior
+			env = environment_owner.getornull(p_environment);
+		}
+
+		current_fb = probe->fbo[p_reflection_probe_pass];
+		state.screen_pixel_size.x = 1.0 / probe->probe_ptr->resolution;
+		state.screen_pixel_size.y = 1.0 / probe->probe_ptr->resolution;
+
+		viewport_width = probe->probe_ptr->resolution;
+		viewport_height = probe->probe_ptr->resolution;
+
+	} else {
+		state.render_no_shadows = false;
+		current_fb = storage->frame.current_rt->fbo;
+		env = environment_owner.getornull(p_environment);
+		state.screen_pixel_size.x = 1.0 / storage->frame.current_rt->width;
+		state.screen_pixel_size.y = 1.0 / storage->frame.current_rt->height;
+		viewport_width = storage->frame.current_rt->width;
+		viewport_height = storage->frame.current_rt->height;
+	}
 	//push back the directional lights
 
 	if (p_light_cull_count) {
@@ -2133,10 +2416,21 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
 		render_light_instance_count = 0;
 	}
 
-	glEnable(GL_BLEND);
+	if (p_reflection_probe_cull_count) {
+
+		reflection_probe_instances = (ReflectionProbeInstance **)alloca(sizeof(ReflectionProbeInstance *) * p_reflection_probe_cull_count);
 
-	GLuint current_fb = storage->frame.current_rt->fbo;
-	Environment *env = environment_owner.getornull(p_environment);
+		for (int i = 0; i < p_reflection_probe_cull_count; i++) {
+			ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe_cull_result[i]);
+			ERR_CONTINUE(!rpi);
+			rpi->last_pass = render_pass + 1; //will be incremented later
+			rpi->index = i;
+			reflection_probe_instances[i] = rpi;
+		}
+
+	} else {
+		reflection_probe_instances = NULL;
+	}
 
 	// render list stuff
 
@@ -2146,6 +2440,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
 	// other stuff
 
 	glBindFramebuffer(GL_FRAMEBUFFER, current_fb);
+	glViewport(0, 0, viewport_width, viewport_height);
 
 	glDepthFunc(GL_LEQUAL);
 	glDepthMask(GL_TRUE);
@@ -2247,6 +2542,8 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
 
 void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
 
+	state.render_no_shadows = false;
+
 	LightInstance *light_instance = light_instance_owner.getornull(p_light);
 	ERR_FAIL_COND(!light_instance);
 

+ 36 - 0
drivers/gles2/rasterizer_scene_gles2.h

@@ -204,6 +204,9 @@ public:
 		float dual_parbolloid_direction;
 		float dual_parbolloid_zfar;
 
+		bool render_no_shadows;
+
+		Vector2 screen_pixel_size;
 	} state;
 
 	/* SHADOW ATLAS API */
@@ -287,6 +290,37 @@ public:
 
 	/* REFLECTION PROBE INSTANCE */
 
+	struct ReflectionProbeInstance : public RID_Data {
+
+		RasterizerStorageGLES2::ReflectionProbe *probe_ptr;
+		RID probe;
+		RID self;
+		RID atlas;
+
+		int reflection_atlas_index;
+
+		int render_step;
+		int reflection_index;
+
+		GLuint fbo[6];
+		GLuint cubemap;
+		GLuint depth;
+
+		GLuint fbo_blur;
+
+		int current_resolution;
+		mutable bool dirty;
+
+		uint64_t last_pass;
+		uint32_t index;
+
+		Transform transform;
+	};
+
+	mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
+
+	ReflectionProbeInstance **reflection_probe_instances;
+
 	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);
@@ -424,6 +458,7 @@ public:
 
 		enum {
 			MAX_LIGHTS = 255,
+			MAX_REFLECTION_PROBES = 255,
 			DEFAULT_MAX_ELEMENTS = 65536
 		};
 
@@ -587,6 +622,7 @@ public:
 	_FORCE_INLINE_ void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton);
 	_FORCE_INLINE_ void _setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas);
 	_FORCE_INLINE_ void _setup_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform);
+	_FORCE_INLINE_ void _setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env);
 	_FORCE_INLINE_ void _render_geometry(RenderList::Element *p_element);
 
 	virtual void render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);

+ 251 - 12
drivers/gles2/rasterizer_storage_gles2.cpp

@@ -3307,69 +3307,194 @@ AABB RasterizerStorageGLES2::light_get_aabb(RID p_light) const {
 /* PROBE API */
 
 RID RasterizerStorageGLES2::reflection_probe_create() {
-	return RID();
+
+	ReflectionProbe *reflection_probe = memnew(ReflectionProbe);
+
+	reflection_probe->intensity = 1.0;
+	reflection_probe->interior_ambient = Color();
+	reflection_probe->interior_ambient_energy = 1.0;
+	reflection_probe->max_distance = 0;
+	reflection_probe->extents = Vector3(1, 1, 1);
+	reflection_probe->origin_offset = Vector3(0, 0, 0);
+	reflection_probe->interior = false;
+	reflection_probe->box_projection = false;
+	reflection_probe->enable_shadows = false;
+	reflection_probe->cull_mask = (1 << 20) - 1;
+	reflection_probe->update_mode = VS::REFLECTION_PROBE_UPDATE_ONCE;
+	reflection_probe->resolution = 128;
+
+	return reflection_probe_owner.make_rid(reflection_probe);
 }
 
 void RasterizerStorageGLES2::reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) {
+
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->update_mode = p_mode;
+	reflection_probe->instance_change_notify();
 }
 
 void RasterizerStorageGLES2::reflection_probe_set_intensity(RID p_probe, float p_intensity) {
+
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->intensity = p_intensity;
 }
 
 void RasterizerStorageGLES2::reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) {
+
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->interior_ambient = p_ambient;
 }
 
 void RasterizerStorageGLES2::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) {
+
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->interior_ambient_energy = p_energy;
 }
 
 void RasterizerStorageGLES2::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) {
+
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->interior_ambient_probe_contrib = p_contrib;
 }
 
 void RasterizerStorageGLES2::reflection_probe_set_max_distance(RID p_probe, float p_distance) {
-}
 
-void RasterizerStorageGLES2::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) {
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->max_distance = p_distance;
+	reflection_probe->instance_change_notify();
 }
+void RasterizerStorageGLES2::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) {
+
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
 
+	reflection_probe->extents = p_extents;
+	reflection_probe->instance_change_notify();
+}
 void RasterizerStorageGLES2::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) {
+
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->origin_offset = p_offset;
+	reflection_probe->instance_change_notify();
 }
 
 void RasterizerStorageGLES2::reflection_probe_set_as_interior(RID p_probe, bool p_enable) {
-}
 
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->interior = p_enable;
+}
 void RasterizerStorageGLES2::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {
+
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->box_projection = p_enable;
 }
 
 void RasterizerStorageGLES2::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {
-}
 
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->enable_shadows = p_enable;
+	reflection_probe->instance_change_notify();
+}
 void RasterizerStorageGLES2::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {
+
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->cull_mask = p_layers;
+	reflection_probe->instance_change_notify();
+}
+
+void RasterizerStorageGLES2::reflection_probe_set_resolution(RID p_probe, int p_resolution) {
+
+	ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!reflection_probe);
+
+	reflection_probe->resolution = p_resolution;
 }
 
 AABB RasterizerStorageGLES2::reflection_probe_get_aabb(RID p_probe) const {
-	return AABB();
+	const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!reflection_probe, AABB());
+
+	AABB aabb;
+	aabb.position = -reflection_probe->extents;
+	aabb.size = reflection_probe->extents * 2.0;
+
+	return aabb;
 }
 VS::ReflectionProbeUpdateMode RasterizerStorageGLES2::reflection_probe_get_update_mode(RID p_probe) const {
-	return VS::REFLECTION_PROBE_UPDATE_ALWAYS;
+
+	const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!reflection_probe, VS::REFLECTION_PROBE_UPDATE_ALWAYS);
+
+	return reflection_probe->update_mode;
 }
 
 uint32_t RasterizerStorageGLES2::reflection_probe_get_cull_mask(RID p_probe) const {
-	return 0;
+
+	const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!reflection_probe, 0);
+
+	return reflection_probe->cull_mask;
 }
 
 Vector3 RasterizerStorageGLES2::reflection_probe_get_extents(RID p_probe) const {
-	return Vector3();
+
+	const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!reflection_probe, Vector3());
+
+	return reflection_probe->extents;
 }
 Vector3 RasterizerStorageGLES2::reflection_probe_get_origin_offset(RID p_probe) const {
-	return Vector3();
+
+	const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!reflection_probe, Vector3());
+
+	return reflection_probe->origin_offset;
 }
 
 bool RasterizerStorageGLES2::reflection_probe_renders_shadows(RID p_probe) const {
-	return false;
+
+	const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!reflection_probe, false);
+
+	return reflection_probe->enable_shadows;
 }
 
 float RasterizerStorageGLES2::reflection_probe_get_origin_max_distance(RID p_probe) const {
-	return 0;
+
+	const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!reflection_probe, 0);
+
+	return reflection_probe->max_distance;
+}
+
+int RasterizerStorageGLES2::reflection_probe_get_resolution(RID p_probe) const {
+
+	const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!reflection_probe, 0);
+
+	return reflection_probe->resolution;
 }
 
 RID RasterizerStorageGLES2::gi_probe_create() {
@@ -3601,15 +3726,115 @@ void RasterizerStorageGLES2::update_particles() {
 ////////
 
 void RasterizerStorageGLES2::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {
+
+	Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+	ERR_FAIL_COND(!skeleton);
+
+	skeleton->instances.insert(p_instance);
 }
 
 void RasterizerStorageGLES2::instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {
+
+	Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+	ERR_FAIL_COND(!skeleton);
+
+	skeleton->instances.erase(p_instance);
 }
 
 void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {
+
+	Instanciable *inst = NULL;
+	switch (p_instance->base_type) {
+		case VS::INSTANCE_MESH: {
+			inst = mesh_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		case VS::INSTANCE_MULTIMESH: {
+			inst = multimesh_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		case VS::INSTANCE_IMMEDIATE: {
+			inst = immediate_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		/*case VS::INSTANCE_PARTICLES: {
+			inst = particles_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;*/
+		case VS::INSTANCE_REFLECTION_PROBE: {
+			inst = reflection_probe_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		case VS::INSTANCE_LIGHT: {
+			inst = light_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		/*case VS::INSTANCE_GI_PROBE: {
+			inst = gi_probe_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;*/
+		/*case VS::INSTANCE_LIGHTMAP_CAPTURE: {
+			inst = lightmap_capture_data_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;*/
+		default: {
+			if (!inst) {
+				ERR_FAIL();
+			}
+		}
+	}
+
+	inst->instance_list.add(&p_instance->dependency_item);
 }
 
 void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {
+
+	Instanciable *inst = NULL;
+
+	switch (p_instance->base_type) {
+		case VS::INSTANCE_MESH: {
+			inst = mesh_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		case VS::INSTANCE_MULTIMESH: {
+			inst = multimesh_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		case VS::INSTANCE_IMMEDIATE: {
+			inst = immediate_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		/*case VS::INSTANCE_PARTICLES: {
+			inst = particles_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;*/
+		case VS::INSTANCE_REFLECTION_PROBE: {
+			inst = reflection_probe_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		case VS::INSTANCE_LIGHT: {
+			inst = light_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		/*case VS::INSTANCE_GI_PROBE: {
+			inst = gi_probe_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		case VS::INSTANCE_LIGHTMAP_CAPTURE: {
+			inst = lightmap_capture_data_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;*/
+		default: {
+
+			if (!inst) {
+				ERR_FAIL();
+			}
+		}
+	}
+
+	ERR_FAIL_COND(!inst);
+
+	inst->instance_list.remove(&p_instance->dependency_item);
 }
 
 /* RENDER TARGET */
@@ -3867,6 +4092,8 @@ VS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const {
 		return VS::INSTANCE_MULTIMESH;
 	} else if (immediate_owner.owns(p_rid)) {
 		return VS::INSTANCE_IMMEDIATE;
+	} else if (reflection_probe_owner.owns(p_rid)) {
+		return VS::INSTANCE_REFLECTION_PROBE;
 	} else {
 		return VS::INSTANCE_NONE;
 	}
@@ -4044,6 +4271,17 @@ bool RasterizerStorageGLES2::free(RID p_rid) {
 		memdelete(light);
 
 		return true;
+	} else if (reflection_probe_owner.owns(p_rid)) {
+
+		// delete the texture
+		ReflectionProbe *reflection_probe = reflection_probe_owner.get(p_rid);
+		reflection_probe->instance_remove_deps();
+
+		reflection_probe_owner.free(p_rid);
+		memdelete(reflection_probe);
+
+		return true;
+
 	} else {
 		return false;
 	}
@@ -4095,6 +4333,7 @@ void RasterizerStorageGLES2::initialize() {
 	}
 
 	config.shrink_textures_x2 = false;
+
 	config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float");
 	config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc");
 	config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture");

+ 23 - 0
drivers/gles2/rasterizer_storage_gles2.h

@@ -955,6 +955,26 @@ public:
 	virtual uint64_t light_get_version(RID p_light) const;
 
 	/* PROBE API */
+
+	struct ReflectionProbe : Instanciable {
+
+		VS::ReflectionProbeUpdateMode update_mode;
+		float intensity;
+		Color interior_ambient;
+		float interior_ambient_energy;
+		float interior_ambient_probe_contrib;
+		float max_distance;
+		Vector3 extents;
+		Vector3 origin_offset;
+		bool interior;
+		bool box_projection;
+		bool enable_shadows;
+		uint32_t cull_mask;
+		int resolution;
+	};
+
+	mutable RID_Owner<ReflectionProbe> reflection_probe_owner;
+
 	virtual RID reflection_probe_create();
 
 	virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode);
@@ -969,11 +989,14 @@ public:
 	virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable);
 	virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable);
 	virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers);
+	virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution);
 
 	virtual AABB reflection_probe_get_aabb(RID p_probe) const;
 	virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const;
 	virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const;
 
+	virtual int reflection_probe_get_resolution(RID p_probe) const;
+
 	virtual Vector3 reflection_probe_get_extents(RID p_probe) const;
 	virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const;
 	virtual float reflection_probe_get_origin_max_distance(RID p_probe) const;

+ 0 - 1
drivers/gles2/shaders/cubemap_filter.glsl

@@ -176,7 +176,6 @@ void main() {
 #ifdef USE_SOURCE_PANORAMA
 			sum.rgb += texturePanorama(source_panorama, L).rgb * NdotL;
 #else
-			L.y = -L.y;
 			sum.rgb += textureCubeLod(source_cube, L, 0.0).rgb * NdotL;
 #endif
 

+ 282 - 1
drivers/gles2/shaders/scene.glsl

@@ -262,6 +262,35 @@ void light_compute(
 
 #endif
 
+#ifdef USE_VERTEX_LIGHTING
+
+#ifdef USE_REFLECTION_PROBE1
+
+uniform mat4 refprobe1_local_matrix;
+varying mediump vec4 refprobe1_reflection_normal_blend;
+uniform vec3 refprobe1_box_extents;
+
+#ifndef USE_LIGHTMAP
+varying mediump vec3 refprobe1_ambient_normal;
+#endif
+
+#endif //reflection probe1
+
+#ifdef USE_REFLECTION_PROBE2
+
+uniform mat4 refprobe2_local_matrix;
+varying mediump vec4 refprobe2_reflection_normal_blend;
+uniform vec3 refprobe2_box_extents;
+
+#ifndef USE_LIGHTMAP
+varying mediump vec3 refprobe2_ambient_normal;
+#endif
+
+#endif //reflection probe2
+
+#endif //vertex lighting for refprobes
+
+
 void main() {
 
 	highp vec4 vertex = vertex_attrib;
@@ -498,6 +527,52 @@ VERTEX_SHADER_CODE
 
 #endif //use shadow and use lighting
 
+#ifdef USE_VERTEX_LIGHTING
+
+#ifdef USE_REFLECTION_PROBE1
+	{
+		vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp));
+		vec3 local_pos = (refprobe1_local_matrix * vec4(vertex_interp, 1.0)).xyz;		
+		vec3 inner_pos = abs(local_pos / refprobe1_box_extents);
+		float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
+
+		{
+			vec3 local_ref_vec = (refprobe1_local_matrix * vec4(ref_normal, 0.0)).xyz;
+			refprobe1_reflection_normal_blend.xyz = local_ref_vec;
+			refprobe1_reflection_normal_blend.a = blend;
+
+		}
+#ifndef USE_LIGHTMAP
+
+		refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz;
+#endif
+	}
+
+#endif //USE_REFLECTION_PROBE1
+
+
+#ifdef USE_REFLECTION_PROBE2
+	{
+		vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp));
+		vec3 local_pos = (refprobe2_local_matrix * vec4(vertex_interp, 1.0)).xyz;
+		vec3 inner_pos = abs(local_pos / refprobe2_box_extents);
+		float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
+
+		{
+			vec3 local_ref_vec = (refprobe2_local_matrix * vec4(ref_normal, 0.0)).xyz;
+			refprobe2_reflection_normal_blend.xyz = local_ref_vec;
+			refprobe2_reflection_normal_blend.a = blend;
+
+		}
+#ifndef USE_LIGHTMAP
+
+		refprobe2_ambient_normal = (refprobe2_local_matrix * vec4(normal_interp, 0.0)).xyz;
+#endif
+	}
+
+#endif //USE_REFLECTION_PROBE2
+
+#endif //use vertex lighting
 	gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
 }
 
@@ -548,10 +623,161 @@ uniform vec2 screen_pixel_size;
 uniform highp sampler2D screen_texture; //texunit:-4
 #endif
 
-#ifdef USE_RADIANCE_MAP
+#ifdef USE_REFLECTION_PROBE1
+
+#ifdef USE_VERTEX_LIGHTING
+
+varying mediump vec4 refprobe1_reflection_normal_blend;
+#ifndef USE_LIGHTMAP
+varying mediump vec3 refprobe1_ambient_normal;
+#endif
+
+#else
+
+uniform bool refprobe1_use_box_project;
+uniform vec3 refprobe1_box_extents;
+uniform vec3 refprobe1_box_offset;
+uniform mat4 refprobe1_local_matrix;
+
+#endif //use vertex lighting
+
+uniform bool refprobe1_exterior;
+
+uniform highp samplerCube reflection_probe1; //texunit:-4
+
+uniform float refprobe1_intensity;
+uniform vec4 refprobe1_ambient;
+
+#endif //USE_REFLECTION_PROBE1
+
+#ifdef USE_REFLECTION_PROBE2
+
+#ifdef USE_VERTEX_LIGHTING
+
+varying mediump vec4 refprobe2_reflection_normal_blend;
+#ifndef USE_LIGHTMAP
+varying mediump vec3 refprobe2_ambient_normal;
+#endif
+
+#else
+
+uniform bool refprobe2_use_box_project;
+uniform vec3 refprobe2_box_extents;
+uniform vec3 refprobe2_box_offset;
+uniform mat4 refprobe2_local_matrix;
+
+#endif //use vertex lighting
+
+uniform bool refprobe2_exterior;
+
+uniform highp samplerCube reflection_probe2; //texunit:-5
+
+uniform float refprobe2_intensity;
+uniform vec4 refprobe2_ambient;
+
+#endif //USE_REFLECTION_PROBE2
 
 #define RADIANCE_MAX_LOD 6.0
 
+#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)
+
+void reflection_process(samplerCube reflection_map,
+#ifdef USE_VERTEX_LIGHTING
+			vec3 ref_normal,
+#ifndef USE_LIGHTMAP
+			vec3 amb_normal,
+#endif
+			float ref_blend,
+
+#else //no vertex lighting
+			vec3 normal, vec3 vertex,
+			mat4 local_matrix,
+			bool use_box_project, vec3 box_extents, vec3 box_offset,
+#endif //vertex lighting
+			bool exterior,float intensity, vec4 ref_ambient, float roughness, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) {
+
+	vec4 reflection;
+
+#ifdef USE_VERTEX_LIGHTING
+
+	reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb;
+
+	float blend = ref_blend; //crappier blend formula for vertex
+	blend *= blend;
+	blend = max(0.0, 1.0 - blend);
+
+#else //fragment lighting
+
+	vec3 local_pos = (local_matrix * vec4(vertex, 1.0)).xyz;
+
+	if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box
+		return;
+	}
+
+	vec3 inner_pos = abs(local_pos / box_extents);
+	float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
+	blend = mix(length(inner_pos), blend, blend);
+	blend *= blend;
+	blend = max(0.0, 1.0 - blend);
+
+	//reflect and make local
+	vec3 ref_normal = normalize(reflect(vertex, normal));
+	ref_normal = (local_matrix * vec4(ref_normal, 0.0)).xyz;
+
+	if (use_box_project) { //box project
+
+		vec3 nrdir = normalize(ref_normal);
+		vec3 rbmax = (box_extents - local_pos) / nrdir;
+		vec3 rbmin = (-box_extents - local_pos) / nrdir;
+
+		vec3 rbminmax = mix(rbmin, rbmax, vec3(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;
+		ref_normal = posonbox - box_offset.xyz;
+	}
+
+	reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb;
+#endif
+
+	if (exterior) {
+		reflection.rgb = mix(skybox, reflection.rgb, blend);
+	}
+	reflection.rgb *= intensity;
+	reflection.a = blend;
+	reflection.rgb *= blend;
+
+	reflection_accum += reflection;
+
+
+#ifndef USE_LIGHTMAP
+
+	vec4 ambient_out;
+#ifndef USE_VERTEX_LIGHTING
+
+	vec3 amb_normal = (local_matrix * vec4(normal, 0.0)).xyz;
+#endif
+
+	ambient_out.rgb = textureCubeLod(reflection_map, amb_normal, RADIANCE_MAX_LOD).rgb;
+	ambient_out.a = blend;
+	ambient_out.rgb = mix(ref_ambient.rgb, ambient_out.rgb, ref_ambient.a);
+	if (exterior) {
+		ambient_out.rgb = mix(ambient, ambient_out.rgb, blend);
+	}
+
+	ambient_out.rgb *= blend;
+	ambient_accum += ambient_out;
+
+#endif
+}
+
+#endif //use refprobe 1 or 2
+
+
+
+#ifdef USE_RADIANCE_MAP
+
+
 uniform samplerCube radiance_map; // texunit:-2
 
 uniform mat4 radiance_inverse_xform;
@@ -660,6 +886,8 @@ vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) {
 	return mix(vec3(dielectric), albedo, metallic); // TODO: reference?
 }
 
+
+
 /* clang-format off */
 
 FRAGMENT_SHADER_GLOBALS
@@ -1123,6 +1351,59 @@ FRAGMENT_SHADER_CODE
 
 	ambient_light *= ambient_energy;
 
+	
+	
+#ifdef USE_REFLECTION_PROBE1
+
+	vec4 ambient_accum = vec4(0.0);
+	vec4 reflection_accum = vec4(0.0);
+
+
+	reflection_process(reflection_probe1,
+#ifdef USE_VERTEX_LIGHTING
+			   refprobe1_reflection_normal_blend.rgb,
+#ifndef USE_LIGHTMAP		
+			   refprobe1_ambient_normal,
+#endif			   
+			   refprobe1_reflection_normal_blend.a,
+#else
+			   normal_interp,vertex_interp,refprobe1_local_matrix,
+			   refprobe1_use_box_project,refprobe1_box_extents,refprobe1_box_offset,
+#endif
+			   refprobe1_exterior,refprobe1_intensity, refprobe1_ambient, roughness,
+			   ambient_light, specular_light, reflection_accum, ambient_accum);
+
+
+#ifdef USE_REFLECTION_PROBE2
+
+	reflection_process(reflection_probe2,
+#ifdef USE_VERTEX_LIGHTING
+			   refprobe2_reflection_normal_blend.rgb,
+#ifndef USE_LIGHTMAP
+			   refprobe2_ambient_normal,
+#endif
+			   refprobe2_reflection_normal_blend.a,
+#else
+			   normal_interp,vertex_interp,refprobe2_local_matrix,
+			   refprobe2_use_box_project,refprobe2_box_extents,refprobe2_box_offset,
+#endif
+			   refprobe2_exterior,refprobe2_intensity, refprobe2_ambient, roughness,
+			   ambient_light, specular_light, reflection_accum, ambient_accum);
+
+#endif // USE_REFLECTION_PROBE2
+
+	if (reflection_accum.a > 0.0) {
+		specular_light = reflection_accum.rgb / reflection_accum.a;
+	}
+
+#ifndef USE_LIGHTMAP
+	if (ambient_accum.a > 0.0) {
+		ambient_light = ambient_accum.rgb / ambient_accum.a;
+	}
+#endif
+
+#endif //use reflection probe 1
+
 #endif //BASE PASS
 
 //

+ 3 - 0
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -5295,6 +5295,9 @@ void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_
 	reflection_probe->instance_change_notify();
 }
 
+void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution) {
+}
+
 AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const {
 	const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
 	ERR_FAIL_COND_V(!reflection_probe, AABB());

+ 1 - 0
drivers/gles3/rasterizer_storage_gles3.h

@@ -1005,6 +1005,7 @@ public:
 	virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable);
 	virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable);
 	virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers);
+	virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution);
 
 	virtual AABB reflection_probe_get_aabb(RID p_probe) const;
 	virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const;

+ 14 - 0
editor/editor_node.cpp

@@ -4523,6 +4523,16 @@ void EditorNode::_bottom_panel_raise_toggled(bool p_pressed) {
 	}
 }
 
+void EditorNode::_update_video_driver_color() {
+
+	//todo probably should de-harcode this and add to editor settings
+	if (video_driver->get_text() == "GLES2") {
+		video_driver->add_color_override("font_color", Color::hex(0x5586a4ff));
+	} else if (video_driver->get_text() == "GLES3") {
+		video_driver->add_color_override("font_color", Color::hex(0xa5557dff));
+	}
+}
+
 void EditorNode::_video_driver_selected(int p_which) {
 
 	String driver = video_driver->get_item_metadata(p_which);
@@ -4536,6 +4546,7 @@ void EditorNode::_video_driver_selected(int p_which) {
 	video_driver_request = driver;
 	video_restart_dialog->popup_centered_minsize();
 	video_driver->select(video_driver_current);
+	_update_video_driver_color();
 }
 
 void EditorNode::_bind_methods() {
@@ -5398,6 +5409,7 @@ EditorNode::EditorNode() {
 	video_driver->set_focus_mode(Control::FOCUS_NONE);
 	video_driver->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
 	video_driver->connect("item_selected", this, "_video_driver_selected");
+	video_driver->add_font_override("font", gui_base->get_font("bold", "EditorFonts"));
 	menu_hb->add_child(video_driver);
 
 	String video_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/quality/driver/driver_name"].hint_string;
@@ -5414,6 +5426,8 @@ EditorNode::EditorNode() {
 		}
 	}
 
+	_update_video_driver_color();
+
 	video_restart_dialog = memnew(ConfirmationDialog);
 	video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor."));
 	video_restart_dialog->get_ok()->set_text(TTR("Save & Restart"));

+ 1 - 0
editor/editor_node.h

@@ -208,6 +208,7 @@ private:
 	int video_driver_current;
 	String video_driver_request;
 	void _video_driver_selected(int);
+	void _update_video_driver_color();
 
 	// Split containers
 

+ 1 - 0
servers/visual/rasterizer.h

@@ -397,6 +397,7 @@ public:
 	virtual RID reflection_probe_create() = 0;
 
 	virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) = 0;
+	virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0;
 	virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0;
 	virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) = 0;
 	virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) = 0;

+ 1 - 0
servers/visual/visual_server_raster.h

@@ -337,6 +337,7 @@ public:
 	BIND2(reflection_probe_set_enable_box_projection, RID, bool)
 	BIND2(reflection_probe_set_enable_shadows, RID, bool)
 	BIND2(reflection_probe_set_cull_mask, RID, uint32_t)
+	BIND2(reflection_probe_set_resolution, RID, int)
 
 	/* BAKED LIGHT API */
 

+ 2 - 0
servers/visual/visual_server_scene.cpp

@@ -2141,6 +2141,8 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int
 	Scenario *scenario = p_instance->scenario;
 	ERR_FAIL_COND_V(!scenario, true);
 
+	VisualServerRaster::redraw_request(); //update, so it updates in editor
+
 	if (p_step == 0) {
 
 		if (!VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) {

+ 1 - 0
servers/visual/visual_server_wrap_mt.h

@@ -271,6 +271,7 @@ public:
 	FUNC2(reflection_probe_set_enable_box_projection, RID, bool)
 	FUNC2(reflection_probe_set_enable_shadows, RID, bool)
 	FUNC2(reflection_probe_set_cull_mask, RID, uint32_t)
+	FUNC2(reflection_probe_set_resolution, RID, int)
 
 	/* BAKED LIGHT API */
 

+ 1 - 0
servers/visual_server.h

@@ -490,6 +490,7 @@ public:
 	virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0;
 	virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0;
 	virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
+	virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0;
 
 	/* GI PROBE API */