diff options
Diffstat (limited to 'drivers/gles3/shaders')
-rw-r--r-- | drivers/gles3/shaders/SCsub | 22 | ||||
-rw-r--r-- | drivers/gles3/shaders/blend_shape.glsl | 197 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas.glsl | 456 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas_shadow.glsl | 49 | ||||
-rw-r--r-- | drivers/gles3/shaders/copy.glsl | 105 | ||||
-rw-r--r-- | drivers/gles3/shaders/cube_to_dp.glsl | 79 | ||||
-rw-r--r-- | drivers/gles3/shaders/cubemap_filter.glsl | 218 | ||||
-rw-r--r-- | drivers/gles3/shaders/effect_blur.glsl | 278 | ||||
-rw-r--r-- | drivers/gles3/shaders/exposure.glsl | 98 | ||||
-rw-r--r-- | drivers/gles3/shaders/particles.glsl | 167 | ||||
-rw-r--r-- | drivers/gles3/shaders/resolve.glsl | 41 | ||||
-rw-r--r-- | drivers/gles3/shaders/scene.glsl | 1432 | ||||
-rw-r--r-- | drivers/gles3/shaders/screen_space_reflection.glsl | 345 | ||||
-rw-r--r-- | drivers/gles3/shaders/ssao.glsl | 247 | ||||
-rw-r--r-- | drivers/gles3/shaders/ssao_blur.glsl | 113 | ||||
-rw-r--r-- | drivers/gles3/shaders/ssao_minify.glsl | 55 | ||||
-rw-r--r-- | drivers/gles3/shaders/subsurf_scattering.glsl | 172 | ||||
-rw-r--r-- | drivers/gles3/shaders/tonemap.glsl | 263 |
18 files changed, 4337 insertions, 0 deletions
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub new file mode 100644 index 0000000000..f9baeae97d --- /dev/null +++ b/drivers/gles3/shaders/SCsub @@ -0,0 +1,22 @@ +Import('env') + +if env['BUILDERS'].has_key('GLES3_GLSL'): + env.GLES3_GLSL('copy.glsl'); + env.GLES3_GLSL('resolve.glsl'); + env.GLES3_GLSL('canvas.glsl'); + env.GLES3_GLSL('canvas_shadow.glsl'); + env.GLES3_GLSL('scene.glsl'); + env.GLES3_GLSL('cubemap_filter.glsl'); + env.GLES3_GLSL('cube_to_dp.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'); + env.GLES3_GLSL('ssao.glsl'); + env.GLES3_GLSL('ssao_minify.glsl'); + env.GLES3_GLSL('ssao_blur.glsl'); + env.GLES3_GLSL('exposure.glsl'); + env.GLES3_GLSL('tonemap.glsl'); + env.GLES3_GLSL('particles.glsl'); + + diff --git a/drivers/gles3/shaders/blend_shape.glsl b/drivers/gles3/shaders/blend_shape.glsl new file mode 100644 index 0000000000..4e0d066823 --- /dev/null +++ b/drivers/gles3/shaders/blend_shape.glsl @@ -0,0 +1,197 @@ +[vertex] + + +/* +from VisualServer: + +ARRAY_VERTEX=0, +ARRAY_NORMAL=1, +ARRAY_TANGENT=2, +ARRAY_COLOR=3, +ARRAY_TEX_UV=4, +ARRAY_TEX_UV2=5, +ARRAY_BONES=6, +ARRAY_WEIGHTS=7, +ARRAY_INDEX=8, +*/ + +#ifdef USE_2D_VERTEX +#define VFORMAT vec2 +#else +#define VFORMAT vec3 +#endif + +/* INPUT ATTRIBS */ + +layout(location=0) in highp VFORMAT vertex_attrib; +layout(location=1) in vec3 normal_attrib; + +#ifdef ENABLE_TANGENT +layout(location=2) in vec4 tangent_attrib; +#endif + +#ifdef ENABLE_COLOR +layout(location=3) in vec4 color_attrib; +#endif + +#ifdef ENABLE_UV +layout(location=4) in vec2 uv_attrib; +#endif + +#ifdef ENABLE_UV2 +layout(location=5) in vec2 uv2_attrib; +#endif + +#ifdef ENABLE_SKELETON +layout(location=6) in ivec4 bone_attrib; +layout(location=7) in vec4 weight_attrib; +#endif + +/* BLEND ATTRIBS */ + +#ifdef ENABLE_BLEND + +layout(location=8) in highp VFORMAT vertex_attrib_blend; +layout(location=9) in vec3 normal_attrib_blend; + +#ifdef ENABLE_TANGENT +layout(location=10) in vec4 tangent_attrib_blend; +#endif + +#ifdef ENABLE_COLOR +layout(location=11) in vec4 color_attrib_blend; +#endif + +#ifdef ENABLE_UV +layout(location=12) in vec2 uv_attrib_blend; +#endif + +#ifdef ENABLE_UV2 +layout(location=13) in vec2 uv2_attrib_blend; +#endif + +#ifdef ENABLE_SKELETON +layout(location=14) in ivec4 bone_attrib_blend; +layout(location=15) in vec4 weight_attrib_blend; +#endif + +#endif + +/* OUTPUTS */ + +out VFORMAT vertex_out; //tfb: + +#ifdef ENABLE_NORMAL +out vec3 normal_out; //tfb:ENABLE_NORMAL +#endif + +#ifdef ENABLE_TANGENT +out vec4 tangent_out; //tfb:ENABLE_TANGENT +#endif + +#ifdef ENABLE_COLOR +out vec4 color_out; //tfb:ENABLE_COLOR +#endif + +#ifdef ENABLE_UV +out vec2 uv_out; //tfb:ENABLE_UV +#endif + +#ifdef ENABLE_UV2 +out vec2 uv2_out; //tfb:ENABLE_UV2 +#endif + +#ifdef ENABLE_SKELETON +out ivec4 bone_out; //tfb:ENABLE_SKELETON +out vec4 weight_out; //tfb:ENABLE_SKELETON +#endif + +uniform float blend_amount; + +void main() { + + +#ifdef ENABLE_BLEND + + vertex_out = vertex_attrib_blend + vertex_attrib * blend_amount; + +#ifdef ENABLE_NORMAL + normal_out = normal_attrib_blend + normal_attrib * blend_amount; +#endif + +#ifdef ENABLE_TANGENT + + tangent_out.xyz = tangent_attrib_blend.xyz + tangent_attrib.xyz * blend_amount; + tangent_out.w = tangent_attrib_blend.w; //just copy, no point in blending his +#endif + +#ifdef ENABLE_COLOR + + color_out = color_attrib_blend + color_attrib * blend_amount; +#endif + +#ifdef ENABLE_UV + + uv_out = uv_attrib_blend + uv_attrib * blend_amount; +#endif + +#ifdef ENABLE_UV2 + + uv2_out = uv2_attrib_blend + uv2_attrib * blend_amount; +#endif + + +#ifdef ENABLE_SKELETON + + bone_out = bone_attrib_blend; + weight_out = weight_attrib_blend + weight_attrib * blend_amount; +#endif + +#else //ENABLE_BLEND + + + vertex_out = vertex_attrib * blend_amount; + +#ifdef ENABLE_NORMAL + normal_out = normal_attrib * blend_amount; +#endif + +#ifdef ENABLE_TANGENT + + tangent_out.xyz = tangent_attrib.xyz * blend_amount; + tangent_out.w = tangent_attrib.w; //just copy, no point in blending his +#endif + +#ifdef ENABLE_COLOR + + color_out = color_attrib * blend_amount; +#endif + +#ifdef ENABLE_UV + + uv_out = uv_attrib * blend_amount; +#endif + +#ifdef ENABLE_UV2 + + uv2_out = uv2_attrib * blend_amount; +#endif + + +#ifdef ENABLE_SKELETON + + bone_out = bone_attrib; + weight_out = weight_attrib * blend_amount; +#endif + +#endif + gl_Position = vec4(0.0); +} + +[fragment] + + +void main() { + +} + diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl new file mode 100644 index 0000000000..cf2e0f776f --- /dev/null +++ b/drivers/gles3/shaders/canvas.glsl @@ -0,0 +1,456 @@ +[vertex] + + +layout(location=0) in highp vec2 vertex; +layout(location=3) in vec4 color_attrib; + +#ifdef USE_TEXTURE_RECT + +layout(location=1) in highp vec4 dst_rect; +layout(location=2) in highp vec4 src_rect; + +#else + +layout(location=4) in highp vec2 uv_attrib; + +//skeletn +#endif + + +layout(std140) uniform CanvasItemData { //ubo:0 + + highp mat4 projection_matrix; + highp vec4 time; +}; + +uniform highp mat4 modelview_matrix; +uniform highp mat4 extra_matrix; + + +out mediump vec2 uv_interp; +out mediump vec4 color_interp; + +#ifdef USE_LIGHTING + +layout(std140) uniform LightData { //ubo:1 + + //light matrices + highp mat4 light_matrix; + highp mat4 light_local_matrix; + highp mat4 shadow_matrix; + highp vec4 light_color; + highp vec4 light_shadow_color; + highp vec2 light_pos; + highp float shadowpixel_size; + highp float shadow_gradient; + highp float light_height; + highp float light_outside_alpha; + highp float shadow_distance_mult; +}; + + +out vec4 light_uv_interp; + +#if defined(NORMAL_USED) +out vec4 local_rot; +#endif + +#ifdef USE_SHADOWS +out highp vec2 pos; +#endif + +#endif + + +VERTEX_SHADER_GLOBALS + +#if defined(USE_MATERIAL) + +layout(std140) uniform UniformData { //ubo:2 + +MATERIAL_UNIFORMS + +}; + +#endif + +void main() { + + vec4 vertex_color = color_attrib; + + +#ifdef USE_TEXTURE_RECT + + + uv_interp = src_rect.xy + abs(src_rect.zw) * vertex; + highp vec4 outvec = vec4(dst_rect.xy + dst_rect.zw * mix(vertex,vec2(1.0,1.0)-vertex,lessThan(src_rect.zw,vec2(0.0,0.0))),0.0,1.0); + +#else + uv_interp = uv_attrib; + highp vec4 outvec = vec4(vertex,0.0,1.0); +#endif + + +{ + vec2 src_vtx=outvec.xy; + +VERTEX_SHADER_CODE + +} + +#if !defined(SKIP_TRANSFORM_USED) + outvec = extra_matrix * outvec; + outvec = modelview_matrix * outvec; +#endif + + color_interp = vertex_color; + +#ifdef USE_PIXEL_SNAP + + outvec.xy=floor(outvec+0.5); +#endif + + + gl_Position = projection_matrix * outvec; + +#ifdef USE_LIGHTING + + light_uv_interp.xy = (light_matrix * outvec).xy; + light_uv_interp.zw =(light_local_matrix * outvec).xy; +#ifdef USE_SHADOWS + pos=outvec.xy; +#endif + +#if defined(NORMAL_USED) + local_rot.xy=normalize( (modelview_matrix * ( extra_matrix * vec4(1.0,0.0,0.0,0.0) )).xy ); + local_rot.zw=normalize( (modelview_matrix * ( extra_matrix * vec4(0.0,1.0,0.0,0.0) )).xy ); +#ifdef USE_TEXTURE_RECT + local_rot.xy*=sign(src_rect.z); + local_rot.zw*=sign(src_rect.w); +#endif + +#endif + +#endif + +} + +[fragment] + + + +uniform mediump sampler2D color_texture; // texunit:0 +uniform highp vec2 color_texpixel_size; + +in mediump vec2 uv_interp; +in mediump vec4 color_interp; + + +#if defined(SCREEN_TEXTURE_USED) + +uniform sampler2D screen_texture; // texunit:-3 + +#endif + +layout(std140) uniform CanvasItemData { + + highp mat4 projection_matrix; + highp vec4 time; +}; + + +#ifdef USE_LIGHTING + +layout(std140) uniform LightData { + + highp mat4 light_matrix; + highp mat4 light_local_matrix; + highp mat4 shadow_matrix; + highp vec4 light_color; + highp vec4 light_shadow_color; + highp vec2 light_pos; + highp float shadowpixel_size; + highp float shadow_gradient; + highp float light_height; + highp float light_outside_alpha; + highp float shadow_distance_mult; +}; + +uniform lowp sampler2D light_texture; // texunit:-1 +in vec4 light_uv_interp; + + +#if defined(NORMAL_USED) +in vec4 local_rot; +#endif + +#ifdef USE_SHADOWS + +uniform highp sampler2D shadow_texture; // texunit:-2 +in highp vec2 pos; + +#endif + +#endif + +uniform mediump vec4 final_modulate; + +FRAGMENT_SHADER_GLOBALS + + +layout(location=0) out mediump vec4 frag_color; + + +#if defined(USE_MATERIAL) + +layout(std140) uniform UniformData { + +MATERIAL_UNIFORMS + +}; + +#endif + +void main() { + + vec4 color = color_interp; +#if defined(NORMAL_USED) + vec3 normal = vec3(0.0,0.0,1.0); +#endif + +#if !defined(COLOR_USED) +//default behavior, texture by color + +#ifdef USE_DISTANCE_FIELD + const float smoothing = 1.0/32.0; + float distance = texture(color_texture, uv_interp).a; + color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance) * color.a; +#else + color *= texture( color_texture, uv_interp ); + +#endif + +#endif + +#if defined(ENABLE_SCREEN_UV) + vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult; +#endif + + +{ + float normal_depth=1.0; + +#if defined(NORMALMAP_USED) + vec3 normal_map=vec3(0.0,0.0,1.0); +#endif + +FRAGMENT_SHADER_CODE + +#if defined(NORMALMAP_USED) + normal = mix(vec3(0.0,0.0,1.0), normal_map * vec3(2.0,-2.0,1.0) - vec3( 1.0, -1.0, 0.0 ), normal_depth ); +#endif + +} +#ifdef DEBUG_ENCODED_32 + highp float enc32 = dot( color,highp vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) ); + color = vec4(vec3(enc32),1.0); +#endif + + + color*=final_modulate; + + + + +#ifdef USE_LIGHTING + + vec2 light_vec = light_uv_interp.zw;; //for shadow and normal mapping + +#if defined(NORMAL_USED) + normal.xy = mat2(local_rot.xy,local_rot.zw) * normal.xy; +#endif + + float att=1.0; + + vec2 light_uv = light_uv_interp.xy; + vec4 light = texture(light_texture,light_uv) * light_color; +#if defined(SHADOW_COLOR_USED) + vec4 shadow_color=vec4(0.0,0.0,0.0,0.0); +#endif + + if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) { + color.a*=light_outside_alpha; //invisible + + } else { + +#if defined(USE_LIGHT_SHADER_CODE) +//light is written by the light shader + { + vec4 light_out=light*color; +LIGHT_SHADER_CODE + color=light_out; + } + +#else + +#if defined(NORMAL_USED) + vec3 light_normal = normalize(vec3(light_vec,-light_height)); + light*=max(dot(-light_normal,normal),0.0); +#endif + + color*=light; +/* +#ifdef USE_NORMAL + color.xy=local_rot.xy;//normal.xy; + color.zw=vec2(0.0,1.0); +#endif +*/ + +//light shader code +#endif + + +#ifdef USE_SHADOWS + + float angle_to_light = -atan(light_vec.x,light_vec.y); + float PI = 3.14159265358979323846264; + /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays + float ang*/ + + float su,sz; + + float abs_angle = abs(angle_to_light); + vec2 point; + float sh; + if (abs_angle<45.0*PI/180.0) { + point = light_vec; + sh=0.0+(1.0/8.0); + } else if (abs_angle>135.0*PI/180.0) { + point = -light_vec; + sh = 0.5+(1.0/8.0); + } else if (angle_to_light>0.0) { + + point = vec2(light_vec.y,-light_vec.x); + sh = 0.25+(1.0/8.0); + } else { + + point = vec2(-light_vec.y,light_vec.x); + sh = 0.75+(1.0/8.0); + + } + + + highp vec4 s = shadow_matrix * vec4(point,0.0,1.0); + s.xyz/=s.w; + su=s.x*0.5+0.5; + sz=s.z*0.5+0.5; + //sz=lightlength(light_vec); + + highp float shadow_attenuation=0.0; + +#ifdef USE_RGBA_SHADOWS + +#define SHADOW_DEPTH(m_tex,m_uv) dot(texture2D((m_tex),(m_uv)),vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) ) + +#else + +#define SHADOW_DEPTH(m_tex,m_uv) (texture2D((m_tex),(m_uv)).r) + +#endif + + + +#ifdef SHADOW_USE_GRADIENT + +#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture,vec2(m_ofs,sh)); shadow_attenuation+=1.0-smoothstep(sd,sd+shadow_gradient,sz); } + +#else + +#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture,vec2(m_ofs,sh)); shadow_attenuation+=step(sz,sd); } + +#endif + + +#ifdef SHADOW_FILTER_NEAREST + + SHADOW_TEST(su+shadowpixel_size); + +#endif + + +#ifdef SHADOW_FILTER_PCF3 + + SHADOW_TEST(su+shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su-shadowpixel_size); + shadow_attenuation/=3.0; + +#endif + + +#ifdef SHADOW_FILTER_PCF5 + + SHADOW_TEST(su+shadowpixel_size*3.0); + SHADOW_TEST(su+shadowpixel_size*2.0); + SHADOW_TEST(su+shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su-shadowpixel_size); + SHADOW_TEST(su-shadowpixel_size*2.0); + SHADOW_TEST(su-shadowpixel_size*3.0); + shadow_attenuation/=5.0; + +#endif + + +#ifdef SHADOW_FILTER_PCF9 + + SHADOW_TEST(su+shadowpixel_size*4.0); + SHADOW_TEST(su+shadowpixel_size*3.0); + SHADOW_TEST(su+shadowpixel_size*2.0); + SHADOW_TEST(su+shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su-shadowpixel_size); + SHADOW_TEST(su-shadowpixel_size*2.0); + SHADOW_TEST(su-shadowpixel_size*3.0); + SHADOW_TEST(su-shadowpixel_size*4.0); + shadow_attenuation/=9.0; + +#endif + +#ifdef SHADOW_FILTER_PCF13 + + SHADOW_TEST(su+shadowpixel_size*6.0); + SHADOW_TEST(su+shadowpixel_size*5.0); + SHADOW_TEST(su+shadowpixel_size*4.0); + SHADOW_TEST(su+shadowpixel_size*3.0); + SHADOW_TEST(su+shadowpixel_size*2.0); + SHADOW_TEST(su+shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su-shadowpixel_size); + SHADOW_TEST(su-shadowpixel_size*2.0); + SHADOW_TEST(su-shadowpixel_size*3.0); + SHADOW_TEST(su-shadowpixel_size*4.0); + SHADOW_TEST(su-shadowpixel_size*5.0); + SHADOW_TEST(su-shadowpixel_size*6.0); + shadow_attenuation/=13.0; + +#endif + + +#if defined(SHADOW_COLOR_USED) + color=mix(shadow_color,color,shadow_attenuation); +#else + //color*=shadow_attenuation; + color=mix(light_shadow_color,color,shadow_attenuation); +#endif +//use shadows +#endif + } + +//use lighting +#endif +// color.rgb*=color.a; + frag_color = color; + +} + diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl new file mode 100644 index 0000000000..c757990de0 --- /dev/null +++ b/drivers/gles3/shaders/canvas_shadow.glsl @@ -0,0 +1,49 @@ +[vertex] + + + +uniform highp mat4 projection_matrix; +uniform highp mat4 light_matrix; +uniform highp mat4 world_matrix; +uniform highp float distance_norm; + +layout(location=0) in highp vec3 vertex; + +out highp vec4 position_interp; + +void main() { + + gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex,1.0))); + position_interp=gl_Position; +} + +[fragment] + +in highp vec4 position_interp; + +#ifdef USE_RGBA_SHADOWS + +layout(location=0) out lowp vec4 distance_buf; + +#else + +layout(location=0) out highp float distance_buf; + +#endif + +void main() { + + highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias; + +#ifdef USE_RGBA_SHADOWS + + highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); + comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); + distance_buf=comp; +#else + + distance_buf=depth; + +#endif +} + diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl new file mode 100644 index 0000000000..a87d62f2d7 --- /dev/null +++ b/drivers/gles3/shaders/copy.glsl @@ -0,0 +1,105 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; +#ifdef USE_CUBEMAP +layout(location=4) in vec3 cube_in; +#else +layout(location=4) in vec2 uv_in; +#endif +layout(location=5) in vec2 uv2_in; + +#ifdef USE_CUBEMAP +out vec3 cube_interp; +#else +out vec2 uv_interp; +#endif + +out vec2 uv2_interp; + +void main() { + +#ifdef USE_CUBEMAP + cube_interp = cube_in; +#else + uv_interp = uv_in; +#endif + uv2_interp = uv2_in; + gl_Position = vertex_attrib; +} + +[fragment] + + +#ifdef USE_CUBEMAP +in vec3 cube_interp; +uniform samplerCube source_cube; //texunit:0 +#else +in vec2 uv_interp; +uniform sampler2D source; //texunit:0 +#endif + + +float sRGB_gamma_correct(float c){ + float a = 0.055; + if(c < 0.0031308) + return 12.92*c; + else + return (1.0+a)*pow(c, 1.0/2.4) - a; +} + + +uniform float stuff; +uniform vec2 pixel_size; + +in vec2 uv2_interp; + +layout(location = 0) out vec4 frag_color; + +void main() { + + //vec4 color = color_interp; + +#ifdef USE_CUBEMAP + vec4 color = texture( source_cube, normalize(cube_interp) ); + +#else + vec4 color = texture( source, uv_interp ); +#endif + +#ifdef LINEAR_TO_SRGB + //regular Linear -> SRGB conversion + vec3 a = vec3(0.055); + color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308))); +#endif + +#ifdef DEBUG_GRADIENT + color.rg=uv_interp; + color.b=0.0; +#endif + +#ifdef DISABLE_ALPHA + color.a=1.0; +#endif + + +#ifdef GAUSSIAN_HORIZONTAL + color*=0.38774; + color+=texture( source, uv_interp+vec2( 1.0, 0.0)*pixel_size )*0.24477; + color+=texture( source, uv_interp+vec2( 2.0, 0.0)*pixel_size )*0.06136; + color+=texture( source, uv_interp+vec2(-1.0, 0.0)*pixel_size )*0.24477; + color+=texture( source, uv_interp+vec2(-2.0, 0.0)*pixel_size )*0.06136; +#endif + +#ifdef GAUSSIAN_VERTICAL + color*=0.38774; + color+=texture( source, uv_interp+vec2( 0.0, 1.0)*pixel_size )*0.24477; + color+=texture( source, uv_interp+vec2( 0.0, 2.0)*pixel_size )*0.06136; + color+=texture( source, uv_interp+vec2( 0.0,-1.0)*pixel_size )*0.24477; + color+=texture( source, uv_interp+vec2( 0.0,-2.0)*pixel_size )*0.06136; +#endif + + + frag_color = color; +} + diff --git a/drivers/gles3/shaders/cube_to_dp.glsl b/drivers/gles3/shaders/cube_to_dp.glsl new file mode 100644 index 0000000000..5ffc78c0b9 --- /dev/null +++ b/drivers/gles3/shaders/cube_to_dp.glsl @@ -0,0 +1,79 @@ +[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] + + +uniform highp samplerCube source_cube; //texunit:0 +in vec2 uv_interp; + +uniform bool z_flip; +uniform highp float z_far; +uniform highp float z_near; +uniform highp float bias; + +void main() { + + highp vec3 normal = vec3( uv_interp * 2.0 - 1.0, 0.0 ); +/* + if(z_flip) { + normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y)); + } else { + normal.z = -0.5 + 0.5*((normal.x * normal.x) + (normal.y * normal.y)); + } +*/ + + //normal.z = sqrt(1.0-dot(normal.xy,normal.xy)); + //normal.xy*=1.0+normal.z; + + normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y)); + normal = normalize(normal); + +/* + normal.z=0.5; + normal=normalize(normal); +*/ + if (!z_flip) { + normal.z=-normal.z; + } + + //normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 )); + float depth = texture(source_cube,normal).r; + + // absolute values for direction cosines, bigger value equals closer to basis axis + vec3 unorm = abs(normal); + + if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) { + // x code + unorm = normal.x > 0.0 ? vec3( 1.0, 0.0, 0.0 ) : vec3( -1.0, 0.0, 0.0 ) ; + } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) { + // y code + unorm = normal.y > 0.0 ? vec3( 0.0, 1.0, 0.0 ) : vec3( 0.0, -1.0, 0.0 ) ; + } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) { + // z code + unorm = normal.z > 0.0 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 0.0, 0.0, -1.0 ) ; + } else { + // oh-no we messed up code + // has to be + unorm = vec3( 1.0, 0.0, 0.0 ); + } + + float depth_fix = 1.0 / dot(normal,unorm); + + + depth = 2.0 * depth - 1.0; + float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near)); + gl_FragDepth = (linear_depth*depth_fix+bias) / z_far; +} + diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl new file mode 100644 index 0000000000..768d20ad22 --- /dev/null +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -0,0 +1,218 @@ +[vertex] + + +layout(location=0) in highp vec2 vertex; + +layout(location=4) in highp vec2 uv; + +out highp vec2 uv_interp; + +void main() { + + uv_interp=uv; + gl_Position=vec4(vertex,0,1); +} + +[fragment] + + +precision highp float; +precision highp int; + + +uniform samplerCube source_cube; //texunit:0 +uniform int face_id; +uniform float roughness; +in highp vec2 uv_interp; + + +layout(location = 0) out vec4 frag_color; + + +#define M_PI 3.14159265359 + + +vec3 texelCoordToVec(vec2 uv, int faceID) +{ + mat3 faceUvVectors[6]; +/* + // -x + faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z + faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face + + // +x + faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z + faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face + + // -y + faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z + faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face + + // +y + faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z + faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face + + // -z + faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x + faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face + + // +z + faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face +*/ + + // -x + faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z + faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face + + // +x + faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z + faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face + + // -y + faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z + faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face + + // +y + faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z + faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face + + // -z + faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x + faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face + + // +z + faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face + + // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. + vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2]; + return normalize(result); +} + +vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) +{ + float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph] + + // Compute distribution direction + float Phi = 2.0 * M_PI * Xi.x; + float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + float SinTheta = sqrt(1.0 - CosTheta * CosTheta); + + // Convert to spherical direction + vec3 H; + H.x = SinTheta * cos(Phi); + H.y = SinTheta * sin(Phi); + H.z = CosTheta; + + vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 TangentX = normalize(cross(UpVector, N)); + vec3 TangentY = cross(N, TangentX); + + // Tangent to world space + return TangentX * H.x + TangentY * H.y + N * H.z; +} + +// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +float GGX(float NdotV, float a) +{ + float k = a / 2.0; + return NdotV / (NdotV * (1.0 - k) + k); +} + +// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +float G_Smith(float a, float nDotV, float nDotL) +{ + return GGX(nDotL, a * a) * GGX(nDotV, a * a); +} + +float radicalInverse_VdC(uint bits) { + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 Hammersley(uint i, uint N) { + return vec2(float(i)/float(N), radicalInverse_VdC(i)); +} + + + +#ifdef LOW_QUALITY + +#define SAMPLE_COUNT 64u + +#else + +#define SAMPLE_COUNT 512u + +#endif + +uniform bool z_flip; + +void main() { + +#ifdef USE_DUAL_PARABOLOID + + vec3 N = vec3( uv_interp * 2.0 - 1.0, 0.0 ); + N.z = 0.5 - 0.5*((N.x * N.x) + (N.y * N.y)); + N = normalize(N); + + if (!z_flip) { + N.y=-N.y; //y is flipped to improve blending between both sides + } else { + N.z=-N.z; + } + + +#else + vec2 uv = (uv_interp * 2.0) - 1.0; + vec3 N = texelCoordToVec(uv, face_id); +#endif + //vec4 color = color_interp; + +#ifdef USE_DIRECT_WRITE + + frag_color=vec4(texture(N,source_cube).rgb,1.0); + +#else + + vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); + + for(uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) { + vec2 xi = Hammersley(sampleNum, SAMPLE_COUNT); + + vec3 H = ImportanceSampleGGX( xi, roughness, N ); + vec3 V = N; + vec3 L = normalize(2.0 * dot( V, H ) * H - V); + + float ndotl = clamp(dot(N, L),0.0,1.0); + + if (ndotl>0.0) { + sum.rgb += textureLod(source_cube, H, 0.0).rgb *ndotl; + sum.a += ndotl; + } + } + sum /= sum.a; + + frag_color = vec4(sum.rgb, 1.0); + +#endif + +} + diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl new file mode 100644 index 0000000000..89afa12f60 --- /dev/null +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -0,0 +1,278 @@ +[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] + + +in vec2 uv_interp; +uniform sampler2D source_color; //texunit:0 + +#ifdef SSAO_MERGE +uniform sampler2D source_ssao; //texunit:1 +#endif + +uniform float lod; +uniform vec2 pixel_size; + + +layout(location = 0) out vec4 frag_color; + +#ifdef SSAO_MERGE + +uniform vec4 ssao_color; + +#endif + +#if defined (GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL) + +uniform float glow_strength; + +#endif + +#if defined(DOF_FAR_BLUR) || defined (DOF_NEAR_BLUR) + +#ifdef DOF_QUALITY_LOW +const int dof_kernel_size=5; +const int dof_kernel_from=2; +const float dof_kernel[5] = float[] (0.153388,0.221461,0.250301,0.221461,0.153388); +#endif + +#ifdef DOF_QUALITY_MEDIUM +const int dof_kernel_size=11; +const int dof_kernel_from=5; +const float dof_kernel[11] = float[] (0.055037,0.072806,0.090506,0.105726,0.116061,0.119726,0.116061,0.105726,0.090506,0.072806,0.055037); + +#endif + +#ifdef DOF_QUALITY_HIGH +const int dof_kernel_size=21; +const int dof_kernel_from=10; +const float dof_kernel[21] = float[] (0.028174,0.032676,0.037311,0.041944,0.046421,0.050582,0.054261,0.057307,0.059587,0.060998,0.061476,0.060998,0.059587,0.057307,0.054261,0.050582,0.046421,0.041944,0.037311,0.032676,0.028174); +#endif + +uniform sampler2D dof_source_depth; //texunit:1 +uniform float dof_begin; +uniform float dof_end; +uniform vec2 dof_dir; +uniform float dof_radius; + +#ifdef DOF_NEAR_BLUR_MERGE + +uniform sampler2D source_dof_original; //texunit:2 +#endif + +#endif + + +#ifdef GLOW_FIRST_PASS + +uniform float exposure; +uniform float white; + +#ifdef GLOW_USE_AUTO_EXPOSURE + +uniform highp sampler2D source_auto_exposure; //texunit:1 +uniform highp float auto_exposure_grey; + +#endif + +uniform float glow_bloom; +uniform float glow_hdr_treshold; +uniform float glow_hdr_scale; + +#endif + +uniform float camera_z_far; +uniform float camera_z_near; + +void main() { + + + +#ifdef GAUSSIAN_HORIZONTAL + vec2 pix_size = pixel_size; + pix_size*=0.5; //reading from larger buffer, so use more samples + vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pix_size,lod )*0.214607; + color+=textureLod( source_color, uv_interp+vec2( 1.0, 0.0)*pix_size,lod )*0.189879; + color+=textureLod( source_color, uv_interp+vec2( 2.0, 0.0)*pix_size,lod )*0.157305; + color+=textureLod( source_color, uv_interp+vec2( 3.0, 0.0)*pix_size,lod )*0.071303; + color+=textureLod( source_color, uv_interp+vec2(-1.0, 0.0)*pix_size,lod )*0.189879; + color+=textureLod( source_color, uv_interp+vec2(-2.0, 0.0)*pix_size,lod )*0.157305; + color+=textureLod( source_color, uv_interp+vec2(-3.0, 0.0)*pix_size,lod )*0.071303; + frag_color = color; +#endif + +#ifdef GAUSSIAN_VERTICAL + vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pixel_size,lod )*0.38774; + color+=textureLod( source_color, uv_interp+vec2( 0.0, 1.0)*pixel_size,lod )*0.24477; + color+=textureLod( source_color, uv_interp+vec2( 0.0, 2.0)*pixel_size,lod )*0.06136; + color+=textureLod( source_color, uv_interp+vec2( 0.0,-1.0)*pixel_size,lod )*0.24477; + color+=textureLod( source_color, uv_interp+vec2( 0.0,-2.0)*pixel_size,lod )*0.06136; + frag_color = color; +#endif + +//glow uses larger sigma for a more rounded blur effect + +#ifdef GLOW_GAUSSIAN_HORIZONTAL + vec2 pix_size = pixel_size; + pix_size*=0.5; //reading from larger buffer, so use more samples + vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pix_size,lod )*0.174938; + color+=textureLod( source_color, uv_interp+vec2( 1.0, 0.0)*pix_size,lod )*0.165569; + color+=textureLod( source_color, uv_interp+vec2( 2.0, 0.0)*pix_size,lod )*0.140367; + color+=textureLod( source_color, uv_interp+vec2( 3.0, 0.0)*pix_size,lod )*0.106595; + color+=textureLod( source_color, uv_interp+vec2(-1.0, 0.0)*pix_size,lod )*0.165569; + color+=textureLod( source_color, uv_interp+vec2(-2.0, 0.0)*pix_size,lod )*0.140367; + color+=textureLod( source_color, uv_interp+vec2(-3.0, 0.0)*pix_size,lod )*0.106595; + color*=glow_strength; + frag_color = color; +#endif + +#ifdef GLOW_GAUSSIAN_VERTICAL + vec4 color =textureLod( source_color, uv_interp+vec2(0.0, 0.0)*pixel_size,lod )*0.288713; + color+=textureLod( source_color, uv_interp+vec2(0.0, 1.0)*pixel_size,lod )*0.233062; + color+=textureLod( source_color, uv_interp+vec2(0.0, 2.0)*pixel_size,lod )*0.122581; + color+=textureLod( source_color, uv_interp+vec2(0.0,-1.0)*pixel_size,lod )*0.233062; + color+=textureLod( source_color, uv_interp+vec2(0.0,-2.0)*pixel_size,lod )*0.122581; + color*=glow_strength; + frag_color = color; +#endif + +#ifdef DOF_FAR_BLUR + + vec4 color_accum = vec4(0.0); + + float depth = textureLod( dof_source_depth, uv_interp, 0.0).r; + depth = depth * 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)); + + float amount = smoothstep(dof_begin,dof_end,depth); + float k_accum=0.0; + + for(int i=0;i<dof_kernel_size;i++) { + + int int_ofs = i-dof_kernel_from; + vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius; + + float tap_k = dof_kernel[i]; + + float tap_depth = texture( dof_source_depth, tap_uv, 0.0).r; + tap_depth = tap_depth * 2.0 - 1.0; + tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); + + float tap_amount = mix(smoothstep(dof_begin,dof_end,tap_depth),1.0,int_ofs==0); + tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect + + vec4 tap_color = textureLod( source_color, tap_uv, 0.0) * tap_k; + + k_accum+=tap_k*tap_amount; + color_accum+=tap_color*tap_amount; + + + } + + if (k_accum>0.0) { + color_accum/=k_accum; + } + + frag_color = color_accum;///k_accum; + +#endif + +#ifdef DOF_NEAR_BLUR + + vec4 color_accum = vec4(0.0); + + float max_accum=0; + + for(int i=0;i<dof_kernel_size;i++) { + + int int_ofs = i-dof_kernel_from; + vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius; + float ofs_influence = max(0.0,1.0-float(abs(int_ofs))/float(dof_kernel_from)); + + float tap_k = dof_kernel[i]; + + vec4 tap_color = textureLod( source_color, tap_uv, 0.0); + + float tap_depth = texture( dof_source_depth, tap_uv, 0.0).r; + tap_depth = tap_depth * 2.0 - 1.0; + tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); + float tap_amount = 1.0-smoothstep(dof_end,dof_begin,tap_depth); + tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect + +#ifdef DOF_NEAR_FIRST_TAP + + tap_color.a= 1.0-smoothstep(dof_end,dof_begin,tap_depth); + +#endif + + max_accum=max(max_accum,tap_amount*ofs_influence); + + color_accum+=tap_color*tap_k; + + } + + color_accum.a=max(color_accum.a,sqrt(max_accum)); + + +#ifdef DOF_NEAR_BLUR_MERGE + + vec4 original = textureLod( source_dof_original, uv_interp, 0.0); + color_accum = mix(original,color_accum,color_accum.a); + +#endif + +#ifndef DOF_NEAR_FIRST_TAP + //color_accum=vec4(vec3(color_accum.a),1.0); +#endif + frag_color = color_accum; + +#endif + + + +#ifdef GLOW_FIRST_PASS + +#ifdef GLOW_USE_AUTO_EXPOSURE + + frag_color/=texelFetch(source_auto_exposure,ivec2(0,0),0).r/auto_exposure_grey; +#endif + frag_color*=exposure; + + float luminance = max(frag_color.r,max(frag_color.g,frag_color.b)); + float feedback = max( smoothstep(glow_hdr_treshold,glow_hdr_treshold+glow_hdr_scale,luminance), glow_bloom ); + + frag_color *= feedback; + +#endif + + +#ifdef SIMPLE_COPY + vec4 color =textureLod( source_color, uv_interp,0.0); + frag_color = color; +#endif + +#ifdef SSAO_MERGE + + vec4 color =textureLod( source_color, uv_interp,0.0); + float ssao =textureLod( source_ssao, uv_interp,0.0).r; + + frag_color = vec4( mix(color.rgb,color.rgb*mix(ssao_color.rgb,vec3(1.0),ssao),color.a), 1.0 ); + +#endif + + +} + diff --git a/drivers/gles3/shaders/exposure.glsl b/drivers/gles3/shaders/exposure.glsl new file mode 100644 index 0000000000..001b90a0f1 --- /dev/null +++ b/drivers/gles3/shaders/exposure.glsl @@ -0,0 +1,98 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; + + +void main() { + + gl_Position = vertex_attrib; + +} + +[fragment] + + +uniform highp sampler2D source_exposure; //texunit:0 + +#ifdef EXPOSURE_BEGIN + +uniform highp ivec2 source_render_size; +uniform highp ivec2 target_size; + +#endif + +#ifdef EXPOSURE_END + +uniform highp sampler2D prev_exposure; //texunit:1 +uniform highp float exposure_adjust; +uniform highp float min_luminance; +uniform highp float max_luminance; + +#endif + +layout(location = 0) out highp float exposure; + + + +void main() { + + + +#ifdef EXPOSURE_BEGIN + + + ivec2 src_pos = ivec2(gl_FragCoord.xy)*source_render_size/target_size; + +#if 1 + //more precise and expensive, but less jittery + ivec2 next_pos = ivec2(gl_FragCoord.xy+ivec2(1))*source_render_size/target_size; + next_pos = max(next_pos,src_pos+ivec2(1)); //so it at least reads one pixel + highp vec3 source_color=vec3(0.0); + for(int i=src_pos.x;i<next_pos.x;i++) { + for(int j=src_pos.y;j<next_pos.y;j++) { + source_color += texelFetch(source_exposure,ivec2(i,j),0).rgb; + } + } + + source_color/=float( (next_pos.x-src_pos.x)*(next_pos.y-src_pos.y) ); +#else + highp vec3 source_color = texelFetch(source_exposure,src_pos,0).rgb; + +#endif + + exposure = max(source_color.r,max(source_color.g,source_color.b)); + +#else + + ivec2 coord = ivec2(gl_FragCoord.xy); + exposure = texelFetch(source_exposure,coord*3+ivec2(0,0),0).r; + exposure += texelFetch(source_exposure,coord*3+ivec2(1,0),0).r; + exposure += texelFetch(source_exposure,coord*3+ivec2(2,0),0).r; + exposure += texelFetch(source_exposure,coord*3+ivec2(0,1),0).r; + exposure += texelFetch(source_exposure,coord*3+ivec2(1,1),0).r; + exposure += texelFetch(source_exposure,coord*3+ivec2(2,1),0).r; + exposure += texelFetch(source_exposure,coord*3+ivec2(0,2),0).r; + exposure += texelFetch(source_exposure,coord*3+ivec2(1,2),0).r; + exposure += texelFetch(source_exposure,coord*3+ivec2(2,2),0).r; + exposure *= (1.0/9.0); + +#ifdef EXPOSURE_END + +#ifdef EXPOSURE_FORCE_SET + //will stay as is +#else + highp float prev_lum = texelFetch(prev_exposure,ivec2(0,0),0).r; //1 pixel previous exposure + exposure = clamp( prev_lum + (exposure-prev_lum)*exposure_adjust,min_luminance,max_luminance); + +#endif //EXPOSURE_FORCE_SET + + +#endif //EXPOSURE_END + +#endif //EXPOSURE_BEGIN + + +} + + diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl new file mode 100644 index 0000000000..e72f12cc5e --- /dev/null +++ b/drivers/gles3/shaders/particles.glsl @@ -0,0 +1,167 @@ +[vertex] + + + +layout(location=0) in highp vec4 color; +layout(location=1) in highp vec4 velocity_active; +layout(location=2) in highp vec4 custom; +layout(location=3) in highp vec4 xform_1; +layout(location=4) in highp vec4 xform_2; +layout(location=5) in highp vec4 xform_3; + + +struct Attractor { + + vec3 pos; + vec3 dir; + float radius; + float eat_radius; + float strength; + float attenuation; +}; + +#define MAX_ATTRACTORS 64 + +uniform mat4 origin; +uniform float system_phase; +uniform float prev_system_phase; +uniform float total_particles; +uniform float explosiveness; +uniform vec4 time; +uniform float delta; +uniform vec3 gravity; +uniform int attractor_count; +uniform Attractor attractors[MAX_ATTRACTORS]; + + +out highp vec4 out_color; //tfb: +out highp vec4 out_velocity_active; //tfb: +out highp vec4 out_custom; //tfb: +out highp vec4 out_xform_1; //tfb: +out highp vec4 out_xform_2; //tfb: +out highp vec4 out_xform_3; //tfb: + +VERTEX_SHADER_GLOBALS + +#if defined(USE_MATERIAL) + +layout(std140) uniform UniformData { //ubo:0 + +MATERIAL_UNIFORMS + +}; + +#endif + +void main() { + + bool apply_forces=true; + bool apply_velocity=true; + + float mass = 1.0; + + float restart_phase = float(gl_InstanceID)/total_particles; + restart_phase*= explosiveness; + bool restart=false; + bool active = out_velocity_active.a > 0.5; + + if (system_phase > prev_system_phase) { + restart = prev_system_phase < restart_phase && system_phase >= restart_phase; + } else { + restart = prev_system_phase < restart_phase || system_phase >= restart_phase; + } + + if (restart) { + active=true; + } + + out_color=color; + out_velocity_active=velocity_active; + out_custom=custom; + + mat4 xform = transpose(mat4(xform_1,xform_2,xform_3,vec4(vec3(0.0),1.0))); + + + out_rot_active=rot_active; + + if (active) { + //execute shader + + { + VERTEX_SHADER_CODE + } + +#if !defined(DISABLE_FORCE) + + { + + vec3 force = gravity; + for(int i=0;i<attractor_count;i++) { + + vec3 rel_vec = out_pos_lifetime.xyz - attractors[i].pos; + float dist = rel_vec.length(); + if (attractors[i].radius < dist) + continue; + if (attractors[i].eat_radius>0 && attractors[i].eat_radius > dist) { + out_velocity_active.a=0.0; + } + + rel_vec = normalize(rel_vec); + + float attenuation = pow(dist / attractors[i].radius,attractors[i].attenuation); + + if (attractors[i].dir==vec3(0.0)) { + //towards center + force+=attractors[i].strength * rel_vec * attenuation * mass; + } else { + force+=attractors[i].strength * attractors[i].dir * attenuation *mass; + + } + } + + out_velocity_seed.xyz += force * delta; + } +#endif + +#if !defined(DISABLE_VELOCITY) + + { + + out_pos_lifetime.xyz += out_velocity_seed.xyz * delta; + } +#endif + } + + xform = transpose(xform); + + out_velocity_active.a = mix(0.0,1.0,active); + + out_xform_1 = xform[0]; + out_xform_2 = xform[1]; + out_xform_3 = xform[2]; + + +} + +[fragment] + +//any code here is never executed, stuff is filled just so it works + +FRAGMENT_SHADER_GLOBALS + +#if defined(USE_MATERIAL) + +layout(std140) uniform UniformData { + +MATERIAL_UNIFORMS + +}; + +#endif + +void main() { + + { + FRAGMENT_SHADER_CODE + } +} diff --git a/drivers/gles3/shaders/resolve.glsl b/drivers/gles3/shaders/resolve.glsl new file mode 100644 index 0000000000..6acc712299 --- /dev/null +++ b/drivers/gles3/shaders/resolve.glsl @@ -0,0 +1,41 @@ +[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] + + +in vec2 uv_interp; +uniform sampler2D source_specular; //texunit:0 +uniform sampler2D source_ssr; //texunit:1 + +uniform float stuff; + +in vec2 uv2_interp; + +layout(location = 0) out vec4 frag_color; + +void main() { + + vec4 specular = texture( source_specular, uv_interp ); + +#ifdef USE_SSR + + vec4 ssr = textureLod(source_ssr,uv_interp,0.0); + specular.rgb = mix(specular.rgb,ssr.rgb*specular.a,ssr.a); +#endif + + frag_color = vec4(specular.rgb,1.0); +} + diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl new file mode 100644 index 0000000000..c5af010c96 --- /dev/null +++ b/drivers/gles3/shaders/scene.glsl @@ -0,0 +1,1432 @@ +[vertex] + + +/* +from VisualServer: + +ARRAY_VERTEX=0, +ARRAY_NORMAL=1, +ARRAY_TANGENT=2, +ARRAY_COLOR=3, +ARRAY_TEX_UV=4, +ARRAY_TEX_UV2=5, +ARRAY_BONES=6, +ARRAY_WEIGHTS=7, +ARRAY_INDEX=8, +*/ + +//hack to use uv if no uv present so it works with lightmap + + +/* INPUT ATTRIBS */ + +layout(location=0) in highp vec4 vertex_attrib; +layout(location=1) in vec3 normal_attrib; +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) +layout(location=2) in vec4 tangent_attrib; +#endif + +#if defined(ENABLE_COLOR_INTERP) +layout(location=3) in vec4 color_attrib; +#endif + +#if defined(ENABLE_UV_INTERP) +layout(location=4) in vec2 uv_attrib; +#endif + +#if defined(ENABLE_UV2_INTERP) +layout(location=5) in vec2 uv2_attrib; +#endif + +uniform float normal_mult; + +#ifdef USE_SKELETON +layout(location=6) in ivec4 bone_indices; // attrib:6 +layout(location=7) in vec4 bone_weights; // attrib:7 +#endif + +#ifdef USE_INSTANCING + +layout(location=8) in highp vec4 instance_xform0; +layout(location=9) in highp vec4 instance_xform1; +layout(location=10) in highp vec4 instance_xform2; +layout(location=11) in lowp vec4 instance_color; + +#endif + +layout(std140) uniform SceneData { //ubo:0 + + highp mat4 projection_matrix; + highp mat4 camera_inverse_matrix; + highp mat4 camera_matrix; + highp vec4 time; + + highp vec4 ambient_light_color; + highp vec4 bg_color; + float ambient_energy; + float bg_energy; + + float shadow_z_offset; + float shadow_z_slope_scale; + float shadow_dual_paraboloid_render_zfar; + float shadow_dual_paraboloid_render_side; + + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + + float reflection_multiplier; + float subsurface_scatter_width; + float ambient_occlusion_affect_light; + +}; + +uniform highp mat4 world_transform; + +#ifdef USE_LIGHT_DIRECTIONAL + +layout(std140) uniform DirectionalLightData { //ubo:3 + + highp vec4 light_pos_inv_radius; + mediump vec4 light_direction_attenuation; + mediump vec4 light_color_energy; + mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled, + mediump vec4 light_clamp; + mediump vec4 shadow_color; + highp mat4 shadow_matrix1; + highp mat4 shadow_matrix2; + highp mat4 shadow_matrix3; + highp mat4 shadow_matrix4; + mediump vec4 shadow_split_offsets; +}; + +#endif + + +/* Varyings */ + +out highp vec3 vertex_interp; +out vec3 normal_interp; + +#if defined(ENABLE_COLOR_INTERP) +out vec4 color_interp; +#endif + +#if defined(ENABLE_UV_INTERP) +out vec2 uv_interp; +#endif + +#if defined(ENABLE_UV2_INTERP) +out vec2 uv2_interp; +#endif + + +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) +out vec3 tangent_interp; +out vec3 binormal_interp; +#endif + + +#if !defined(USE_DEPTH_SHADOWS) && defined(USE_SHADOW_PASS) + +varying vec4 position_interp; + +#endif + + +VERTEX_SHADER_GLOBALS + + +#if defined(USE_MATERIAL) + +layout(std140) uniform UniformData { //ubo:1 + +MATERIAL_UNIFORMS + +}; + +#endif + +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + +out highp float dp_clip; + +#endif + +#ifdef USE_SKELETON + +layout(std140) uniform SkeletonData { //ubo:7 + + mat3x4 skeleton[MAX_SKELETON_BONES]; +}; + +#endif + +void main() { + + highp vec4 vertex = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0); + highp mat4 modelview = camera_inverse_matrix * world_transform; + vec3 normal = normal_attrib * normal_mult; + +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) + vec3 tangent = tangent_attrib.xyz; + tangent*=normal_mult; + float binormalf = tangent_attrib.a; +#endif + +#if defined(ENABLE_COLOR_INTERP) + color_interp = color_attrib; +#endif + + +#ifdef USE_SKELETON + + { + //skeleton transform + highp mat3x4 m=skeleton[bone_indices.x]*bone_weights.x; + m+=skeleton[bone_indices.y]*bone_weights.y; + m+=skeleton[bone_indices.z]*bone_weights.z; + m+=skeleton[bone_indices.w]*bone_weights.w; + + vertex.xyz = vertex * m; + + normal = vec4(normal,0.0) * m; +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) + tangent.xyz = vec4(tangent.xyz,0.0) * mn; +#endif + } +#endif // USE_SKELETON1 + + +#ifdef USE_INSTANCING + + { + highp mat3x4 m=mat3x4(instance_xform0,instance_xform1,instance_xform2); + + vertex.xyz = vertex * m; + normal = vec4(normal,0.0) * m; +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) + tangent.xyz = vec4(tangent.xyz,0.0) * mn; +#endif + +#if defined(ENABLE_COLOR_INTERP) + color_interp*=instance_color; +#endif + } +#endif //USE_INSTANCING + +#if !defined(SKIP_TRANSFORM_USED) + + vertex = modelview * vertex; + normal = normalize((modelview * vec4(normal,0.0)).xyz); +#endif + +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) +# if !defined(SKIP_TRANSFORM_USED) + + tangent=normalize((modelview * vec4(tangent,0.0)).xyz); +# endif + vec3 binormal = normalize( cross(normal,tangent) * binormalf ); +#endif + + + + +#if defined(ENABLE_UV_INTERP) + uv_interp = uv_attrib; +#endif + +#if defined(ENABLE_UV2_INTERP) + uv2_interp = uv2_attrib; +#endif + +{ + +VERTEX_SHADER_CODE + +} + + vertex_interp = vertex.xyz; + normal_interp = normal; + +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) + tangent_interp = tangent; + binormal_interp = binormal; +#endif + +#ifdef RENDER_DEPTH + + +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + + vertex_interp.z*= shadow_dual_paraboloid_render_side; + normal_interp.z*= shadow_dual_paraboloid_render_side; + + dp_clip=vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias + + //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges + + highp vec3 vtx = vertex_interp+normalize(vertex_interp)*shadow_z_offset; + highp float distance = length(vtx); + vtx = normalize(vtx); + vtx.xy/=1.0-vtx.z; + vtx.z=(distance/shadow_dual_paraboloid_render_zfar); + vtx.z=vtx.z * 2.0 - 1.0; + + vertex.xyz=vtx; + vertex.w=1.0; + + +#else + + float z_ofs = shadow_z_offset; + z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale; + vertex_interp.z-=z_ofs; + +#endif //RENDER_DEPTH_DUAL_PARABOLOID + +#endif //RENDER_DEPTH + + +#if !defined(SKIP_TRANSFORM_USED) && !defined(RENDER_DEPTH_DUAL_PARABOLOID) + gl_Position = projection_matrix * vec4(vertex_interp,1.0); +#else + gl_Position = vertex; +#endif + + +} + + +[fragment] + + + +#define M_PI 3.14159265359 + +/* Varyings */ + +#if defined(ENABLE_COLOR_INTERP) +in vec4 color_interp; +#endif + +#if defined(ENABLE_UV_INTERP) +in vec2 uv_interp; +#endif + +#if defined(ENABLE_UV2_INTERP) +in vec2 uv2_interp; +#endif + +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) +in vec3 tangent_interp; +in vec3 binormal_interp; +#endif + +in highp vec3 vertex_interp; +in vec3 normal_interp; + + +/* PBR CHANNELS */ + +//used on forward mainly +uniform bool no_ambient_light; + +uniform sampler2D brdf_texture; //texunit:-1 + +#ifdef USE_RADIANCE_MAP + +uniform sampler2D radiance_map; //texunit:-2 + + +layout(std140) uniform Radiance { //ubo:2 + + mat4 radiance_inverse_xform; + vec3 radiance_box_min; + vec3 radiance_box_max; + float radiance_ambient_contribution; + +}; + +#endif + +/* Material Uniforms */ + + +FRAGMENT_SHADER_GLOBALS + + +#if defined(USE_MATERIAL) + +layout(std140) uniform UniformData { + +MATERIAL_UNIFORMS + +}; + +#endif + + +layout(std140) uniform SceneData { + + highp mat4 projection_matrix; + highp mat4 camera_inverse_matrix; + highp mat4 camera_matrix; + highp vec4 time; + + highp vec4 ambient_light_color; + highp vec4 bg_color; + float ambient_energy; + float bg_energy; + + float shadow_z_offset; + float shadow_z_slope_scale; + float shadow_dual_paraboloid_render_zfar; + float shadow_dual_paraboloid_render_side; + + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + + float reflection_multiplier; + float subsurface_scatter_width; + float ambient_occlusion_affect_light; + +}; + +//directional light data + +#ifdef USE_LIGHT_DIRECTIONAL + +layout(std140) uniform DirectionalLightData { + + highp vec4 light_pos_inv_radius; + mediump vec4 light_direction_attenuation; + mediump vec4 light_color_energy; + mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled, + mediump vec4 light_clamp; + mediump vec4 shadow_color; + highp mat4 shadow_matrix1; + highp mat4 shadow_matrix2; + highp mat4 shadow_matrix3; + highp mat4 shadow_matrix4; + mediump vec4 shadow_split_offsets; +}; + + +uniform highp sampler2DShadow directional_shadow; //texunit:-4 + +#endif + +//omni and spot + +struct LightData { + + highp vec4 light_pos_inv_radius; + mediump vec4 light_direction_attenuation; + mediump vec4 light_color_energy; + mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled, + mediump vec4 light_clamp; + mediump vec4 shadow_color; + highp mat4 shadow_matrix; + +}; + + +layout(std140) uniform OmniLightData { //ubo:4 + + LightData omni_lights[MAX_LIGHT_DATA_STRUCTS]; +}; + +layout(std140) uniform SpotLightData { //ubo:5 + + LightData spot_lights[MAX_LIGHT_DATA_STRUCTS]; +}; + + +uniform highp sampler2DShadow shadow_atlas; //texunit:-3 + + +struct ReflectionData { + + mediump vec4 box_extents; + mediump vec4 box_offset; + mediump vec4 params; // intensity, 0, interior , boxproject + mediump vec4 ambient; //ambient color, energy + mediump vec4 atlas_clamp; + highp mat4 local_matrix; //up to here for spot and omni, rest is for directional + //notes: for ambientblend, use distance to edge to blend between already existing global environment +}; + +layout(std140) uniform ReflectionProbeData { //ubo:6 + + ReflectionData reflections[MAX_REFLECTION_DATA_STRUCTS]; +}; +uniform mediump sampler2D reflection_atlas; //texunit:-5 + + +#ifdef USE_FORWARD_LIGHTING + +uniform int omni_light_indices[MAX_FORWARD_LIGHTS]; +uniform int omni_light_count; + +uniform int spot_light_indices[MAX_FORWARD_LIGHTS]; +uniform int spot_light_count; + +uniform int reflection_indices[MAX_FORWARD_LIGHTS]; +uniform int reflection_count; + +#endif + + + +#ifdef USE_MULTIPLE_RENDER_TARGETS + +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 vec4 motion_ssr_buffer; +#endif + +#else + +layout(location=0) out vec4 frag_color; + +#endif + + +// GGX Specular +// Source: http://www.filmicworlds.com/images/ggx-opt/optimized-ggx.hlsl +float G1V(float dotNV, float k) +{ + return 1.0 / (dotNV * (1.0 - k) + k); +} + + +float SchlickFresnel(float u) +{ + float m = 1.0-u; + float m2 = m*m; + return m2*m2*m; // pow(m,5) +} + +float GTR1(float NdotH, float a) +{ + if (a >= 1.0) return 1.0/M_PI; + float a2 = a*a; + float t = 1.0 + (a2-1.0)*NdotH*NdotH; + return (a2-1.0) / (M_PI*log(a2)*t); +} + +void light_compute(vec3 N, vec3 L,vec3 V,vec3 B, vec3 T,vec3 light_color,vec3 diffuse_color, vec3 specular_color, float specular_blob_intensity, float roughness, float rim,float rim_tint, float clearcoat, float clearcoat_gloss,float anisotropy,inout vec3 diffuse, inout vec3 specular) { + + float dotNL = max(dot(N,L), 0.0 ); + float dotNV = max(dot(N,V), 0.0 ); + +#if defined(LIGHT_USE_RIM) + float rim_light = pow(1.0-dotNV,(1.0-roughness)*16.0); + diffuse += rim_light * rim * mix(vec3(1.0),diffuse_color,rim_tint) * light_color; +#endif + + diffuse += dotNL * light_color * diffuse_color; + + if (roughness > 0.0) { + + float alpha = roughness * roughness; + + vec3 H = normalize(V + L); + + float dotNH = max(dot(N,H), 0.0 ); + float dotLH = max(dot(L,H), 0.0 ); + + // D +#if defined(LIGHT_USE_ANISOTROPY) + + float aspect = sqrt(1.0-anisotropy*0.9); + float rx = roughness/aspect; + float ry = roughness*aspect; + float ax = rx*rx; + float ay = ry*ry; + float dotXH = dot( T, H ); + float dotYH = dot( B, H ); + float pi = M_PI; + float denom = dotXH*dotXH / (ax*ax) + dotYH*dotYH / (ay*ay) + dotNH*dotNH; + float D = 1.0 / ( pi * ax*ay * denom*denom ); + +#else + float alphaSqr = alpha * alpha; + float pi = M_PI; + float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0; + float D = alphaSqr / (pi * denom * denom); +#endif + // F + float F0 = 1.0; + float dotLH5 = SchlickFresnel( dotLH ); + float F = F0 + (1.0 - F0) * (dotLH5); + + // V + float k = alpha / 2.0f; + float vis = G1V(dotNL, k) * G1V(dotNV, k); + + float speci = dotNL * D * F * vis; + + specular += speci * light_color /* specular_color*/ * specular_blob_intensity; + +#if defined(LIGHT_USE_CLEARCOAT) + float Dr = GTR1(dotNH, mix(.1,.001,clearcoat_gloss)); + float Fr = mix(.04, 1.0, dotLH5); + float Gr = G1V(dotNL, .25) * G1V(dotNV, .25); + + specular += .25*clearcoat*Gr*Fr*Dr; +#endif + } + + +} + + +float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 pos, float depth, vec4 clamp_rect) { + +#ifdef SHADOW_MODE_PCF_13 + + float avg=textureProj(shadow,vec4(pos,depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,-shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,-shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x*2.0,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x*2.0,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y*2.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y*2.0),depth,1.0)); + return avg*(1.0/13.0); + +#endif + +#ifdef SHADOW_MODE_PCF_5 + + float avg=textureProj(shadow,vec4(pos,depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0)); + return avg*(1.0/5.0); +#endif + +#if !defined(SHADOW_MODE_PCF_5) && !defined(SHADOW_MODE_PCF_13) + + return textureProj(shadow,vec4(pos,depth,1.0)); +#endif + +} + +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + +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; + float normalized_distance = length( light_rel_vec )*omni_lights[idx].light_pos_inv_radius.w; + vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w )); + + if (omni_lights[idx].light_params.w>0.5) { + //there is a shadowmap + + highp vec3 splane=(omni_lights[idx].shadow_matrix * vec4(vertex,1.0)).xyz; + float shadow_len=length(splane); + splane=normalize(splane); + vec4 clamp_rect=omni_lights[idx].light_clamp; + + if (splane.z>=0.0) { + + splane.z+=1.0; + + clamp_rect.y+=clamp_rect.w; + + } else { + + splane.z=1.0 - splane.z; + + //if (clamp_rect.z<clamp_rect.w) { + // clamp_rect.x+=clamp_rect.z; + //} else { + // clamp_rect.y+=clamp_rect.w; + //} + + } + + splane.xy/=splane.z; + splane.xy=splane.xy * 0.5 + 0.5; + splane.z = shadow_len * omni_lights[idx].light_pos_inv_radius.w; + + splane.xy = clamp_rect.xy+splane.xy*clamp_rect.zw; + + light_attenuation*=mix(omni_lights[idx].shadow_color.rgb,vec3(1.0),sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,clamp_rect)); + } + + light_compute(normal,normalize(light_rel_vec),eye_vec,binormal,tangent,omni_lights[idx].light_color_energy.rgb*light_attenuation,albedo,specular,omni_lights[idx].light_params.z,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light); + +} + +void light_process_spot(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 = spot_lights[idx].light_pos_inv_radius.xyz-vertex; + float normalized_distance = length( light_rel_vec )*spot_lights[idx].light_pos_inv_radius.w; + vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.0), spot_lights[idx].light_direction_attenuation.w )); + vec3 spot_dir = spot_lights[idx].light_direction_attenuation.xyz; + float spot_cutoff=spot_lights[idx].light_params.y; + float scos = max(dot(-normalize(light_rel_vec), spot_dir),spot_cutoff); + float spot_rim = (1.0 - scos) / (1.0 - spot_cutoff); + light_attenuation *= 1.0 - pow( spot_rim, spot_lights[idx].light_params.x); + + if (spot_lights[idx].light_params.w>0.5) { + //there is a shadowmap + highp vec4 splane=(spot_lights[idx].shadow_matrix * vec4(vertex,1.0)); + splane.xyz/=splane.w; + light_attenuation*=mix(spot_lights[idx].shadow_color.rgb,vec3(1.0),sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,spot_lights[idx].light_clamp)); + } + + light_compute(normal,normalize(light_rel_vec),eye_vec,binormal,tangent,spot_lights[idx].light_color_energy.rgb*light_attenuation,albedo,specular,spot_lights[idx].light_params.z,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light); + +} + +void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 tangent,float roughness,float anisotropy,vec3 ambient,vec3 skybox,vec2 brdf, inout highp vec4 reflection_accum,inout highp vec4 ambient_accum) { + + vec3 ref_vec = normalize(reflect(vertex,normal)); + vec3 local_pos = (reflections[idx].local_matrix * vec4(vertex,1.0)).xyz; + vec3 box_extents = reflections[idx].box_extents.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)); + //make blend more rounded + blend=mix(length(inner_pos),blend,blend); + blend*=blend; + blend=1.001-blend; + + if (reflections[idx].params.x>0.0){// compute reflection + + vec3 local_ref_vec = (reflections[idx].local_matrix * vec4(ref_vec,0.0)).xyz; + + if (reflections[idx].params.w > 0.5) { //box project + + vec3 nrdir = normalize(local_ref_vec); + vec3 rbmax = (box_extents - local_pos)/nrdir; + vec3 rbmin = (-box_extents - local_pos)/nrdir; + + + vec3 rbminmax = mix(rbmin,rbmax,greaterThan(nrdir,vec3(0.0,0.0,0.0))); + + float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); + vec3 posonbox = local_pos + nrdir * fa; + local_ref_vec = posonbox - reflections[idx].box_offset.xyz; + } + + + + vec3 splane=normalize(local_ref_vec); + vec4 clamp_rect=reflections[idx].atlas_clamp; + + splane.z*=-1.0; + if (splane.z>=0.0) { + splane.z+=1.0; + clamp_rect.y+=clamp_rect.w; + } else { + splane.z=1.0 - splane.z; + splane.y=-splane.y; + } + + splane.xy/=splane.z; + splane.xy=splane.xy * 0.5 + 0.5; + + splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy; + splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw); + + highp vec4 reflection; + reflection.rgb = textureLod(reflection_atlas,splane.xy,roughness*5.0).rgb * brdf.x + brdf.y; + + if (reflections[idx].params.z < 0.5) { + reflection.rgb = mix(skybox,reflection.rgb,blend); + } + reflection.rgb*=reflections[idx].params.x; + reflection.a = blend; + reflection.rgb*=reflection.a; + + reflection_accum+=reflection; + } + + if (reflections[idx].ambient.a>0.0) { //compute ambient using skybox + + + vec3 local_amb_vec = (reflections[idx].local_matrix * vec4(normal,0.0)).xyz; + + vec3 splane=normalize(local_amb_vec); + vec4 clamp_rect=reflections[idx].atlas_clamp; + + splane.z*=-1.0; + if (splane.z>=0.0) { + splane.z+=1.0; + clamp_rect.y+=clamp_rect.w; + } else { + splane.z=1.0 - splane.z; + splane.y=-splane.y; + } + + splane.xy/=splane.z; + splane.xy=splane.xy * 0.5 + 0.5; + + splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy; + splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw); + + highp vec4 ambient_out; + ambient_out.a=blend; + ambient_out.rgb = textureLod(reflection_atlas,splane.xy,5.0).rgb; + ambient_out.rgb=mix(reflections[idx].ambient.rgb,ambient_out.rgb,reflections[idx].ambient.a); + if (reflections[idx].params.z < 0.5) { + ambient_out.rgb = mix(ambient,ambient_out.rgb,blend); + } + + ambient_out.rgb *= ambient_out.a; + ambient_accum+=ambient_out; + } else { + + highp vec4 ambient_out; + ambient_out.a=blend; + ambient_out.rgb=reflections[idx].ambient.rgb; + if (reflections[idx].params.z < 0.5) { + ambient_out.rgb = mix(ambient,ambient_out.rgb,blend); + } + ambient_out.rgb *= ambient_out.a; + ambient_accum+=ambient_out; + + } +} + +#ifdef USE_GI_PROBES + +uniform mediump sampler3D gi_probe1; //texunit:-6 +uniform highp mat4 gi_probe_xform1; +uniform highp vec3 gi_probe_bounds1; +uniform highp vec3 gi_probe_cell_size1; +uniform highp float gi_probe_multiplier1; +uniform bool gi_probe_blend_ambient1; + +uniform mediump sampler3D gi_probe2; //texunit:-7 +uniform highp mat4 gi_probe_xform2; +uniform highp vec3 gi_probe_bounds2; +uniform highp vec3 gi_probe_cell_size2; +uniform highp float gi_probe_multiplier2; +uniform bool gi_probe2_enabled; +uniform bool gi_probe_blend_ambient2; + +vec3 voxel_cone_trace(sampler3D probe, vec3 cell_size, vec3 pos, vec3 ambient, bool blend_ambient, vec3 direction, float tan_half_angle, float max_distance) { + + + float dist = dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0; + float alpha=0.0; + vec3 color = vec3(0.0); + + while(dist < max_distance && alpha < 0.95) { + float diameter = max(1.0, 2.0 * tan_half_angle * dist); + vec4 scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) ); + float a = (1.0 - alpha); + color += scolor.rgb * a; + alpha += a * scolor.a; + dist += diameter * 0.5; + } + + //color.rgb = mix(color.rgb,mix(ambient,color.rgb,alpha),blend_ambient); + + return color; +} + +void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_size,vec3 pos, vec3 ambient, vec3 environment, bool blend_ambient,float multiplier, mat3 normal_mtx,vec3 ref_vec, float roughness, out vec4 out_spec, out vec4 out_diff) { + + + + vec3 probe_pos = (probe_xform * vec4(pos,1.0)).xyz; + vec3 ref_pos = (probe_xform * vec4(pos+ref_vec,1.0)).xyz; + + ref_vec = normalize(ref_pos - probe_pos); + +/* out_diff.rgb = voxel_cone_trace(probe,cell_size,probe_pos,normalize((probe_xform * vec4(ref_vec,0.0)).xyz),0.0 ,100.0); + out_diff.a = 1.0; + return;*/ + //out_diff = vec4(textureLod(probe,probe_pos*cell_size,3.0).rgb,1.0); + //return; + + if (any(bvec2(any(lessThan(probe_pos,vec3(0.0))),any(greaterThan(probe_pos,bounds))))) + return; + + vec3 blendv = probe_pos/bounds * 2.0 - 1.0; + float blend = 1.001-max(blendv.x,max(blendv.y,blendv.z)); + blend=1.0; + + float max_distance = length(bounds); + + //radiance +#ifdef VCT_QUALITY_HIGH + +#define MAX_CONE_DIRS 6 + vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] ( + vec3(0, 0, 1), + vec3(0.866025, 0, 0.5), + vec3(0.267617, 0.823639, 0.5), + vec3(-0.700629, 0.509037, 0.5), + vec3(-0.700629, -0.509037, 0.5), + vec3(0.267617, -0.823639, 0.5) + ); + + float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15); + float cone_angle_tan = 0.577; + float min_ref_tan = 0.0; +#else + +#define MAX_CONE_DIRS 4 + + vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] ( + vec3(0.707107, 0, 0.707107), + vec3(0, 0.707107, 0.707107), + vec3(-0.707107, 0, 0.707107), + vec3(0, -0.707107, 0.707107) + ); + + float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25); + float cone_angle_tan = 0.98269; + max_distance*=0.5; + float min_ref_tan = 0.2; + +#endif + vec3 light=vec3(0.0); + for(int i=0;i<MAX_CONE_DIRS;i++) { + + vec3 dir = normalize( (probe_xform * vec4(pos + normal_mtx * cone_dirs[i],1.0)).xyz - probe_pos); + light+=cone_weights[i] * voxel_cone_trace(probe,cell_size,probe_pos,ambient,blend_ambient,dir,cone_angle_tan,max_distance); + + } + + light*=multiplier; + + out_diff = vec4(light*blend,blend); + + //irradiance + + vec3 irr_light = voxel_cone_trace(probe,cell_size,probe_pos,environment,blend_ambient,ref_vec,max(min_ref_tan,tan(roughness * 0.5 * M_PI)) ,max_distance); + + irr_light *= multiplier; + //irr_light=vec3(0.0); + + out_spec = vec4(irr_light*blend,blend); +} + + +void gi_probes_compute(vec3 pos, vec3 normal, float roughness, vec3 specular, inout vec3 out_specular, inout vec3 out_ambient) { + + roughness = roughness * roughness; + + vec3 ref_vec = normalize(reflect(normalize(pos),normal)); + + //find arbitrary tangent and bitangent, then build a matrix + vec3 v0 = abs(normal.z) < 0.999 ? vec3(0, 0, 1) : vec3(0, 1, 0); + vec3 tangent = normalize(cross(v0, normal)); + vec3 bitangent = normalize(cross(tangent, normal)); + mat3 normal_mat = mat3(tangent,bitangent,normal); + + vec4 diff_accum = vec4(0.0); + vec4 spec_accum = vec4(0.0); + + vec3 ambient = out_ambient; + out_ambient = vec3(0.0); + + vec3 environment = out_specular; + + out_specular = vec3(0.0); + + gi_probe_compute(gi_probe1,gi_probe_xform1,gi_probe_bounds1,gi_probe_cell_size1,pos,ambient,environment,gi_probe_blend_ambient1,gi_probe_multiplier1,normal_mat,ref_vec,roughness,spec_accum,diff_accum); + + if (gi_probe2_enabled) { + + gi_probe_compute(gi_probe2,gi_probe_xform2,gi_probe_bounds2,gi_probe_cell_size2,pos,ambient,environment,gi_probe_blend_ambient2,gi_probe_multiplier2,normal_mat,ref_vec,roughness,spec_accum,diff_accum); + } + + if (diff_accum.a>0.0) { + diff_accum.rgb/=diff_accum.a; + } + + if (spec_accum.a>0.0) { + spec_accum.rgb/=spec_accum.a; + } + + out_specular+=spec_accum.rgb; + out_ambient+=diff_accum.rgb; + +} + +#endif + + +void main() { + +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + + if (dp_clip>0.0) + discard; +#endif + + //lay out everything, whathever is unused is optimized away anyway + highp vec3 vertex = vertex_interp; + vec3 albedo = vec3(0.8,0.8,0.8); + vec3 specular = vec3(0.2,0.2,0.2); + vec3 emission = vec3(0.0,0.0,0.0); + float roughness = 1.0; + float rim = 0.0; + float rim_tint = 0.0; + float clearcoat=0.0; + float clearcoat_gloss=0.0; + float anisotropy = 1.0; + vec2 anisotropy_flow = vec2(1.0,0.0); + +#if defined(ENABLE_AO) + float ao=1.0; +#endif + + float alpha = 1.0; + +#ifdef METERIAL_DOUBLESIDED + float side=float(gl_FrontFacing)*2.0-1.0; +#else + float side=1.0; +#endif + + +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) + vec3 binormal = normalize(binormal_interp)*side; + vec3 tangent = normalize(tangent_interp)*side; +#else + vec3 binormal = vec3(0.0); + vec3 tangent = vec3(0.0); +#endif + vec3 normal = normalize(normal_interp)*side; + +#if defined(ENABLE_UV_INTERP) + vec2 uv = uv_interp; +#endif + +#if defined(ENABLE_UV2_INTERP) + vec2 uv2 = uv2_interp; +#endif + +#if defined(ENABLE_COLOR_INTERP) + vec4 color = color_interp; +#endif + +#if defined(ENABLE_NORMALMAP) + + vec3 normalmap = vec3(0.0); +#endif + + float normaldepth=1.0; + + + +#if defined(ENABLE_DISCARD) + bool discard_=false; +#endif + +#if defined (ENABLE_SSS_MOTION) + float sss_strength=0.0; +#endif + +{ + + +FRAGMENT_SHADER_CODE + +} + + + +#if defined(ENABLE_NORMALMAP) + + normalmap.xy=normalmap.xy*2.0-1.0; + normalmap.z=sqrt(1.0-dot(normalmap.xy,normalmap.xy)); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. + + normal = normalize( mix(normal_interp,tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z,normaldepth) ) * side; + +#endif + +#if defined(LIGHT_USE_ANISOTROPY) + + if (anisotropy>0.01) { + //rotation matrix + mat3 rot = mat3( tangent, binormal, normal ); + //make local to space + tangent = normalize(rot * vec3(anisotropy_flow.x,anisotropy_flow.y,0.0)); + binormal = normalize(rot * vec3(-anisotropy_flow.y,anisotropy_flow.x,0.0)); + } + +#endif + +#if defined(ENABLE_DISCARD) + if (discard_) { + //easy to eliminate dead code + discard; + } +#endif + +#ifdef ENABLE_CLIP_ALPHA + if (albedo.a<0.99) { + //used for doublepass and shadowmapping + discard; + } +#endif + +/////////////////////// LIGHTING ////////////////////////////// + + //apply energy conservation + + vec3 specular_light = vec3(0.0,0.0,0.0); + vec3 ambient_light; + vec3 diffuse_light = vec3(0.0,0.0,0.0); + + vec3 eye_vec = -normalize( vertex_interp ); + +#ifndef RENDER_DEPTH + float ndotv = clamp(dot(normal,eye_vec),0.0,1.0); + + vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy; +#endif + +#ifdef USE_RADIANCE_MAP + + if (no_ambient_light) { + ambient_light=vec3(0.0,0.0,0.0); + } else { + { + + + + float lod = roughness * 5.0; + + { //read radiance from dual paraboloid + + vec3 ref_vec = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n); + ref_vec=normalize((radiance_inverse_xform * vec4(ref_vec,0.0)).xyz); + + vec3 norm = normalize(ref_vec); + float y_ofs=0.0; + if (norm.z>=0.0) { + + norm.z+=1.0; + y_ofs+=0.5; + } else { + norm.z=1.0 - norm.z; + norm.y=-norm.y; + } + + norm.xy/=norm.z; + norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25+y_ofs); + specular_light = textureLod(radiance_map, norm.xy, lod).xyz * brdf.x + brdf.y; + + } + //no longer a cubemap + //vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y); + + } + + { + + /*vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz); + vec3 env_ambient=textureLod(radiance_cube, ambient_dir, 5.0).xyz; + + ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution);*/ + ambient_light=vec3(0.0,0.0,0.0); + } + } + +#else + + if (no_ambient_light){ + ambient_light=vec3(0.0,0.0,0.0); + } else { + ambient_light=ambient_light_color.rgb; + } +#endif + + +#ifdef USE_LIGHT_DIRECTIONAL + + vec3 light_attenuation=vec3(1.0); + +#ifdef LIGHT_DIRECTIONAL_SHADOW + + if (gl_FragCoord.w > shadow_split_offsets.w) { + + vec3 pssm_coord; + +#ifdef LIGHT_USE_PSSM_BLEND + float pssm_blend; + vec3 pssm_coord2; + bool use_blend=true; + vec3 light_pssm_split_inv = 1.0/shadow_split_offsets.xyz; + float w_inv = 1.0/gl_FragCoord.w; +#endif + + +#ifdef LIGHT_USE_PSSM4 + + + if (gl_FragCoord.w > shadow_split_offsets.y) { + + if (gl_FragCoord.w > shadow_split_offsets.x) { + + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + + +#if defined(LIGHT_USE_PSSM_BLEND) + + splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv); +#endif + + } else { + + highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + +#if defined(LIGHT_USE_PSSM_BLEND) + splane=(shadow_matrix3 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(light_pssm_split_inv.x,light_pssm_split_inv.y,w_inv); +#endif + + } + } else { + + + if (gl_FragCoord.w > shadow_split_offsets.z) { + + highp vec4 splane=(shadow_matrix3 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + +#if defined(LIGHT_USE_PSSM_BLEND) + splane=(shadow_matrix4 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(light_pssm_split_inv.y,light_pssm_split_inv.z,w_inv); +#endif + + } else { + highp vec4 splane=(shadow_matrix4 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + +#if defined(LIGHT_USE_PSSM_BLEND) + use_blend=false; + +#endif + + } + } + +#endif //LIGHT_USE_PSSM4 + +#ifdef LIGHT_USE_PSSM2 + + if (gl_FragCoord.w > shadow_split_offsets.x) { + + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + + +#if defined(LIGHT_USE_PSSM_BLEND) + + splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv); +#endif + + } else { + highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; +#if defined(LIGHT_USE_PSSM_BLEND) + use_blend=false; + +#endif + + } + +#endif //LIGHT_USE_PSSM2 + +#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) + { //regular orthogonal + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + } +#endif + + + //one one sample + light_attenuation=mix(shadow_color.rgb,vec3(1.0),sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord.xy,pssm_coord.z,light_clamp)); + + +#if defined(LIGHT_USE_PSSM_BLEND) + if (use_blend) { + vec3 light_attenuation2=mix(shadow_color.rgb,vec3(1.0),sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp)); + light_attenuation=mix(light_attenuation,light_attenuation2,pssm_blend); + } +#endif + + } + +#endif //LIGHT_DIRECTIONAL_SHADOW + + light_compute(normal,-light_direction_attenuation.xyz,eye_vec,binormal,tangent,light_color_energy.rgb*light_attenuation,albedo,specular,light_params.z,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light); + + +#endif //#USE_LIGHT_DIRECTIONAL + +#ifdef USE_GI_PROBES + gi_probes_compute(vertex,normal,roughness,specular,specular_light,ambient_light); +#endif + + +#ifdef USE_FORWARD_LIGHTING + + highp vec4 reflection_accum = vec4(0.0,0.0,0.0,0.0); + highp vec4 ambient_accum = vec4(0.0,0.0,0.0,0.0); + + + + for(int i=0;i<reflection_count;i++) { + reflection_process(reflection_indices[i],vertex,normal,binormal,tangent,roughness,anisotropy,ambient_light,specular_light,brdf,reflection_accum,ambient_accum); + } + + if (reflection_accum.a>0.0) { + specular_light+=reflection_accum.rgb/reflection_accum.a; + } + if (ambient_accum.a>0.0) { + ambient_light+=ambient_accum.rgb/ambient_accum.a; + } + + for(int i=0;i<omni_light_count;i++) { + light_process_omni(omni_light_indices[i],vertex,eye_vec,normal,binormal,tangent,albedo,specular,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light); + } + + for(int i=0;i<spot_light_count;i++) { + light_process_spot(spot_light_indices[i],vertex,eye_vec,normal,binormal,tangent,albedo,specular,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light); + } + + + +#endif + + + + +#if defined(USE_LIGHT_SHADER_CODE) +//light is written by the light shader +{ + +LIGHT_SHADER_CODE + +} +#endif + +#ifdef RENDER_DEPTH +//nothing happens, so a tree-ssa optimizer will result in no fragment shader :) +#else + + specular_light*=reflection_multiplier; + ambient_light*=albedo; //ambient must be multiplied by albedo at the end + +#if defined(ENABLE_AO) + ambient_light*=ao; +#endif + + //energy conservation + diffuse_light=mix(diffuse_light,vec3(0.0),specular); + ambient_light=mix(ambient_light,vec3(0.0),specular); + specular_light *= max(vec3(0.04),specular); + +#ifdef USE_MULTIPLE_RENDER_TARGETS + +#if defined(ENABLE_AO) + + float ambient_scale=0.0; // AO is supplied by material +#else + //approximate ambient scale for SSAO, since we will lack full ambient + float max_emission=max(emission.r,max(emission.g,emission.b)); + float max_ambient=max(ambient_light.r,max(ambient_light.g,ambient_light.b)); + float max_diffuse=max(diffuse_light.r,max(diffuse_light.g,diffuse_light.b)); + float total_ambient = max_ambient+max_diffuse+max_emission; + float ambient_scale = (total_ambient>0.0) ? (max_ambient+ambient_occlusion_affect_light*max_diffuse)/total_ambient : 0.0; +#endif //ENABLE_AO + + diffuse_buffer=vec4(emission+diffuse_light+ambient_light,ambient_scale); + specular_buffer=vec4(specular_light,max(specular.r,max(specular.g,specular.b))); + + + normal_mr_buffer=vec4(normalize(normal)*0.5+0.5,roughness); + +#if defined (ENABLE_SSS_MOTION) + motion_ssr_buffer = vec4(vec3(0.0),sss_strength); +#endif + +#else + + +#ifdef SHADELESS + frag_color=vec4(albedo,alpha); +#else + frag_color=vec4(emission+ambient_light+diffuse_light+specular_light,alpha); +#endif //SHADELESS + + +#endif //USE_MULTIPLE_RENDER_TARGETS + + + +#endif //RENDER_DEPTH + + +} + + diff --git a/drivers/gles3/shaders/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl new file mode 100644 index 0000000000..ec4bdf86c9 --- /dev/null +++ b/drivers/gles3/shaders/screen_space_reflection.glsl @@ -0,0 +1,345 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; +layout(location=4) in vec2 uv_in; + +out vec2 uv_interp; +out vec2 pos_interp; + +void main() { + + uv_interp = uv_in; + gl_Position = vertex_attrib; + pos_interp.xy=gl_Position.xy; +} + +[fragment] + + +in vec2 uv_interp; +in vec2 pos_interp; + +uniform sampler2D source_diffuse; //texunit:0 +uniform sampler2D source_normal_roughness; //texunit:1 +uniform sampler2D source_depth; //texunit:2 + +uniform float camera_z_near; +uniform float camera_z_far; + +uniform vec2 viewport_size; +uniform vec2 pixel_size; + +uniform float filter_mipmap_levels; + +uniform mat4 inverse_projection; +uniform mat4 projection; + +uniform int num_steps; +uniform float depth_tolerance; +uniform float distance_fade; +uniform float acceleration; + +layout(location = 0) out vec4 frag_color; + + +vec2 view_to_screen(vec3 view_pos,out float w) { + vec4 projected = projection * vec4(view_pos, 1.0); + projected.xyz /= projected.w; + projected.xy = projected.xy * 0.5 + 0.5; + w=projected.w; + return projected.xy; +} + + + +#define M_PI 3.14159265359 + + +void main() { + + + //// + + vec4 diffuse = texture( source_diffuse, uv_interp ); + vec4 normal_roughness = texture( source_normal_roughness, uv_interp); + + vec3 normal; + + normal = normal_roughness.xyz*2.0-1.0; + + float roughness = normal_roughness.w; + + float depth_tex = texture(source_depth,uv_interp).r; + + vec4 world_pos = inverse_projection * vec4( uv_interp*2.0-1.0, depth_tex*2.0-1.0, 1.0 ); + vec3 vertex = world_pos.xyz/world_pos.w; + + vec3 view_dir = normalize(vertex); + vec3 ray_dir = normalize(reflect(view_dir, normal)); + + if (dot(ray_dir,normal)<0.001) { + frag_color=vec4(0.0); + return; + } + //ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0); + + //ray_dir = normalize(vec3(1,1,-1)); + + + //////////////// + + + //make ray length and clip it against the near plane (don't want to trace beyond visible) + float ray_len = (vertex.z + ray_dir.z * camera_z_far) > -camera_z_near ? (-camera_z_near - vertex.z) / ray_dir.z : camera_z_far; + vec3 ray_end = vertex + ray_dir*ray_len; + + float w_begin; + vec2 vp_line_begin = view_to_screen(vertex,w_begin); + float w_end; + vec2 vp_line_end = view_to_screen( ray_end, w_end); + vec2 vp_line_dir = vp_line_end-vp_line_begin; + + //we need to interpolate w along the ray, to generate perspective correct reflections + + w_begin = 1.0/w_begin; + w_end = 1.0/w_end; + + + float z_begin = vertex.z*w_begin; + float z_end = ray_end.z*w_end; + + vec2 line_begin = vp_line_begin/pixel_size; + vec2 line_dir = vp_line_dir/pixel_size; + float z_dir = z_end - z_begin; + float w_dir = w_end - w_begin; + + + // clip the line to the viewport edges + + float scale_max_x = min(1, 0.99 * (1.0 - vp_line_begin.x) / max(1e-5, vp_line_dir.x)); + float scale_max_y = min(1, 0.99 * (1.0 - vp_line_begin.y) / max(1e-5, vp_line_dir.y)); + float scale_min_x = min(1, 0.99 * vp_line_begin.x / max(1e-5, -vp_line_dir.x)); + float scale_min_y = min(1, 0.99 * vp_line_begin.y / max(1e-5, -vp_line_dir.y)); + float line_clip = min(scale_max_x, scale_max_y) * min(scale_min_x, scale_min_y); + line_dir *= line_clip; + z_dir *= line_clip; + w_dir *=line_clip; + + //clip z and w advance to line advance + vec2 line_advance = normalize(line_dir); //down to pixel + float step_size = length(line_advance)/length(line_dir); + float z_advance = z_dir*step_size; // adapt z advance to line advance + float w_advance = w_dir*step_size; // adapt w advance to line advance + + //make line advance faster if direction is closer to pixel edges (this avoids sampling the same pixel twice) + float advance_angle_adj = 1.0/max(abs(line_advance.x),abs(line_advance.y)); + line_advance*=advance_angle_adj; // adapt z advance to line advance + z_advance*=advance_angle_adj; + w_advance*=advance_angle_adj; + + vec2 pos = line_begin; + float z = z_begin; + float w = w_begin; + float z_from=z/w; + float z_to=z_from; + float depth; + vec2 prev_pos=pos; + + bool found=false; + + //if acceleration > 0, distance between pixels gets larger each step. This allows covering a larger area + float accel=1.0+acceleration; + float steps_taken=0; + + for(float i=0;i<num_steps;i++) { + + pos+=line_advance; + z+=z_advance; + w+=w_advance; + + //convert to linear depth + depth = texture(source_depth, pos*pixel_size).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; + + z_from = z_to; + z_to = z/w; + + if (depth>z_to) { + //if depth was surpassed + if (depth<=max(z_to,z_from)+depth_tolerance) { + //check the depth tolerance + found=true; + } + break; + } + + steps_taken+=1.0; + prev_pos=pos; + z_advance*=accel; + w_advance*=accel; + line_advance*=accel; + } + + + + + if (found) { + + float margin_blend=1.0; + + + vec2 margin = vec2((viewport_size.x+viewport_size.y)*0.5*0.05); //make a uniform margin + if (any(bvec4(lessThan(pos,-margin),greaterThan(pos,viewport_size+margin)))) { + //clip outside screen + margin + frag_color=vec4(0.0); + return; + } + + { + //blend fading out towards external margin + vec2 margin_grad = mix(pos-viewport_size,-pos,lessThan(pos,vec2(0.0))); + margin_blend = 1.0-smoothstep(0.0,margin.x,max(margin_grad.x,margin_grad.y)); + //margin_blend=1.0; + + } + + vec2 final_pos; + float grad; + +#ifdef SMOOTH_ACCEL + //if the distance between point and prev point is >1, then take some samples in the middle for smoothing out the image + vec2 blend_dir = pos - prev_pos; + float steps = min(8.0,length(blend_dir)); + if (steps>2.0) { + vec2 blend_step = blend_dir/steps; + float blend_z = (z_to-z_from)/steps; + vec2 new_pos; + float subgrad=0.0; + for(float i=0.0;i<steps;i++) { + + new_pos = (prev_pos+blend_step*i); + float z = z_from+blend_z*i; + + depth = texture(source_depth, new_pos*pixel_size).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; + + subgrad=i/steps; + if (depth>z) + break; + } + + final_pos = new_pos; + grad=(steps_taken+subgrad)/num_steps; + + } else { +#endif + grad=steps_taken/num_steps; + final_pos=pos; +#ifdef SMOOTH_ACCEL + } + +#endif + + + +#ifdef REFLECT_ROUGHNESS + + + vec4 final_color; + //if roughness is enabled, do screen space cone tracing + if (roughness > 0.001) { + /////////////////////////////////////////////////////////////////////////////////////// + //use a blurred version (in consecutive mipmaps) of the screen to simulate roughness + + float gloss = 1.0-roughness; + float cone_angle = roughness * M_PI * 0.5; + vec2 cone_dir = final_pos - line_begin; + float cone_len = length(cone_dir); + cone_dir = normalize(cone_dir); //will be used normalized from now on + float max_mipmap = filter_mipmap_levels -1; + float gloss_mult=gloss; + + float rem_alpha=1.0; + final_color = vec4(0.0); + + for(int i=0;i<7;i++) { + + float op_len = 2.0 * tan(cone_angle) * cone_len; //oposite side of iso triangle + float radius; + { + //fit to sphere inside cone (sphere ends at end of cone), something like this: + // ___ + // \O/ + // V + // + // as it avoids bleeding from beyond the reflection as much as possible. As a plus + // it also makes the rough reflection more elongated. + float a = op_len; + float h = cone_len; + float a2 = a * a; + float fh2 = 4.0f * h * h; + radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h); + } + + //find the place where screen must be sampled + vec2 sample_pos = ( line_begin + cone_dir * (cone_len - radius) ) * pixel_size; + //radius is in pixels, so it's natural that log2(radius) maps to the right mipmap for the amount of pixels + float mipmap = clamp( log2( radius ), 0.0, max_mipmap ); + + //mipmap = max(mipmap-1.0,0.0); + //do sampling + + vec4 sample_color; + { + sample_color = textureLod(source_diffuse,sample_pos,mipmap); + } + + //multiply by gloss + sample_color.rgb*=gloss_mult; + sample_color.a=gloss_mult; + + rem_alpha -= sample_color.a; + if(rem_alpha < 0.0) { + sample_color.rgb *= (1.0 - abs(rem_alpha)); + } + + final_color+=sample_color; + + if (final_color.a>=0.95) { + // This code of accumulating gloss and aborting on near one + // makes sense when you think of cone tracing. + // Think of it as if roughness was 0, then we could abort on the first + // iteration. For lesser roughness values, we need more iterations, but + // each needs to have less influence given the sphere is smaller + break; + } + + cone_len-=radius*2.0; //go to next (smaller) circle. + + gloss_mult*=gloss; + + + } + } else { + final_color = textureLod(source_diffuse,final_pos*pixel_size,0.0); + } + + frag_color = vec4(final_color.rgb,pow(clamp(1.0-grad,0.0,1.0),distance_fade)*margin_blend); + +#else + frag_color = vec4(textureLod(source_diffuse,final_pos*pixel_size,0.0).rgb,pow(clamp(1.0-grad,0.0,1.0),distance_fade)*margin_blend); +#endif + + + + } else { + frag_color = vec4(0.0,0.0,0.0,0.0); + } + + + +} + diff --git a/drivers/gles3/shaders/ssao.glsl b/drivers/gles3/shaders/ssao.glsl new file mode 100644 index 0000000000..75f49ef37a --- /dev/null +++ b/drivers/gles3/shaders/ssao.glsl @@ -0,0 +1,247 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; + +void main() { + + gl_Position = vertex_attrib; + gl_Position.z=1.0; +} + +[fragment] + + +#define NUM_SAMPLES (11) + +// If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower +// miplevel to maintain reasonable spatial locality in the cache +// If this number is too small (< 3), too many taps will land in the same pixel, and we'll get bad variance that manifests as flashing. +// If it is too high (> 5), we'll get bad performance because we're not using the MIP levels effectively +#define LOG_MAX_OFFSET (3) + +// This must be less than or equal to the MAX_MIP_LEVEL defined in SSAO.cpp +#define MAX_MIP_LEVEL (4) + +// This is the number of turns around the circle that the spiral pattern makes. This should be prime to prevent +// taps from lining up. This particular choice was tuned for NUM_SAMPLES == 9 +#define NUM_SPIRAL_TURNS (7) + + +uniform sampler2D source_depth; //texunit:0 +uniform usampler2D source_depth_mipmaps; //texunit:1 +uniform sampler2D source_normal; //texunit:2 + +uniform ivec2 screen_size; +uniform float camera_z_far; +uniform float camera_z_near; + +uniform float intensity_div_r6; +uniform float radius; + +#ifdef ENABLE_RADIUS2 +uniform float intensity_div_r62; +uniform float radius2; +#endif + +uniform float bias; +uniform float proj_scale; + +layout(location = 0) out float visibility; + +uniform vec4 proj_info; + +vec3 reconstructCSPosition(vec2 S, float z) { + return vec3((S.xy * proj_info.xy + proj_info.zw) * z, z); +} + +vec3 getPosition(ivec2 ssP) { + vec3 P; + P.z = texelFetch(source_depth, ssP, 0).r; + + P.z = P.z * 2.0 - 1.0; + P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near)); + P.z = -P.z; + + // Offset to pixel center + P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); + return P; +} + +/** Reconstructs screen-space unit normal from screen-space position */ +vec3 reconstructCSFaceNormal(vec3 C) { + return normalize(cross(dFdy(C), dFdx(C))); +} + + + +/** Returns a unit vector and a screen-space radius for the tap on a unit disk (the caller should scale by the actual disk radius) */ +vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ + // Radius relative to ssR + float alpha = float(sampleNumber + 0.5) * (1.0 / NUM_SAMPLES); + float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle; + + ssR = alpha; + return vec2(cos(angle), sin(angle)); +} + + +/** Read the camera-space position of the point at screen-space pixel ssP + unitOffset * ssR. Assumes length(unitOffset) == 1 */ +vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { + // Derivation: + // mipLevel = floor(log(ssR / MAX_OFFSET)); + int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); + + ivec2 ssP = ivec2(ssR * unitOffset) + ssC; + + vec3 P; + + // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. + // Manually clamp to the texture size because texelFetch bypasses the texture unit + ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), (screen_size >> mipLevel) - ivec2(1)); + + + if (mipLevel < 1) { + //read from depth buffer + P.z = texelFetch(source_depth, mipP, 0).r; + P.z = P.z * 2.0 - 1.0; + P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near)); + P.z = -P.z; + + } else { + //read from mipmaps + uint d = texelFetch(source_depth_mipmaps, mipP, mipLevel-1).r; + P.z = -(float(d)/65535.0)*camera_z_far; + } + + + // Offset to pixel center + P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); + + return P; +} + + + +/** Compute the occlusion due to sample with index \a i about the pixel at \a ssC that corresponds + to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius + + Note that units of H() in the HPG12 paper are meters, not + unitless. The whole falloff/sampling function is therefore + unitless. In this implementation, we factor out (9 / radius). + + Four versions of the falloff function are implemented below +*/ +float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius,in float p_radius, in int tapIndex, in float randomPatternRotationAngle) { + // Offset on the unit disk, spun for this pixel + float ssR; + vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); + ssR *= ssDiskRadius; + + // The occluding point in camera space + vec3 Q = getOffsetPosition(ssC, unitOffset, ssR); + + vec3 v = Q - C; + + float vv = dot(v, v); + float vn = dot(v, n_C); + + const float epsilon = 0.01; + float radius2 = p_radius*p_radius; + + // A: From the HPG12 paper + // Note large epsilon to avoid overdarkening within cracks + //return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6; + + // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended] + float f=max(radius2 - vv, 0.0); + return f * f * f * max((vn - bias) / (epsilon + vv), 0.0); + + // C: Medium contrast (which looks better at high radii), no division. Note that the + // contribution still falls off with radius^2, but we've adjusted the rate in a way that is + // more computationally efficient and happens to be aesthetically pleasing. + // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0); + + // D: Low contrast, no division operation + // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0); +} + + + +void main() { + + + // Pixel being shaded + ivec2 ssC = ivec2(gl_FragCoord.xy); + + // World space point being shaded + vec3 C = getPosition(ssC); + +/* if (C.z <= -camera_z_far*0.999) { + // We're on the skybox + visibility=1.0; + return; + }*/ + + //visibility=-C.z/camera_z_far; + //return; + + //vec3 n_C = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0; + + vec3 n_C = reconstructCSFaceNormal(C); + n_C = -n_C; + + + // Hash function used in the HPG12 AlchemyAO paper + float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10; + + // Reconstruct normals from positions. These will lead to 1-pixel black lines + // at depth discontinuities, however the blur will wipe those out so they are not visible + // in the final image. + + // Choose the screen-space sample radius + // proportional to the projected area of the sphere + float ssDiskRadius = -proj_scale * radius / C.z; + + float sum = 0.0; + for (int i = 0; i < NUM_SAMPLES; ++i) { + sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius,i, randomPatternRotationAngle); + } + + float A = max(0.0, 1.0 - sum * intensity_div_r6 * (5.0 / NUM_SAMPLES)); + +#ifdef ENABLE_RADIUS2 + + //go again for radius2 + randomPatternRotationAngle = (5 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 11; + + // Reconstruct normals from positions. These will lead to 1-pixel black lines + // at depth discontinuities, however the blur will wipe those out so they are not visible + // in the final image. + + // Choose the screen-space sample radius + // proportional to the projected area of the sphere + ssDiskRadius = -proj_scale * radius2 / C.z; + + sum = 0.0; + for (int i = 0; i < NUM_SAMPLES; ++i) { + sum += sampleAO(ssC, C, n_C, ssDiskRadius,radius2, i, randomPatternRotationAngle); + } + + A= min(A,max(0.0, 1.0 - sum * intensity_div_r62 * (5.0 / NUM_SAMPLES))); +#endif + // Bilateral box-filter over a quad for free, respecting depth edges + // (the difference that this makes is subtle) + if (abs(dFdx(C.z)) < 0.02) { + A -= dFdx(A) * ((ssC.x & 1) - 0.5); + } + if (abs(dFdy(C.z)) < 0.02) { + A -= dFdy(A) * ((ssC.y & 1) - 0.5); + } + + visibility = A; + +} + + + diff --git a/drivers/gles3/shaders/ssao_blur.glsl b/drivers/gles3/shaders/ssao_blur.glsl new file mode 100644 index 0000000000..31f3841a2a --- /dev/null +++ b/drivers/gles3/shaders/ssao_blur.glsl @@ -0,0 +1,113 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; + + +void main() { + + gl_Position = vertex_attrib; + gl_Position.z=1.0; +} + +[fragment] + + +uniform sampler2D source_ssao; //texunit:0 +uniform sampler2D source_depth; //texunit:1 + + +layout(location = 0) out float visibility; + + +////////////////////////////////////////////////////////////////////////////////////////////// +// Tunable Parameters: + +/** Increase to make depth edges crisper. Decrease to reduce flicker. */ +#define EDGE_SHARPNESS (1.0) + +/** Step in 2-pixel intervals since we already blurred against neighbors in the + first AO pass. This constant can be increased while R decreases to improve + performance at the expense of some dithering artifacts. + + Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was + unobjectionable after shading was applied but eliminated most temporal incoherence + from using small numbers of sample taps. + */ +#define SCALE (3) + +/** Filter radius in pixels. This will be multiplied by SCALE. */ +#define R (4) + + +////////////////////////////////////////////////////////////////////////////////////////////// + + +// Gaussian coefficients +const float gaussian[R + 1] = +// float[](0.356642, 0.239400, 0.072410, 0.009869); +// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 + float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 +// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 + +/** (1, 0) or (0, 1)*/ +uniform ivec2 axis; + +uniform float camera_z_far; +uniform float camera_z_near; + +void main() { + + ivec2 ssC = ivec2(gl_FragCoord.xy); + + float depth = texelFetch(source_depth, ssC, 0).r; + + depth = depth * 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)); + + float depth_divide = 1.0 / camera_z_far; + + depth*=depth_divide; + + //if (depth > camera_z_far*0.999) { + // discard;//skybox + //} + + float sum = texelFetch(source_ssao, ssC, 0).r; + + // Base weight for depth falloff. Increase this for more blurriness, + // decrease it for better edge discrimination + float BASE = gaussian[0]; + float totalWeight = BASE; + sum *= totalWeight; + + + for (int r = -R; r <= R; ++r) { + // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, + // so the IF statement has no runtime cost + if (r != 0) { + + ivec2 ppos = ssC + axis * (r * SCALE); + float value = texelFetch(source_ssao, ppos, 0).r; + float temp_depth = texelFetch(source_depth, ssC, 0).r; + + temp_depth = temp_depth * 2.0 - 1.0; + temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near)); + temp_depth *= depth_divide; + + // spatial domain: offset gaussian tap + float weight = 0.3 + gaussian[abs(r)]; + + // range domain (the "bilateral" weight). As depth difference increases, decrease weight. + weight *= max(0.0, 1.0 + - (EDGE_SHARPNESS * 2000.0) * abs(temp_depth - depth) + ); + + sum += value * weight; + totalWeight += weight; + } + } + + const float epsilon = 0.0001; + visibility = sum / (totalWeight + epsilon); +} diff --git a/drivers/gles3/shaders/ssao_minify.glsl b/drivers/gles3/shaders/ssao_minify.glsl new file mode 100644 index 0000000000..df9045c28a --- /dev/null +++ b/drivers/gles3/shaders/ssao_minify.glsl @@ -0,0 +1,55 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; + +void main() { + + gl_Position = vertex_attrib; +} + +[fragment] + + +#ifdef MINIFY_START + +#define SDEPTH_TYPE highp sampler2D +uniform float camera_z_far; +uniform float camera_z_near; + +#else + +#define SDEPTH_TYPE mediump usampler2D + +#endif + +uniform SDEPTH_TYPE source_depth; //texunit:0 + +uniform ivec2 from_size; +uniform int source_mipmap; + +layout(location = 0) out mediump uint depth; + +void main() { + + + ivec2 ssP = ivec2(gl_FragCoord.xy); + + // Rotated grid subsampling to avoid XY directional bias or Z precision bias while downsampling. + // On DX9, the bit-and can be implemented with floating-point modulo + +#ifdef MINIFY_START + float fdepth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r; + fdepth = fdepth * 2.0 - 1.0; + fdepth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - fdepth * (camera_z_far - camera_z_near)); + fdepth /= camera_z_far; + depth = uint(clamp(fdepth*65535,0.0,65535.0)); + +#else + depth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r; +#endif + + +} + + diff --git a/drivers/gles3/shaders/subsurf_scattering.glsl b/drivers/gles3/shaders/subsurf_scattering.glsl new file mode 100644 index 0000000000..eb329dbaed --- /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 sampler2D source_motion_ss; //texunit:1 +uniform sampler2D source_depth; //texunit:2 + +layout(location = 0) out vec4 frag_color; + +void main() { + + float strength = texture(source_motion_ss,uv_interp).a; + 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/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl new file mode 100644 index 0000000000..8f7e0c7be3 --- /dev/null +++ b/drivers/gles3/shaders/tonemap.glsl @@ -0,0 +1,263 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; +layout(location=4) in vec2 uv_in; + +out vec2 uv_interp; + + + +void main() { + + gl_Position = vertex_attrib; + uv_interp = uv_in; + +} + +[fragment] + + +in vec2 uv_interp; + +uniform highp sampler2D source; //texunit:0 + +uniform float exposure; +uniform float white; + +#ifdef USE_AUTO_EXPOSURE + +uniform highp sampler2D source_auto_exposure; //texunit:1 +uniform highp float auto_exposure_grey; + +#endif + +#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) + +uniform highp sampler2D source_glow; //texunit:2 +uniform highp float glow_intensity; + +#endif + +layout(location = 0) out vec4 frag_color; + +#ifdef USE_GLOW_FILTER_BICUBIC + +// w0, w1, w2, and w3 are the four cubic B-spline basis functions +float w0(float a) +{ + return (1.0/6.0)*(a*(a*(-a + 3.0) - 3.0) + 1.0); +} + +float w1(float a) +{ + return (1.0/6.0)*(a*a*(3.0*a - 6.0) + 4.0); +} + +float w2(float a) +{ + return (1.0/6.0)*(a*(a*(-3.0*a + 3.0) + 3.0) + 1.0); +} + +float w3(float a) +{ + return (1.0/6.0)*(a*a*a); +} + +// g0 and g1 are the two amplitude functions +float g0(float a) +{ + return w0(a) + w1(a); +} + +float g1(float a) +{ + return w2(a) + w3(a); +} + +// h0 and h1 are the two offset functions +float h0(float a) +{ + return -1.0 + w1(a) / (w0(a) + w1(a)); +} + +float h1(float a) +{ + return 1.0 + w3(a) / (w2(a) + w3(a)); +} + +uniform ivec2 glow_texture_size; + +vec4 texture2D_bicubic(sampler2D tex, vec2 uv,int p_lod) +{ + float lod=float(p_lod); + vec2 tex_size = vec2(glow_texture_size >> p_lod); + vec2 pixel_size =1.0/tex_size; + uv = uv*tex_size + 0.5; + vec2 iuv = floor( uv ); + vec2 fuv = fract( uv ); + + float g0x = g0(fuv.x); + float g1x = g1(fuv.x); + float h0x = h0(fuv.x); + float h1x = h1(fuv.x); + float h0y = h0(fuv.y); + float h1y = h1(fuv.y); + + vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - 0.5) * pixel_size; + vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - 0.5) * pixel_size; + vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - 0.5) * pixel_size; + vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - 0.5) * pixel_size; + + return g0(fuv.y) * (g0x * textureLod(tex, p0,lod) + + g1x * textureLod(tex, p1,lod)) + + g1(fuv.y) * (g0x * textureLod(tex, p2,lod) + + g1x * textureLod(tex, p3,lod)); +} + + + +#define GLOW_TEXTURE_SAMPLE(m_tex,m_uv,m_lod) texture2D_bicubic(m_tex,m_uv,m_lod) + +#else + +#define GLOW_TEXTURE_SAMPLE(m_tex,m_uv,m_lod) textureLod(m_tex,m_uv,float(m_lod)) + +#endif + + +void main() { + + ivec2 coord = ivec2(gl_FragCoord.xy); + vec3 color = texelFetch(source,coord,0).rgb; + + +#ifdef USE_AUTO_EXPOSURE + + color/=texelFetch(source_auto_exposure,ivec2(0,0),0).r/auto_exposure_grey; +#endif + + color*=exposure; + + +#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) + vec3 glow = vec3(0.0); + +#ifdef USE_GLOW_LEVEL1 + + glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,1).rgb; +#endif + +#ifdef USE_GLOW_LEVEL2 + glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,2).rgb; +#endif + +#ifdef USE_GLOW_LEVEL3 + glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,3).rgb; +#endif + +#ifdef USE_GLOW_LEVEL4 + glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,4).rgb; +#endif + +#ifdef USE_GLOW_LEVEL5 + glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,5).rgb; +#endif + +#ifdef USE_GLOW_LEVEL6 + glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,6).rgb; +#endif + +#ifdef USE_GLOW_LEVEL7 + glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,7).rgb; +#endif + + + glow *= glow_intensity; + + + +#ifdef USE_GLOW_REPLACE + + color.rgb = glow; + +#endif + +#ifdef USE_GLOW_SCREEN + + color.rgb = clamp((color.rgb + glow) - (color.rgb * glow), 0.0, 1.0); + +#endif + +#ifdef USE_GLOW_SOFTLIGHT + + { + + glow = (glow * 0.5) + 0.5; + color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r))); + color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g))); + color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b))); + } + +#endif + +#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) + color.rgb+=glow; +#endif + + +#endif + + +#ifdef USE_REINDHART_TONEMAPPER + + { + color.rgb = ( color.rgb * ( 1.0 + ( color.rgb / ( white) ) ) ) / ( 1.0 + color.rgb ); + + } +#endif + +#ifdef USE_FILMIC_TONEMAPPER + + { + + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + float W = 11.2; + + vec3 coltn = ((color.rgb*(A*color.rgb+C*B)+D*E)/(color.rgb*(A*color.rgb+B)+D*F))-E/F; + float whitetn = ((white*(A*white+C*B)+D*E)/(white*(A*white+B)+D*F))-E/F; + + color.rgb=coltn/whitetn; + + } +#endif + +#ifdef USE_ACES_TONEMAPPER + + { + float a = 2.51f; + float b = 0.03f; + float c = 2.43f; + float d = 0.59f; + float e = 0.14f; + color.rgb = clamp((color.rgb*(a*color.rgb+b))/(color.rgb*(c*color.rgb+d)+e),vec3(0.0),vec3(1.0)); + } + +#endif + + //regular Linear -> SRGB conversion + vec3 a = vec3(0.055); + color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308))); + + + + + frag_color=vec4(color.rgb,1.0); +} + + |