summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2016-12-02 22:23:16 -0300
committerJuan Linietsky <reduzio@gmail.com>2016-12-02 22:23:16 -0300
commit27a46d78ec43b69a70a1d84c540353e3cb3b04c0 (patch)
treedc4fc077c325b26d6f7a159419fe4ca55bc29783
parent8c6a586b75692eaa67ddaf4bb73edf325cc60e5d (diff)
Subsurface scattering material param is now working!
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp91
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h12
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp21
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h5
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp11
-rw-r--r--drivers/gles3/shader_compiler_gles3.h1
-rw-r--r--drivers/gles3/shaders/SCsub2
-rw-r--r--drivers/gles3/shaders/resolve.glsl12
-rw-r--r--drivers/gles3/shaders/scene.glsl42
-rw-r--r--drivers/gles3/shaders/screen_space_reflection.glsl7
-rw-r--r--drivers/gles3/shaders/subsurf_scattering.glsl172
-rw-r--r--scene/3d/light.cpp2
-rw-r--r--scene/resources/material.cpp37
-rw-r--r--scene/resources/material.h8
-rw-r--r--servers/visual/shader_types.cpp1
-rw-r--r--servers/visual/visual_server_scene.cpp2
-rw-r--r--servers/visual_server.h1
17 files changed, 378 insertions, 49 deletions
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 16784246f6..c4c7d4409d 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1809,6 +1809,10 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g
mirror=!mirror;
}
+ if (m->shader->spatial.uses_sss) {
+ state.used_sss=true;
+ }
+
if (p_shadow) {
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();
if (!e)
@@ -2620,6 +2625,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_
current_geometry_index=0;
current_material_index=0;
+ state.used_sss=false;
//fill list
@@ -2683,6 +2689,50 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env,const CameraMatrix &p_c
glDisable(GL_CULL_FACE);
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) {
//blur diffuse into effect mipmaps using separatable convolution
//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::LOD,float(i));
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);
_copy_screen();
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);
glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse);
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);
glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->depth);
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.bind();
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);
if (env->ssr_enabled) {
- glActiveTexture(GL_TEXTURE2);
+ glActiveTexture(GL_TEXTURE1);
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->fbo);
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_ONE,GL_ONE); //use additive to accumulate one over the other
+
_copy_screen();
+ glDisable(GL_BLEND); //end additive
+
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::SIMPLE_COPY,true);
state.effect_blur_shader.bind();
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;
+
_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_ATTACHMENT1);
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());
Color black(0,0,0,0);
glClearBufferfv(GL_COLOR,1,black.components); // specular
glClearBufferfv(GL_COLOR,2,black.components); // normal metal rough
+ if (state.used_sss) {
+ glClearBufferfv(GL_COLOR,3,black.components); // normal metal rough
+ }
} else {
@@ -3968,11 +4025,25 @@ void RasterizerSceneGLES3::initialize() {
state.resolve_shader.init();
state.ssr_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() {
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(){
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 0b934085ed..21711292a0 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -7,6 +7,7 @@
#include "drivers/gles3/shaders/resolve.glsl.h"
#include "drivers/gles3/shaders/screen_space_reflection.glsl.h"
#include "drivers/gles3/shaders/effect_blur.glsl.h"
+#include "drivers/gles3/shaders/subsurf_scattering.glsl.h"
class RasterizerSceneGLES3 : public RasterizerScene {
public:
@@ -22,6 +23,15 @@ public:
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 scene_pass;
@@ -51,6 +61,7 @@ public:
ResolveShaderGLES3 resolve_shader;
ScreenSpaceReflectionShaderGLES3 ssr_shader;
EffectBlurShaderGLES3 effect_blur_shader;
+ SubsurfScatteringShaderGLES3 sss_shader;
struct SceneDataUBO {
@@ -118,6 +129,7 @@ public:
int reflection_probe_count;
bool cull_front;
+ bool used_sss;
} state;
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 01668e728c..7b9a3f2af1 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/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.unshaded=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_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["VERTEX"]=&p_shader->spatial.uses_vertex;
+ shaders.actions_scene.usage_flag_pointers["SSS_STRENGTH"]=&p_shader->spatial.uses_sss;
+
actions=&shaders.actions_scene;
actions->uniforms=&p_shader->uniforms;
@@ -4771,7 +4774,8 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) {
glDeleteFramebuffers(1,&rt->buffers.alpha_fbo);
glDeleteTextures(1,&rt->buffers.diffuse);
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.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);
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);
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_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);
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 1eba8b42c9..e6b89eb66c 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -369,6 +369,7 @@ public:
bool ontop;
bool uses_vertex;
bool uses_discard;
+ bool uses_sss;
} spatial;
@@ -886,8 +887,8 @@ public:
GLuint alpha_fbo; //single buffer, just diffuse (for alpha pass)
GLuint specular;
GLuint diffuse;
- GLuint normal_sr;
- GLuint temporal;
+ GLuint normal_rough;
+ GLuint motion_sss;
} buffers;
struct Effects {
diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp
index c54fc011e9..5c7a72ab17 100644
--- a/drivers/gles3/shader_compiler_gles3.cpp
+++ b/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);
}
- 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;
- used_name_defines.insert(vnode->name);
+ used_flag_pointers.insert(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["ANISOTROPY"]="anisotropy";
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["EMISSION"]="emission";
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["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";
diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h
index 3549526808..1beee66ad7 100644
--- a/drivers/gles3/shader_compiler_gles3.h
+++ b/drivers/gles3/shader_compiler_gles3.h
@@ -58,6 +58,7 @@ private:
StringName time_name;
Set<StringName> used_name_defines;
+ Set<StringName> used_flag_pointers;
Set<StringName> used_rmode_defines;
Set<StringName> internal_functions;
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index 66a19eefd1..b5797e78b8 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -11,4 +11,6 @@ if env['BUILDERS'].has_key('GLES3_GLSL'):
env.GLES3_GLSL('blend_shape.glsl');
env.GLES3_GLSL('screen_space_reflection.glsl');
env.GLES3_GLSL('effect_blur.glsl');
+ env.GLES3_GLSL('subsurf_scattering.glsl');
+
diff --git a/drivers/gles3/shaders/resolve.glsl b/drivers/gles3/shaders/resolve.glsl
index 4ca6297303..6acc712299 100644
--- a/drivers/gles3/shaders/resolve.glsl
+++ b/drivers/gles3/shaders/resolve.glsl
@@ -17,11 +17,8 @@ void main() {
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;
@@ -31,15 +28,14 @@ layout(location = 0) out vec4 frag_color;
void main() {
- vec4 diffuse = texture( source_diffuse, uv_interp );
vec4 specular = texture( source_specular, uv_interp );
#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);
#endif
- frag_color = vec4(diffuse.rgb,1.0)+vec4(specular.rgb,1.0);
+ frag_color = vec4(specular.rgb,1.0);
}
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 192042192e..230544c1c3 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -75,6 +75,7 @@ layout(std140) uniform SceneData { //ubo:0
vec2 directional_shadow_pixel_size;
float reflection_multiplier;
+ float subsurface_scatter_width;
};
@@ -385,6 +386,7 @@ layout(std140) uniform SceneData {
vec2 directional_shadow_pixel_size;
float reflection_multiplier;
+ float subsurface_scatter_width;
};
@@ -479,6 +481,9 @@ uniform int reflection_count;
layout(location=0) out vec4 diffuse_buffer;
layout(location=1) out vec4 specular_buffer;
layout(location=2) out vec4 normal_mr_buffer;
+#if defined (ENABLE_SSS_MOTION)
+layout(location=3) out uint motion_ssr_buffer;
+#endif
#else
@@ -621,6 +626,35 @@ in highp float dp_clip;
#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) {
vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex;
@@ -870,6 +904,10 @@ void main() {
bool discard_=false;
#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);
+#if defined (ENABLE_SSS_MOTION)
+ motion_ssr_buffer = uint(clamp(sqrt(sss_strength)*255.0,0.0,255))<<24;
+#endif
+
#else
diff --git a/drivers/gles3/shaders/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl
index 5b24013c07..ec4bdf86c9 100644
--- a/drivers/gles3/shaders/screen_space_reflection.glsl
+++ b/drivers/gles3/shaders/screen_space_reflection.glsl
@@ -23,7 +23,6 @@ in vec2 pos_interp;
uniform sampler2D source_diffuse; //texunit:0
uniform sampler2D source_normal_roughness; //texunit:1
uniform sampler2D source_depth; //texunit:2
-uniform sampler2D source_diffuse_mipmaps; //texunit:3
uniform float camera_z_near;
uniform float camera_z_far;
@@ -295,11 +294,7 @@ void main() {
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
diff --git a/drivers/gles3/shaders/subsurf_scattering.glsl b/drivers/gles3/shaders/subsurf_scattering.glsl
new file mode 100644
index 0000000000..89e618b66c
--- /dev/null
+++ b/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;
+ }
+}
+
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 49bffd3c21..7177e21e1e 100644
--- a/scene/3d/light.cpp
+++ b/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::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_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_PROPERTY( PropertyInfo( Variant::BOOL, "editor/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only"));
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 99b7a130f7..70afd68113 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -72,7 +72,7 @@ void FixedSpatialMaterial::init_shaders() {
shader_names->clearcoat_gloss="clearcoat_gloss";
shader_names->anisotropy="anisotropy_ratio";
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_roughness="refraction_roughness";
shader_names->point_size="point_size";
@@ -217,6 +217,14 @@ void FixedSpatialMaterial::_update_shader() {
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+="void vertex() {\n";
@@ -230,7 +238,7 @@ void FixedSpatialMaterial::_update_shader() {
code+="\tPOINT_SIZE=point_size;\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";
}
@@ -284,6 +292,12 @@ void FixedSpatialMaterial::_update_shader() {
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]) {
String det_uv=detail_uv==DETAIL_UV_1?"UV":"UV2";
code+="\tvec4 detail_tex = texture(texture_detail_albedo,"+det_uv+");\n";
@@ -512,17 +526,18 @@ float FixedSpatialMaterial::get_height_scale() const{
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){
@@ -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("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("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::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::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_anisotropy(0);
set_height_scale(1);
- set_subsurface_scattering(0);
+ set_subsurface_scattering_strength(0);
set_refraction(0);
set_refraction_roughness(0);
set_line_width(1);
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 15c5910a9c..9b80b67691 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -213,7 +213,7 @@ private:
StringName clearcoat_gloss;
StringName anisotropy;
StringName height_scale;
- StringName subsurface_scattering;
+ StringName subsurface_scattering_strength;
StringName refraction;
StringName refraction_roughness;
StringName point_size;
@@ -247,7 +247,7 @@ private:
float clearcoat_gloss;
float anisotropy;
float height_scale;
- float subsurface_scattering;
+ float subsurface_scattering_strength;
float refraction;
float refraction_roughness;
float line_width;
@@ -318,8 +318,8 @@ public:
void set_height_scale(float p_height_scale);
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);
float get_refraction() const;
diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp
index f799329026..4872135e2a 100644
--- a/servers/visual/shader_types.cpp
+++ b/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"]["ANISOTROPY"]=ShaderLanguage::TYPE_FLOAT;
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"]["EMISSION"]=ShaderLanguage::TYPE_VEC3;
shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SPECIAL"]=ShaderLanguage::TYPE_FLOAT;
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
index 0f7dabcc12..6f7dac7f4d 100644
--- a/servers/visual/visual_server_scene.cpp
+++ b/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);
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);
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 4c9e04a782..9b1a9d81ac 100644
--- a/servers/visual_server.h
+++ b/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_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 */