Browse Source

Subsurface scattering material param is now working!

Juan Linietsky 8 years ago
parent
commit
27a46d78ec

+ 81 - 10
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -1809,6 +1809,10 @@ void RasterizerSceneGLES3::_add_geometry(  RasterizerStorageGLES3::Geometry* p_g
 		mirror=!mirror;
 		mirror=!mirror;
 	}
 	}
 
 
+	if (m->shader->spatial.uses_sss) {
+		state.used_sss=true;
+	}
+
 	if (p_shadow) {
 	if (p_shadow) {
 
 
 		if (has_blend_alpha || (has_base_alpha && m->shader->spatial.depth_draw_mode!=RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS))
 		if (has_blend_alpha || (has_base_alpha && m->shader->spatial.depth_draw_mode!=RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS))
@@ -1827,6 +1831,7 @@ void RasterizerSceneGLES3::_add_geometry(  RasterizerStorageGLES3::Geometry* p_g
 	}
 	}
 
 
 
 
+
 	RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element();
 	RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element();
 
 
 	if (!e)
 	if (!e)
@@ -2620,6 +2625,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_
 
 
 	current_geometry_index=0;
 	current_geometry_index=0;
 	current_material_index=0;
 	current_material_index=0;
+	state.used_sss=false;
 
 
 	//fill list
 	//fill list
 
 
@@ -2683,6 +2689,50 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env,const CameraMatrix &p_c
 	glDisable(GL_CULL_FACE);
 	glDisable(GL_CULL_FACE);
 	glDisable(GL_BLEND);
 	glDisable(GL_BLEND);
 
 
+	if (state.used_sss) {//sss enabled
+		//copy diffuse while performing sss
+
+		state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_11_SAMPLES,subsurface_scatter_quality==SSS_QUALITY_LOW);
+		state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_17_SAMPLES,subsurface_scatter_quality==SSS_QUALITY_MEDIUM);
+		state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_25_SAMPLES,subsurface_scatter_quality==SSS_QUALITY_HIGH);
+		state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::ENABLE_FOLLOW_SURFACE,subsurface_scatter_follow_surface);
+		state.sss_shader.bind();
+		state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::MAX_RADIUS,subsurface_scatter_size);
+		state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::FOVY,p_cam_projection.get_fov());
+		state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::CAMERA_Z_NEAR,p_cam_projection.get_z_near());
+		state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::CAMERA_Z_FAR,p_cam_projection.get_z_far());
+		state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::DIR,Vector2(1,0));
+
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse);
+		glActiveTexture(GL_TEXTURE1);
+		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.motion_sss);
+		glActiveTexture(GL_TEXTURE2);
+		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->depth);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+
+		glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->fbo); //copy to front first
+
+		_copy_screen();
+
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->color);
+		state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::DIR,Vector2(0,1));
+		glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level
+		_copy_screen();
+
+	} else {
+		// just copy diffuse
+		storage->shaders.copy.bind();
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse);
+		glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level
+		_copy_screen();
+
+	}
+
+
+
 	if (env->ssr_enabled) {
 	if (env->ssr_enabled) {
 		//blur diffuse into effect mipmaps using separatable convolution
 		//blur diffuse into effect mipmaps using separatable convolution
 		//storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true);
 		//storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true);
@@ -2698,11 +2748,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env,const CameraMatrix &p_c
 			state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE,Vector2(1.0/vp_w,1.0/vp_h));
 			state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE,Vector2(1.0/vp_w,1.0/vp_h));
 			state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD,float(i));
 			state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD,float(i));
 			glActiveTexture(GL_TEXTURE0);
 			glActiveTexture(GL_TEXTURE0);
-			if (i==0) {
-				glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse);
-			} else {
-				glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->effects.mip_maps[0].color); //previous level, since mipmaps[0] starts one level bigger
-			}
+			glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->effects.mip_maps[0].color); //previous level, since mipmaps[0] starts one level bigger
 			glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->effects.mip_maps[1].sizes[i].fbo);
 			glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->effects.mip_maps[1].sizes[i].fbo);
 			_copy_screen();
 			_copy_screen();
 			state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_HORIZONTAL,false);
 			state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_HORIZONTAL,false);
@@ -2748,7 +2794,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env,const CameraMatrix &p_c
 		glActiveTexture(GL_TEXTURE0);
 		glActiveTexture(GL_TEXTURE0);
 		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse);
 		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse);
 		glActiveTexture(GL_TEXTURE1);
 		glActiveTexture(GL_TEXTURE1);
-		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.normal_sr);
+		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.normal_rough);
 		glActiveTexture(GL_TEXTURE2);
 		glActiveTexture(GL_TEXTURE2);
 		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->depth);
 		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->depth);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
@@ -2764,22 +2810,26 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env,const CameraMatrix &p_c
 	}
 	}
 
 
 
 
+	//copy reflection over diffuse, resolving SSR if needed
 	state.resolve_shader.set_conditional(ResolveShaderGLES3::USE_SSR,env->ssr_enabled);
 	state.resolve_shader.set_conditional(ResolveShaderGLES3::USE_SSR,env->ssr_enabled);
 	state.resolve_shader.bind();
 	state.resolve_shader.bind();
 	glActiveTexture(GL_TEXTURE0);
 	glActiveTexture(GL_TEXTURE0);
-	glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse);
-	glActiveTexture(GL_TEXTURE1);
 	glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.specular);
 	glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.specular);
 	if (env->ssr_enabled) {
 	if (env->ssr_enabled) {
-		glActiveTexture(GL_TEXTURE2);
+		glActiveTexture(GL_TEXTURE1);
 		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->effects.mip_maps[1].color);
 		glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->effects.mip_maps[1].color);
 	}
 	}
 
 
 
 
 	glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo);
 	glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo);
-	//glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->fbo);
+	glEnable(GL_BLEND);
+	glBlendEquation(GL_FUNC_ADD);
+	glBlendFunc(GL_ONE,GL_ONE); //use additive to accumulate one over the other
+
 	_copy_screen();
 	_copy_screen();
 
 
+	glDisable(GL_BLEND); //end additive
+
 	state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::SIMPLE_COPY,true);
 	state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::SIMPLE_COPY,true);
 	state.effect_blur_shader.bind();
 	state.effect_blur_shader.bind();
 	state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD,float(0));
 	state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD,float(0));
@@ -2839,6 +2889,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C
 	bool use_mrt=true;
 	bool use_mrt=true;
 
 
 
 
+
 	_fill_render_list(p_cull_result,p_cull_count,false);
 	_fill_render_list(p_cull_result,p_cull_count,false);
 	//
 	//
 
 
@@ -2893,11 +2944,17 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C
 			draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
 			draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
 			draw_buffers.push_back(GL_COLOR_ATTACHMENT1);
 			draw_buffers.push_back(GL_COLOR_ATTACHMENT1);
 			draw_buffers.push_back(GL_COLOR_ATTACHMENT2);
 			draw_buffers.push_back(GL_COLOR_ATTACHMENT2);
+			if (state.used_sss) {
+				draw_buffers.push_back(GL_COLOR_ATTACHMENT3);
+			}
 			glDrawBuffers(draw_buffers.size(),draw_buffers.ptr());
 			glDrawBuffers(draw_buffers.size(),draw_buffers.ptr());
 
 
 			Color black(0,0,0,0);
 			Color black(0,0,0,0);
 			glClearBufferfv(GL_COLOR,1,black.components); // specular
 			glClearBufferfv(GL_COLOR,1,black.components); // specular
 			glClearBufferfv(GL_COLOR,2,black.components); // normal metal rough
 			glClearBufferfv(GL_COLOR,2,black.components); // normal metal rough
+			if (state.used_sss) {
+				glClearBufferfv(GL_COLOR,3,black.components); // normal metal rough
+			}
 
 
 		} else {
 		} else {
 
 
@@ -3968,11 +4025,25 @@ void RasterizerSceneGLES3::initialize() {
 	state.resolve_shader.init();
 	state.resolve_shader.init();
 	state.ssr_shader.init();
 	state.ssr_shader.init();
 	state.effect_blur_shader.init();
 	state.effect_blur_shader.init();
+	state.sss_shader.init();
+
+
+	{
+		GLOBAL_DEF("rendering/gles3/subsurface_scattering/quality",1);
+		Globals::get_singleton()->set_custom_property_info("rendering/gles3/subsurface_scattering/quality",PropertyInfo(Variant::INT,"rendering/gles3/subsurface_scattering/quality",PROPERTY_HINT_ENUM,"Low,Medium,High"));
+		GLOBAL_DEF("rendering/gles3/subsurface_scattering/max_size",1.0);
+		Globals::get_singleton()->set_custom_property_info("rendering/gles3/subsurface_scattering/max_size",PropertyInfo(Variant::INT,"rendering/gles3/subsurface_scattering/max_size",PROPERTY_HINT_RANGE,"0.01,8,0.01"));
+		GLOBAL_DEF("rendering/gles3/subsurface_scattering/follow_surface",false);
+	}
+
 }
 }
 
 
 void RasterizerSceneGLES3::iteration() {
 void RasterizerSceneGLES3::iteration() {
 
 
 	shadow_filter_mode=ShadowFilterMode(int(Globals::get_singleton()->get("rendering/gles3/shadow_filter_mode")));
 	shadow_filter_mode=ShadowFilterMode(int(Globals::get_singleton()->get("rendering/gles3/shadow_filter_mode")));
+	subsurface_scatter_follow_surface=Globals::get_singleton()->get("rendering/gles3/subsurface_scattering/follow_surface");
+	subsurface_scatter_quality=SubSurfaceScatterQuality(int(Globals::get_singleton()->get("rendering/gles3/subsurface_scattering/quality")));
+	subsurface_scatter_size=Globals::get_singleton()->get("rendering/gles3/subsurface_scattering/max_size");
 }
 }
 
 
 void RasterizerSceneGLES3::finalize(){
 void RasterizerSceneGLES3::finalize(){

+ 12 - 0
drivers/gles3/rasterizer_scene_gles3.h

@@ -7,6 +7,7 @@
 #include "drivers/gles3/shaders/resolve.glsl.h"
 #include "drivers/gles3/shaders/resolve.glsl.h"
 #include "drivers/gles3/shaders/screen_space_reflection.glsl.h"
 #include "drivers/gles3/shaders/screen_space_reflection.glsl.h"
 #include "drivers/gles3/shaders/effect_blur.glsl.h"
 #include "drivers/gles3/shaders/effect_blur.glsl.h"
+#include "drivers/gles3/shaders/subsurf_scattering.glsl.h"
 
 
 class RasterizerSceneGLES3 : public RasterizerScene {
 class RasterizerSceneGLES3 : public RasterizerScene {
 public:
 public:
@@ -22,6 +23,15 @@ public:
 
 
 	uint64_t shadow_atlas_realloc_tolerance_msec;
 	uint64_t shadow_atlas_realloc_tolerance_msec;
 
 
+	enum SubSurfaceScatterQuality {
+		SSS_QUALITY_LOW,
+		SSS_QUALITY_MEDIUM,
+		SSS_QUALITY_HIGH,
+	};
+
+	SubSurfaceScatterQuality subsurface_scatter_quality;
+	float subsurface_scatter_size;
+	bool subsurface_scatter_follow_surface;
 
 
 	uint64_t render_pass;
 	uint64_t render_pass;
 	uint64_t scene_pass;
 	uint64_t scene_pass;
@@ -51,6 +61,7 @@ public:
 		ResolveShaderGLES3 resolve_shader;
 		ResolveShaderGLES3 resolve_shader;
 		ScreenSpaceReflectionShaderGLES3 ssr_shader;
 		ScreenSpaceReflectionShaderGLES3 ssr_shader;
 		EffectBlurShaderGLES3 effect_blur_shader;
 		EffectBlurShaderGLES3 effect_blur_shader;
+		SubsurfScatteringShaderGLES3 sss_shader;
 
 
 
 
 		struct SceneDataUBO {
 		struct SceneDataUBO {
@@ -118,6 +129,7 @@ public:
 		int reflection_probe_count;
 		int reflection_probe_count;
 
 
 		bool cull_front;
 		bool cull_front;
+		bool used_sss;
 
 
 	} state;
 	} state;
 
 

+ 17 - 4
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -1456,6 +1456,7 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
 			p_shader->spatial.uses_alpha=false;
 			p_shader->spatial.uses_alpha=false;
 			p_shader->spatial.unshaded=false;
 			p_shader->spatial.unshaded=false;
 			p_shader->spatial.ontop=false;
 			p_shader->spatial.ontop=false;
+			p_shader->spatial.uses_sss=false;
 
 
 			shaders.actions_scene.render_mode_values["blend_add"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_ADD);
 			shaders.actions_scene.render_mode_values["blend_add"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_ADD);
 			shaders.actions_scene.render_mode_values["blend_mix"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_MIX);
 			shaders.actions_scene.render_mode_values["blend_mix"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_MIX);
@@ -1477,6 +1478,8 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
 			shaders.actions_scene.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha;
 			shaders.actions_scene.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha;
 			shaders.actions_scene.usage_flag_pointers["VERTEX"]=&p_shader->spatial.uses_vertex;
 			shaders.actions_scene.usage_flag_pointers["VERTEX"]=&p_shader->spatial.uses_vertex;
 
 
+			shaders.actions_scene.usage_flag_pointers["SSS_STRENGTH"]=&p_shader->spatial.uses_sss;
+
 			actions=&shaders.actions_scene;
 			actions=&shaders.actions_scene;
 			actions->uniforms=&p_shader->uniforms;
 			actions->uniforms=&p_shader->uniforms;
 
 
@@ -4771,7 +4774,8 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) {
 		glDeleteFramebuffers(1,&rt->buffers.alpha_fbo);
 		glDeleteFramebuffers(1,&rt->buffers.alpha_fbo);
 		glDeleteTextures(1,&rt->buffers.diffuse);
 		glDeleteTextures(1,&rt->buffers.diffuse);
 		glDeleteTextures(1,&rt->buffers.specular);
 		glDeleteTextures(1,&rt->buffers.specular);
-		glDeleteTextures(1,&rt->buffers.normal_sr);
+		glDeleteTextures(1,&rt->buffers.normal_rough);
+		glDeleteTextures(1,&rt->buffers.motion_sss);
 		rt->buffers.fbo=0;
 		rt->buffers.fbo=0;
 		rt->buffers.alpha_fbo=0;
 		rt->buffers.alpha_fbo=0;
 	}
 	}
@@ -4923,14 +4927,23 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt){
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt->buffers.specular, 0);
 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt->buffers.specular, 0);
 
 
-		glGenTextures(1, &rt->buffers.normal_sr);
-		glBindTexture(GL_TEXTURE_2D, rt->buffers.normal_sr);
+		glGenTextures(1, &rt->buffers.normal_rough);
+		glBindTexture(GL_TEXTURE_2D, rt->buffers.normal_rough);
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, rt->buffers.normal_sr, 0);
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, rt->buffers.normal_rough, 0);
+
+		glGenTextures(1, &rt->buffers.motion_sss);
+		glBindTexture(GL_TEXTURE_2D, rt->buffers.motion_sss);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI,  rt->width, rt->height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, rt->buffers.motion_sss, 0);
 
 
 
 
 		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

+ 3 - 2
drivers/gles3/rasterizer_storage_gles3.h

@@ -369,6 +369,7 @@ public:
 			bool ontop;
 			bool ontop;
 			bool uses_vertex;
 			bool uses_vertex;
 			bool uses_discard;
 			bool uses_discard;
+			bool uses_sss;
 
 
 		} spatial;
 		} spatial;
 
 
@@ -886,8 +887,8 @@ public:
 			GLuint alpha_fbo; //single buffer, just diffuse (for alpha pass)
 			GLuint alpha_fbo; //single buffer, just diffuse (for alpha pass)
 			GLuint specular;
 			GLuint specular;
 			GLuint diffuse;
 			GLuint diffuse;
-			GLuint normal_sr;
-			GLuint temporal;
+			GLuint normal_rough;
+			GLuint motion_sss;
 		} buffers;
 		} buffers;
 
 
 		struct Effects {
 		struct Effects {

+ 9 - 2
drivers/gles3/shader_compiler_gles3.cpp

@@ -422,9 +422,9 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 				used_name_defines.insert(vnode->name);
 				used_name_defines.insert(vnode->name);
 			}
 			}
 
 
-			if (p_actions.usage_flag_pointers.has(vnode->name) && !used_name_defines.has(vnode->name)) {
+			if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) {
 				*p_actions.usage_flag_pointers[vnode->name]=true;
 				*p_actions.usage_flag_pointers[vnode->name]=true;
-				used_name_defines.insert(vnode->name);
+				used_flag_pointers.insert(vnode->name);
 			}
 			}
 
 
 			if (p_default_actions.renames.has(vnode->name))
 			if (p_default_actions.renames.has(vnode->name))
@@ -670,6 +670,8 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
 	actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"]="clearcoat_gloss";
 	actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"]="clearcoat_gloss";
 	actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"]="anisotropy";
 	actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"]="anisotropy";
 	actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"]="anisotropy_flow";
 	actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"]="anisotropy_flow";
+	actions[VS::SHADER_SPATIAL].renames["SSS_SPREAD"]="sss_spread";
+	actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"]="sss_strength";
 	actions[VS::SHADER_SPATIAL].renames["AO"]="ao";
 	actions[VS::SHADER_SPATIAL].renames["AO"]="ao";
 	actions[VS::SHADER_SPATIAL].renames["EMISSION"]="emission";
 	actions[VS::SHADER_SPATIAL].renames["EMISSION"]="emission";
 	actions[VS::SHADER_SPATIAL].renames["DISCARD"]="_discard";
 	actions[VS::SHADER_SPATIAL].renames["DISCARD"]="_discard";
@@ -692,6 +694,11 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
 	actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"]="@NORMALMAP";
 	actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"]="@NORMALMAP";
 	actions[VS::SHADER_SPATIAL].usage_defines["COLOR"]="#define ENABLE_COLOR_INTERP\n";
 	actions[VS::SHADER_SPATIAL].usage_defines["COLOR"]="#define ENABLE_COLOR_INTERP\n";
 
 
+	actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"]="#define ENABLE_SSS_MOTION\n";
+
+	actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"]="sss_strength";
+
+
 	actions[VS::SHADER_SPATIAL].render_mode_defines["skip_transform"]="#define SKIP_TRANSFORM_USED\n";
 	actions[VS::SHADER_SPATIAL].render_mode_defines["skip_transform"]="#define SKIP_TRANSFORM_USED\n";
 
 
 
 

+ 1 - 0
drivers/gles3/shader_compiler_gles3.h

@@ -58,6 +58,7 @@ private:
 	StringName time_name;
 	StringName time_name;
 
 
 	Set<StringName> used_name_defines;
 	Set<StringName> used_name_defines;
+	Set<StringName> used_flag_pointers;
 	Set<StringName> used_rmode_defines;
 	Set<StringName> used_rmode_defines;
 	Set<StringName> internal_functions;
 	Set<StringName> internal_functions;
 
 

+ 2 - 0
drivers/gles3/shaders/SCsub

@@ -11,4 +11,6 @@ if env['BUILDERS'].has_key('GLES3_GLSL'):
 	env.GLES3_GLSL('blend_shape.glsl');
 	env.GLES3_GLSL('blend_shape.glsl');
 	env.GLES3_GLSL('screen_space_reflection.glsl');
 	env.GLES3_GLSL('screen_space_reflection.glsl');
 	env.GLES3_GLSL('effect_blur.glsl');
 	env.GLES3_GLSL('effect_blur.glsl');
+	env.GLES3_GLSL('subsurf_scattering.glsl');
+
 
 

+ 4 - 8
drivers/gles3/shaders/resolve.glsl

@@ -17,11 +17,8 @@ void main() {
 
 
 
 
 in vec2 uv_interp;
 in vec2 uv_interp;
-uniform sampler2D source_diffuse; //texunit:0
-uniform sampler2D source_specular; //texunit:1
-
-
-uniform sampler2D source_ssr_ssao; //texunit:2
+uniform sampler2D source_specular; //texunit:0
+uniform sampler2D source_ssr; //texunit:1
 
 
 uniform float stuff;
 uniform float stuff;
 
 
@@ -31,15 +28,14 @@ layout(location = 0) out vec4 frag_color;
 
 
 void main() {
 void main() {
 
 
-	vec4 diffuse = texture( source_diffuse,  uv_interp );
 	vec4 specular = texture( source_specular,  uv_interp );
 	vec4 specular = texture( source_specular,  uv_interp );
 
 
 #ifdef USE_SSR
 #ifdef USE_SSR
 
 
-	vec4 ssr = textureLod(source_ssr_ssao,uv_interp,0.0);
+	vec4 ssr = textureLod(source_ssr,uv_interp,0.0);
 	specular.rgb = mix(specular.rgb,ssr.rgb*specular.a,ssr.a);
 	specular.rgb = mix(specular.rgb,ssr.rgb*specular.a,ssr.a);
 #endif
 #endif
 
 
-	frag_color = vec4(diffuse.rgb,1.0)+vec4(specular.rgb,1.0);
+	frag_color = vec4(specular.rgb,1.0);
 }
 }
 
 

+ 42 - 0
drivers/gles3/shaders/scene.glsl

@@ -75,6 +75,7 @@ layout(std140) uniform SceneData { //ubo:0
 	vec2 directional_shadow_pixel_size;
 	vec2 directional_shadow_pixel_size;
 
 
 	float reflection_multiplier;
 	float reflection_multiplier;
+	float subsurface_scatter_width;
 
 
 };
 };
 
 
@@ -385,6 +386,7 @@ layout(std140) uniform SceneData {
 	vec2 directional_shadow_pixel_size;
 	vec2 directional_shadow_pixel_size;
 
 
 	float reflection_multiplier;
 	float reflection_multiplier;
+	float subsurface_scatter_width;
 
 
 };
 };
 
 
@@ -479,6 +481,9 @@ uniform int reflection_count;
 layout(location=0) out vec4 diffuse_buffer;
 layout(location=0) out vec4 diffuse_buffer;
 layout(location=1) out vec4 specular_buffer;
 layout(location=1) out vec4 specular_buffer;
 layout(location=2) out vec4 normal_mr_buffer;
 layout(location=2) out vec4 normal_mr_buffer;
+#if defined (ENABLE_SSS_MOTION)
+layout(location=3) out uint motion_ssr_buffer;
+#endif
 
 
 #else
 #else
 
 
@@ -621,6 +626,35 @@ in highp float dp_clip;
 
 
 #endif
 #endif
 
 
+#if 0
+//need to save texture depth for this
+
+vec3 light_transmittance(float translucency,vec3 light_vec, vec3 normal, vec3 pos, float distance) {
+
+	float scale = 8.25 * (1.0 - translucency) / subsurface_scatter_width;
+	float d = scale * distance;
+
+    /**
+     * Armed with the thickness, we can now calculate the color by means of the
+     * precalculated transmittance profile.
+     * (It can be precomputed into a texture, for maximum performance):
+     */
+	float dd = -d * d;
+	vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
+		     vec3(0.1,   0.336, 0.344) * exp(dd / 0.0484) +
+		     vec3(0.118, 0.198, 0.0)   * exp(dd / 0.187)  +
+		     vec3(0.113, 0.007, 0.007) * exp(dd / 0.567)  +
+		     vec3(0.358, 0.004, 0.0)   * exp(dd / 1.99)   +
+		     vec3(0.078, 0.0,   0.0)   * exp(dd / 7.41);
+
+    /**
+     * Using the profile, we finally approximate the transmitted lighting from
+     * the back of the object:
+     */
+    return profile * clamp(0.3 + dot(light_vec, normal),0.0,1.0);
+}
+#endif
+
 void light_process_omni(int idx, vec3 vertex, vec3 eye_vec,vec3 normal,vec3 binormal, vec3 tangent, vec3 albedo, vec3 specular, float roughness, float rim, float rim_tint, float clearcoat, float clearcoat_gloss,float anisotropy,inout vec3 diffuse_light, inout vec3 specular_light) {
 void light_process_omni(int idx, vec3 vertex, vec3 eye_vec,vec3 normal,vec3 binormal, vec3 tangent, vec3 albedo, vec3 specular, float roughness, float rim, float rim_tint, float clearcoat, float clearcoat_gloss,float anisotropy,inout vec3 diffuse_light, inout vec3 specular_light) {
 
 
 	vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex;
 	vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex;
@@ -870,6 +904,10 @@ void main() {
 	bool discard_=false;
 	bool discard_=false;
 #endif
 #endif
 
 
+#if defined (ENABLE_SSS_MOTION)
+	float sss_strength=0.0;
+#endif
+
 {
 {
 
 
 
 
@@ -1194,6 +1232,10 @@ LIGHT_SHADER_CODE
 
 
 	normal_mr_buffer=vec4(normalize(normal)*0.5+0.5,roughness);
 	normal_mr_buffer=vec4(normalize(normal)*0.5+0.5,roughness);
 
 
+#if defined (ENABLE_SSS_MOTION)
+	motion_ssr_buffer = uint(clamp(sqrt(sss_strength)*255.0,0.0,255))<<24;
+#endif
+
 #else
 #else
 
 
 
 

+ 1 - 6
drivers/gles3/shaders/screen_space_reflection.glsl

@@ -23,7 +23,6 @@ in vec2 pos_interp;
 uniform sampler2D source_diffuse; //texunit:0
 uniform sampler2D source_diffuse; //texunit:0
 uniform sampler2D source_normal_roughness; //texunit:1
 uniform sampler2D source_normal_roughness; //texunit:1
 uniform sampler2D source_depth; //texunit:2
 uniform sampler2D source_depth; //texunit:2
-uniform sampler2D source_diffuse_mipmaps; //texunit:3
 
 
 uniform float camera_z_near;
 uniform float camera_z_near;
 uniform float camera_z_far;
 uniform float camera_z_far;
@@ -295,11 +294,7 @@ void main() {
 
 
 				vec4 sample_color;
 				vec4 sample_color;
 				{
 				{
-					sample_color = textureLod(source_diffuse_mipmaps,sample_pos,max(1.0,mipmap));
-					if (mipmap<1.0) { //we use another image as base to avoid copying all the screen unnecesarily
-						vec4 base_sample_color = textureLod(source_diffuse,sample_pos,0.0);
-						sample_color = mix(base_sample_color,sample_color,mipmap);
-					}
+					sample_color = textureLod(source_diffuse,sample_pos,mipmap);
 				}
 				}
 
 
 				//multiply by gloss
 				//multiply by gloss

+ 172 - 0
drivers/gles3/shaders/subsurf_scattering.glsl

@@ -0,0 +1,172 @@
+[vertex]
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=4) in vec2 uv_in;
+
+out vec2 uv_interp;
+
+
+void main() {
+
+	uv_interp = uv_in;
+	gl_Position = vertex_attrib;
+}
+
+[fragment]
+
+//#define QUALIFIER uniform // some guy on the interweb says it may be faster with this
+#define QUALIFIER const
+
+#ifdef USE_25_SAMPLES
+
+const int kernel_size=25;
+QUALIFIER vec4 kernel[25] = vec4[] (
+    vec4(0.530605, 0.613514, 0.739601, 0.0),
+    vec4(0.000973794, 1.11862e-005, 9.43437e-007, -3.0),
+    vec4(0.00333804, 7.85443e-005, 1.2945e-005, -2.52083),
+    vec4(0.00500364, 0.00020094, 5.28848e-005, -2.08333),
+    vec4(0.00700976, 0.00049366, 0.000151938, -1.6875),
+    vec4(0.0094389, 0.00139119, 0.000416598, -1.33333),
+    vec4(0.0128496, 0.00356329, 0.00132016, -1.02083),
+    vec4(0.017924, 0.00711691, 0.00347194, -0.75),
+    vec4(0.0263642, 0.0119715, 0.00684598, -0.520833),
+    vec4(0.0410172, 0.0199899, 0.0118481, -0.333333),
+    vec4(0.0493588, 0.0367726, 0.0219485, -0.1875),
+    vec4(0.0402784, 0.0657244, 0.04631, -0.0833333),
+    vec4(0.0211412, 0.0459286, 0.0378196, -0.0208333),
+    vec4(0.0211412, 0.0459286, 0.0378196, 0.0208333),
+    vec4(0.0402784, 0.0657244, 0.04631, 0.0833333),
+    vec4(0.0493588, 0.0367726, 0.0219485, 0.1875),
+    vec4(0.0410172, 0.0199899, 0.0118481, 0.333333),
+    vec4(0.0263642, 0.0119715, 0.00684598, 0.520833),
+    vec4(0.017924, 0.00711691, 0.00347194, 0.75),
+    vec4(0.0128496, 0.00356329, 0.00132016, 1.02083),
+    vec4(0.0094389, 0.00139119, 0.000416598, 1.33333),
+    vec4(0.00700976, 0.00049366, 0.000151938, 1.6875),
+    vec4(0.00500364, 0.00020094, 5.28848e-005, 2.08333),
+    vec4(0.00333804, 7.85443e-005, 1.2945e-005, 2.52083),
+    vec4(0.000973794, 1.11862e-005, 9.43437e-007, 3.0)
+);
+
+#endif //USE_25_SAMPLES
+
+#ifdef USE_17_SAMPLES
+
+const int kernel_size=17;
+
+QUALIFIER vec4 kernel[17] = vec4[](
+    vec4(0.536343, 0.624624, 0.748867, 0.0),
+    vec4(0.00317394, 0.000134823, 3.77269e-005, -2.0),
+    vec4(0.0100386, 0.000914679, 0.000275702, -1.53125),
+    vec4(0.0144609, 0.00317269, 0.00106399, -1.125),
+    vec4(0.0216301, 0.00794618, 0.00376991, -0.78125),
+    vec4(0.0347317, 0.0151085, 0.00871983, -0.5),
+    vec4(0.0571056, 0.0287432, 0.0172844, -0.28125),
+    vec4(0.0582416, 0.0659959, 0.0411329, -0.125),
+    vec4(0.0324462, 0.0656718, 0.0532821, -0.03125),
+    vec4(0.0324462, 0.0656718, 0.0532821, 0.03125),
+    vec4(0.0582416, 0.0659959, 0.0411329, 0.125),
+    vec4(0.0571056, 0.0287432, 0.0172844, 0.28125),
+    vec4(0.0347317, 0.0151085, 0.00871983, 0.5),
+    vec4(0.0216301, 0.00794618, 0.00376991, 0.78125),
+    vec4(0.0144609, 0.00317269, 0.00106399, 1.125),
+    vec4(0.0100386, 0.000914679, 0.000275702, 1.53125),
+    vec4(0.00317394, 0.000134823, 3.77269e-005, 2.0)
+);
+
+#endif //USE_17_SAMPLES
+
+
+#ifdef USE_11_SAMPLES
+
+const int kernel_size=11;
+
+QUALIFIER vec4 kernel[11] = vec4[](
+    vec4(0.560479, 0.669086, 0.784728, 0.0),
+    vec4(0.00471691, 0.000184771, 5.07566e-005, -2.0),
+    vec4(0.0192831, 0.00282018, 0.00084214, -1.28),
+    vec4(0.03639, 0.0130999, 0.00643685, -0.72),
+    vec4(0.0821904, 0.0358608, 0.0209261, -0.32),
+    vec4(0.0771802, 0.113491, 0.0793803, -0.08),
+    vec4(0.0771802, 0.113491, 0.0793803, 0.08),
+    vec4(0.0821904, 0.0358608, 0.0209261, 0.32),
+    vec4(0.03639, 0.0130999, 0.00643685, 0.72),
+    vec4(0.0192831, 0.00282018, 0.00084214, 1.28),
+    vec4(0.00471691, 0.000184771, 5.07565e-005, 2.0)
+);
+
+#endif //USE_11_SAMPLES
+
+
+uniform float max_radius;
+uniform float fovy;
+uniform float camera_z_far;
+uniform float camera_z_near;
+uniform vec2 dir;
+in vec2 uv_interp;
+
+uniform sampler2D source_diffuse; //texunit:0
+uniform highp usampler2D source_motion_ss; //texunit:1
+uniform sampler2D source_depth; //texunit:2
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+
+	float strength = float(texture(source_motion_ss,uv_interp).r>>24)*(1.0/255.0);
+	strength*=strength; //stored as sqrt
+
+	// Fetch color of current pixel:
+	vec4 base_color = texture(source_diffuse, uv_interp);
+
+	if (strength>0.0) {
+
+
+		// Fetch linear depth of current pixel:
+		float depth = texture(source_depth, uv_interp).r * 2.0 - 1.0;
+		depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
+		depth=-depth;
+
+
+		// Calculate the radius scale (1.0 for a unit plane sitting on the
+		// projection window):
+		float distance = 1.0 / tan(0.5 * fovy);
+		float scale = distance / -depth; //remember depth is negative by default in OpenGL
+
+		// Calculate the final step to fetch the surrounding pixels:
+		vec2 step = max_radius * scale * dir;
+		step *= strength; // Modulate it using the alpha channel.
+		step *= 1.0 / 3.0; // Divide by 3 as the kernels range from -3 to 3.
+
+		// Accumulate the center sample:
+		vec3 color_accum = base_color.rgb;
+		color_accum *= kernel[0].rgb;
+
+		// Accumulate the other samples:
+		for (int i = 1; i < kernel_size; i++) {
+			// Fetch color and depth for current sample:
+			vec2 offset = uv_interp + kernel[i].a * step;
+			vec3 color = texture(source_diffuse, offset).rgb;
+
+#ifdef ENABLE_FOLLOW_SURFACE
+			// If the difference in depth is huge, we lerp color back to "colorM":
+			float depth_cmp = texture(source_depth, offset).r *2.0 - 1.0;
+			depth_cmp = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth_cmp * (camera_z_far - camera_z_near));
+			depth_cmp=-depth_cmp;
+
+			float s = clamp(300.0f * distance *
+					       max_radius * abs(depth - depth_cmp),0.0,1.0);
+			color = mix(color, base_color.rgb, s);
+#endif
+
+			// Accumulate:
+			color_accum += kernel[i].rgb * color;
+		}
+
+		frag_color = vec4(color_accum,base_color.a); //keep alpha (used for SSAO)
+	} else {
+		frag_color = base_color;
+	}
+}
+

+ 1 - 1
scene/3d/light.cpp

@@ -218,7 +218,7 @@ void Light::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "light/cull_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_cull_mask"), _SCS("get_cull_mask"));
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "light/cull_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_cull_mask"), _SCS("get_cull_mask"));
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow"));
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow"));
 	ADD_PROPERTY( PropertyInfo( Variant::COLOR, "shadow/color",PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_shadow_color"), _SCS("get_shadow_color"));
 	ADD_PROPERTY( PropertyInfo( Variant::COLOR, "shadow/color",PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_shadow_color"), _SCS("get_shadow_color"));
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias",PROPERTY_HINT_RANGE,"0,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS);
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias",PROPERTY_HINT_RANGE,"-16,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS);
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/max_distance",PROPERTY_HINT_RANGE,"0,65536,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_MAX_DISTANCE);
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/max_distance",PROPERTY_HINT_RANGE,"0,65536,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_MAX_DISTANCE);
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editor/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only"));
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editor/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only"));
 
 

+ 26 - 11
scene/resources/material.cpp

@@ -72,7 +72,7 @@ void FixedSpatialMaterial::init_shaders() {
 	shader_names->clearcoat_gloss="clearcoat_gloss";
 	shader_names->clearcoat_gloss="clearcoat_gloss";
 	shader_names->anisotropy="anisotropy_ratio";
 	shader_names->anisotropy="anisotropy_ratio";
 	shader_names->height_scale="height_scale";
 	shader_names->height_scale="height_scale";
-	shader_names->subsurface_scattering="subsurface_scattering";
+	shader_names->subsurface_scattering_strength="subsurface_scattering_strength";
 	shader_names->refraction="refraction";
 	shader_names->refraction="refraction";
 	shader_names->refraction_roughness="refraction_roughness";
 	shader_names->refraction_roughness="refraction_roughness";
 	shader_names->point_size="point_size";
 	shader_names->point_size="point_size";
@@ -217,6 +217,14 @@ void FixedSpatialMaterial::_update_shader() {
 		code+="uniform sampler2D texture_detail_mask : hint_white;\n";
 		code+="uniform sampler2D texture_detail_mask : hint_white;\n";
 	}
 	}
 
 
+	if (features[FEATURE_SUBSURACE_SCATTERING]) {
+
+		code+="uniform float subsurface_scattering_strength : hint_range(0,1);\n";
+		code+="uniform sampler2D texture_subsurface_scattering : hint_white;\n";
+
+	}
+
+
 	code+="\n\n";
 	code+="\n\n";
 
 
 	code+="void vertex() {\n";
 	code+="void vertex() {\n";
@@ -230,7 +238,7 @@ void FixedSpatialMaterial::_update_shader() {
 		code+="\tPOINT_SIZE=point_size;\n";
 		code+="\tPOINT_SIZE=point_size;\n";
 	}
 	}
 	code+="\tUV=UV*uv1_scale+uv1_offset;\n";
 	code+="\tUV=UV*uv1_scale+uv1_offset;\n";
-	if (detail_blend_mode==DETAIL_UV_2) {
+	if (detail_uv==DETAIL_UV_2) {
 		code+="\tUV2=UV2*uv2_scale+uv2_offset;\n";
 		code+="\tUV2=UV2*uv2_scale+uv2_offset;\n";
 	}
 	}
 
 
@@ -284,6 +292,12 @@ void FixedSpatialMaterial::_update_shader() {
 		code+="\tAO = texture(texture_ambient_occlusion,UV).r;\n";
 		code+="\tAO = texture(texture_ambient_occlusion,UV).r;\n";
 	}
 	}
 
 
+	if (features[FEATURE_SUBSURACE_SCATTERING]) {
+
+		code+="\tfloat sss_tex = texture(texture_subsurface_scattering,UV).r;\n";
+		code+="\tSSS_STRENGTH=subsurface_scattering_strength*sss_tex;\n";
+	}
+
 	if (features[FEATURE_DETAIL]) {
 	if (features[FEATURE_DETAIL]) {
 		String det_uv=detail_uv==DETAIL_UV_1?"UV":"UV2";
 		String det_uv=detail_uv==DETAIL_UV_1?"UV":"UV2";
 		code+="\tvec4 detail_tex = texture(texture_detail_albedo,"+det_uv+");\n";
 		code+="\tvec4 detail_tex = texture(texture_detail_albedo,"+det_uv+");\n";
@@ -512,17 +526,18 @@ float FixedSpatialMaterial::get_height_scale() const{
 	return height_scale;
 	return height_scale;
 }
 }
 
 
-void FixedSpatialMaterial::set_subsurface_scattering(float p_subsurface_scattering){
 
 
-	subsurface_scattering=p_subsurface_scattering;
-	VS::get_singleton()->material_set_param(_get_material(),shader_names->subsurface_scattering,subsurface_scattering);
+void FixedSpatialMaterial::set_subsurface_scattering_strength(float p_subsurface_scattering_strength){
+
+	subsurface_scattering_strength=p_subsurface_scattering_strength;
+	VS::get_singleton()->material_set_param(_get_material(),shader_names->subsurface_scattering_strength,subsurface_scattering_strength);
 
 
 
 
 }
 }
 
 
-float FixedSpatialMaterial::get_subsurface_scattering() const{
+float FixedSpatialMaterial::get_subsurface_scattering_strength() const{
 
 
-	return subsurface_scattering;
+	return subsurface_scattering_strength;
 }
 }
 
 
 void FixedSpatialMaterial::set_refraction(float p_refraction){
 void FixedSpatialMaterial::set_refraction(float p_refraction){
@@ -806,8 +821,8 @@ void FixedSpatialMaterial::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_height_scale","height_scale"),&FixedSpatialMaterial::set_height_scale);
 	ObjectTypeDB::bind_method(_MD("set_height_scale","height_scale"),&FixedSpatialMaterial::set_height_scale);
 	ObjectTypeDB::bind_method(_MD("get_height_scale"),&FixedSpatialMaterial::get_height_scale);
 	ObjectTypeDB::bind_method(_MD("get_height_scale"),&FixedSpatialMaterial::get_height_scale);
 
 
-	ObjectTypeDB::bind_method(_MD("set_subsurface_scattering","subsurface_scattering"),&FixedSpatialMaterial::set_subsurface_scattering);
-	ObjectTypeDB::bind_method(_MD("get_subsurface_scattering"),&FixedSpatialMaterial::get_subsurface_scattering);
+	ObjectTypeDB::bind_method(_MD("set_subsurface_scattering_strength","strength"),&FixedSpatialMaterial::set_subsurface_scattering_strength);
+	ObjectTypeDB::bind_method(_MD("get_subsurface_scattering_strength"),&FixedSpatialMaterial::get_subsurface_scattering_strength);
 
 
 	ObjectTypeDB::bind_method(_MD("set_refraction","refraction"),&FixedSpatialMaterial::set_refraction);
 	ObjectTypeDB::bind_method(_MD("set_refraction","refraction"),&FixedSpatialMaterial::set_refraction);
 	ObjectTypeDB::bind_method(_MD("get_refraction"),&FixedSpatialMaterial::get_refraction);
 	ObjectTypeDB::bind_method(_MD("get_refraction"),&FixedSpatialMaterial::get_refraction);
@@ -912,7 +927,7 @@ void FixedSpatialMaterial::_bind_methods() {
 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"height/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_HEIGHT);
 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"height/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_HEIGHT);
 
 
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"subsurf_scatter/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_SUBSURACE_SCATTERING);
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"subsurf_scatter/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_SUBSURACE_SCATTERING);
-	ADD_PROPERTY(PropertyInfo(Variant::REAL,"subsurf_scatter/amount",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_subsurface_scattering"),_SCS("get_subsurface_scattering"));
+	ADD_PROPERTY(PropertyInfo(Variant::REAL,"subsurf_scatter/strength",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_subsurface_scattering_strength"),_SCS("get_subsurface_scattering_strength"));
 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"subsurf_scatter/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_SUBSURFACE_SCATTERING);
 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"subsurf_scatter/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_SUBSURFACE_SCATTERING);
 
 
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"refraction/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_REFRACTION);
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"refraction/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_REFRACTION);
@@ -1011,7 +1026,7 @@ FixedSpatialMaterial::FixedSpatialMaterial() : element(this) {
 	set_clearcoat_gloss(0.5);
 	set_clearcoat_gloss(0.5);
 	set_anisotropy(0);
 	set_anisotropy(0);
 	set_height_scale(1);
 	set_height_scale(1);
-	set_subsurface_scattering(0);
+	set_subsurface_scattering_strength(0);
 	set_refraction(0);
 	set_refraction(0);
 	set_refraction_roughness(0);
 	set_refraction_roughness(0);
 	set_line_width(1);
 	set_line_width(1);

+ 4 - 4
scene/resources/material.h

@@ -213,7 +213,7 @@ private:
 		StringName clearcoat_gloss;
 		StringName clearcoat_gloss;
 		StringName anisotropy;
 		StringName anisotropy;
 		StringName height_scale;
 		StringName height_scale;
-		StringName subsurface_scattering;
+		StringName subsurface_scattering_strength;
 		StringName refraction;
 		StringName refraction;
 		StringName refraction_roughness;
 		StringName refraction_roughness;
 		StringName point_size;
 		StringName point_size;
@@ -247,7 +247,7 @@ private:
 	float clearcoat_gloss;
 	float clearcoat_gloss;
 	float anisotropy;
 	float anisotropy;
 	float height_scale;
 	float height_scale;
-	float subsurface_scattering;
+	float subsurface_scattering_strength;
 	float refraction;
 	float refraction;
 	float refraction_roughness;
 	float refraction_roughness;
 	float line_width;
 	float line_width;
@@ -318,8 +318,8 @@ public:
 	void set_height_scale(float p_height_scale);
 	void set_height_scale(float p_height_scale);
 	float get_height_scale() const;
 	float get_height_scale() const;
 
 
-	void set_subsurface_scattering(float p_subsurface_scattering);
-	float get_subsurface_scattering() const;
+	void set_subsurface_scattering_strength(float p_strength);
+	float get_subsurface_scattering_strength() const;
 
 
 	void set_refraction(float p_refraction);
 	void set_refraction(float p_refraction);
 	float get_refraction() const;
 	float get_refraction() const;

+ 1 - 0
servers/visual/shader_types.cpp

@@ -66,6 +66,7 @@ ShaderTypes::ShaderTypes()
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["CLEARCOAT_GLOSS"]=ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["CLEARCOAT_GLOSS"]=ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ANISOTROPY"]=ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ANISOTROPY"]=ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ANISOTROPY_FLOW"]=ShaderLanguage::TYPE_VEC2;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ANISOTROPY_FLOW"]=ShaderLanguage::TYPE_VEC2;
+	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SSS_STRENGTH"]=ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["AO"]=ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["AO"]=ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["EMISSION"]=ShaderLanguage::TYPE_VEC3;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["EMISSION"]=ShaderLanguage::TYPE_VEC3;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SPECIAL"]=ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SPECIAL"]=ShaderLanguage::TYPE_FLOAT;

+ 1 - 1
servers/visual/visual_server_scene.cpp

@@ -1555,7 +1555,7 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,const
 			float angle = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_SPOT_ANGLE);
 			float angle = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_SPOT_ANGLE);
 
 
 			CameraMatrix cm;
 			CameraMatrix cm;
-			cm.set_perspective( angle, 1.0, 0.01, radius );
+			cm.set_perspective( angle*2.0, 1.0, 0.01, radius );
 
 
 
 
 			Vector<Plane> planes = cm.get_projection_planes(p_instance->transform);
 			Vector<Plane> planes = cm.get_projection_planes(p_instance->transform);

+ 1 - 0
servers/visual_server.h

@@ -556,6 +556,7 @@ public:
 	virtual void environment_set_adjustment(RID p_env,bool p_enable,float p_brightness,float p_contrast,float p_saturation,RID p_ramp)=0;
 	virtual void environment_set_adjustment(RID p_env,bool p_enable,float p_brightness,float p_contrast,float p_saturation,RID p_ramp)=0;
 
 
 	virtual void environment_set_ssr(RID p_env,bool p_enable, int p_max_steps,float p_accel,float p_fade,float p_depth_tolerance,bool p_smooth,bool p_roughness)=0;
 	virtual void environment_set_ssr(RID p_env,bool p_enable, int p_max_steps,float p_accel,float p_fade,float p_depth_tolerance,bool p_smooth,bool p_roughness)=0;
+
 	/* SCENARIO API */
 	/* SCENARIO API */