diff options
Diffstat (limited to 'servers/visual/rasterizer_rd/shaders')
-rw-r--r-- | servers/visual/rasterizer_rd/shaders/SCsub | 8 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/shaders/blur.glsl | 274 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/shaders/blur_inc.glsl | 35 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/shaders/canvas.glsl | 605 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl | 40 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl | 145 |
6 files changed, 1107 insertions, 0 deletions
diff --git a/servers/visual/rasterizer_rd/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub new file mode 100644 index 0000000000..a8e1dafb47 --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/SCsub @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +Import('env') + +if 'RD_GLSL' in env['BUILDERS']: + env.RD_GLSL('canvas.glsl'); + env.RD_GLSL('canvas_occlusion.glsl'); + env.RD_GLSL('blur.glsl'); diff --git a/servers/visual/rasterizer_rd/shaders/blur.glsl b/servers/visual/rasterizer_rd/shaders/blur.glsl new file mode 100644 index 0000000000..830d4d7d94 --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/blur.glsl @@ -0,0 +1,274 @@ +/* clang-format off */ +[vertex] +/* clang-format on */ + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +#include "blur_inc.glsl" + +layout(location =0) out vec2 uv_interp; + +void main() { + + vec2 base_arr[4] = vec2[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0)); + uv_interp = base_arr[gl_VertexIndex]; + + if (bool(blur.flags&FLAG_USE_BLUR_SECTION)) { + uv_interp = blur.section.xy + uv_interp * blur.section.zw; + } + + gl_Position = vec4( uv_interp *2.0 - 1.0, 0.0, 1.0); + +} + +/* clang-format off */ +[fragment] +/* clang-format on */ + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +#include "blur_inc.glsl" + +layout(location =0) in vec2 uv_interp; + +layout( set=0, binding=0 ) uniform sampler2D source_color; + +#ifdef MODE_SSAO_MERGE +layout( set=1, binding=0 ) uniform sampler2D source_ssao; +#endif + +#ifdef GLOW_USE_AUTO_EXPOSURE +layout( set=1, binding=0 ) uniform sampler2D source_auto_exposure; +#endif + + +layout(location = 0) out vec4 frag_color; + +//DOF +#if defined(MODE_DOF_FAR_BLUR) || defined(MODE_DOF_NEAR_BLUR) + +layout( set=1, binding=0 ) uniform sampler2D dof_source_depth; + +#ifdef DOF_NEAR_BLUR_MERGE +layout( set=2, binding=0 ) uniform sampler2D source_dof_original; +#endif + +#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 + +#endif + + +void main() { + +#ifdef MODE_GAUSSIAN_BLUR + + //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect + + if (bool(blur.flags&FLAG_HORIZONTAL)) { + + vec2 pix_size = blur.pixel_size; + pix_size *= 0.5; //reading from larger buffer, so use more samples + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.214607; + color += texture(source_color, uv_interp + vec2(1.0, 0.0) * pix_size) * 0.189879; + color += texture(source_color, uv_interp + vec2(2.0, 0.0) * pix_size) * 0.131514; + color += texture(source_color, uv_interp + vec2(3.0, 0.0) * pix_size) * 0.071303; + color += texture(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size) * 0.189879; + color += texture(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size) * 0.131514; + color += texture(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size) * 0.071303; + frag_color = color; + } else { + + vec2 pix_size = blur.pixel_size; + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.38774; + color += texture(source_color, uv_interp + vec2(0.0, 1.0) * pix_size) * 0.24477; + color += texture(source_color, uv_interp + vec2(0.0, 2.0) * pix_size) * 0.06136; + color += texture(source_color, uv_interp + vec2(0.0, -1.0) * pix_size) * 0.24477; + color += texture(source_color, uv_interp + vec2(0.0, -2.0) * pix_size) * 0.06136; + frag_color = color; + } +#endif + + + +#ifdef MODE_GAUSSIAN_GLOW + + //Glow uses larger sigma 1 for a more rounded blur effect + + if (bool(blur.flags&FLAG_HORIZONTAL)) { + + vec2 pix_size = blur.pixel_size; + pix_size *= 0.5; //reading from larger buffer, so use more samples + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.174938; + color += texture(source_color, uv_interp + vec2(1.0, 0.0) * pix_size) * 0.165569; + color += texture(source_color, uv_interp + vec2(2.0, 0.0) * pix_size) * 0.140367; + color += texture(source_color, uv_interp + vec2(3.0, 0.0) * pix_size) * 0.106595; + color += texture(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size) * 0.165569; + color += texture(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size) * 0.140367; + color += texture(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size) * 0.106595; + color *= blur.glow_strength; + frag_color = color; + } else { + + vec2 pix_size = blur.pixel_size; + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.288713; + color += texture(source_color, uv_interp + vec2(0.0, 1.0) * pix_size) * 0.233062; + color += texture(source_color, uv_interp + vec2(0.0, 2.0) * pix_size) * 0.122581; + color += texture(source_color, uv_interp + vec2(0.0, -1.0) * pix_size) * 0.233062; + color += texture(source_color, uv_interp + vec2(0.0, -2.0) * pix_size) * 0.122581; + color *= blur.glow_strength; + frag_color = color; + } + + + if (bool(blur.flags&FLAG_GLOW_FIRST_PASS)) { +#ifdef GLOW_USE_AUTO_EXPOSURE + + frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_grey; +#endif + frag_color *= blur.glow_exposure; + + float luminance = max(frag_color.r, max(frag_color.g, frag_color.b)); + float feedback = max(smoothstep(blur.glow_hdr_threshold, blur.glow_hdr_threshold + blur.glow_hdr_scale, luminance), blur.glow_bloom); + + frag_color = min(frag_color * feedback, vec4(blur.glow_luminance_cap)); + } + + +#endif + +#ifdef MODE_DOF_FAR_BLUR + + vec4 color_accum = vec4(0.0); + + float depth = texture(dof_source_depth, uv_interp, 0.0).r; + depth = depth * 2.0 - 1.0; + + if (bool(blur.flags&FLAG_USE_ORTHOGONAL_PROJECTION)) { + depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; + } else { + depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near)); + } + + float amount = smoothstep(blur.dof_begin, blur.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 + blur.dof_dir * float(int_ofs) * amount * blur.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; + + if (bool(blur.flags&FLAG_USE_ORTHOGONAL_PROJECTION)) { + + tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; + } else { + tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); + } + + float tap_amount = mix(smoothstep(blur.dof_begin, blur.dof_end, tap_depth), 1.0, int_ofs == 0); + tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect + + vec4 tap_color = texture(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 MODE_DOF_NEAR_BLUR + + vec4 color_accum = vec4(0.0); + + float max_accum = 0.0; + + for (int i = 0; i < dof_kernel_size; i++) { + + int int_ofs = i - dof_kernel_from; + vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * blur.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 = texture(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; + if (bool(blur.flags&FLAG_USE_ORTHOGONAL_PROJECTION)) { + + tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; + } else { + tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); + } + float tap_amount = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth); + tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect + + if (bool(blur.flags&FLAG_DOF_NEAR_FIRST_TAP)) { + tap_color.a = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth); + } + + 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 = texture(source_dof_original, uv_interp, 0.0); + color_accum = mix(original, color_accum, color_accum.a); + } +#endif + + if (bool(blur.flags&FLAG_DOF_NEAR_FIRST_TAP)) { + frag_color = color_accum; + } +#endif + +#ifdef MODE_SIMPLE_COPY + vec4 color = texture(source_color, uv_interp, 0.0); + frag_color = color; +#endif + +#ifdef MODE_SSAO_MERGE + vec4 color = texture(source_color, uv_interp, 0.0); + float ssao = texture(source_ssao, uv_interp, 0.0).r; + frag_color = vec4(mix(color.rgb, color.rgb * mix(blur.ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0); +#endif +} diff --git a/servers/visual/rasterizer_rd/shaders/blur_inc.glsl b/servers/visual/rasterizer_rd/shaders/blur_inc.glsl new file mode 100644 index 0000000000..ea932130aa --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/blur_inc.glsl @@ -0,0 +1,35 @@ +#define FLAG_HORIZONTAL (1<<0) +#define FLAG_USE_BLUR_SECTION (1<<1) +#define FLAG_USE_ORTHOGONAL_PROJECTION (1<<2) +#define FLAG_DOF_NEAR_FIRST_TAP (1<<3) +#define FLAG_GLOW_FIRST_PASS (1<<4) + +layout(push_constant, binding = 1, std430) uniform Blur { + vec4 section; + vec2 pixel_size; + uint flags; + uint pad; + //glow + float glow_strength; + float glow_bloom; + float glow_hdr_threshold; + float glow_hdr_scale; + float glow_exposure; + float glow_white; + float glow_luminance_cap; + float glow_auto_exposure_grey; + //dof + float dof_begin; + float dof_end; + float dof_radius; + float dof_pad; + + vec2 dof_dir; + float camera_z_far; + float camera_z_near; + + vec4 ssao_color; + + + +} blur; diff --git a/servers/visual/rasterizer_rd/shaders/canvas.glsl b/servers/visual/rasterizer_rd/shaders/canvas.glsl new file mode 100644 index 0000000000..63d2251465 --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/canvas.glsl @@ -0,0 +1,605 @@ +/* clang-format off */ +[vertex] +/* clang-format on */ + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +#ifdef USE_ATTRIBUTES +layout(location = 0) in vec2 vertex_attrib; +layout(location = 3) in vec4 color_attrib; +layout(location = 4) in vec2 uv_attrib; + +layout(location = 6) in uvec4 bone_indices_attrib; +layout(location = 7) in vec4 bone_weights_attrib; + +#endif + +#include "canvas_uniforms_inc.glsl" + + +layout(location=0) out vec2 uv_interp; +layout(location=1) out vec4 color_interp; +layout(location=2) out vec2 vertex_interp; + +#ifdef USE_NINEPATCH + +layout(location=3) out vec2 pixel_size_interp; + +#endif + +#ifdef USE_MATERIAL_UNIFORMS +layout(set = 1, binding = 1, std140) uniform MaterialUniforms { +/* clang-format off */ +MATERIAL_UNIFORMS +/* clang-format on */ +} material; +#endif + +/* clang-format off */ +VERTEX_SHADER_GLOBALS +/* clang-format on */ + + +void main() { + + vec4 instance_custom = vec4(0.0); +#ifdef USE_PRIMITIVE + +//weird bug, +//this works + vec2 vertex; + vec2 uv; + vec4 color; + + if (gl_VertexIndex==0) { + vertex = draw_data.points[0]; + uv = draw_data.uvs[0]; + color = vec4(unpackHalf2x16(draw_data.colors[0]),unpackHalf2x16(draw_data.colors[1])); + } else if (gl_VertexIndex==1) { + vertex = draw_data.points[1]; + uv = draw_data.uvs[1]; + color = vec4(unpackHalf2x16(draw_data.colors[2]),unpackHalf2x16(draw_data.colors[3])); + } else { + vertex = draw_data.points[2]; + uv = draw_data.uvs[2]; + color = vec4(unpackHalf2x16(draw_data.colors[4]),unpackHalf2x16(draw_data.colors[5])); + } + uvec4 bone_indices = uvec4(0,0,0,0); + vec4 bone_weights = vec4(0,0,0,0); + +#elif defined(USE_ATTRIBUTES) + + vec2 vertex = vertex_attrib; + vec4 color = color_attrib; + vec2 uv = uv_attrib; + + uvec4 bone_indices = bone_indices_attrib; + vec4 bone_weights = bone_weights_attrib; +#else + + vec2 vertex_base_arr[4] = vec2[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0)); + vec2 vertex_base = vertex_base_arr[gl_VertexIndex]; + + vec2 uv = draw_data.src_rect.xy + abs(draw_data.src_rect.zw) * ((draw_data.flags&FLAGS_TRANSPOSE_RECT)!=0 ? vertex_base.yx : vertex_base.xy); + vec4 color = draw_data.modulation; + vec2 vertex = draw_data.dst_rect.xy + abs(draw_data.dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data.src_rect.zw, vec2(0.0, 0.0))); + uvec4 bone_indices = uvec4(0,0,0,0); + vec4 bone_weights = vec4(0,0,0,0); + +#endif + + mat4 world_matrix = mat4(vec4(draw_data.world_x,0.0,0.0),vec4(draw_data.world_y,0.0,0.0),vec4(0.0,0.0,1.0,0.0),vec4(draw_data.world_ofs,0.0,1.0)); +#if 0 + + if (draw_data.flags&FLAGS_INSTANCING_ENABLED) { + + uint offset = draw_data.flags&FLAGS_INSTANCING_STRIDE_MASK; + offset *= gl_InstanceIndex; + mat4 instance_xform = mat4( + vec4( texelFetch(instancing_buffer,offset+0),texelFetch(instancing_buffer,offset+1),0.0,texelFetch(instancing_buffer,offset+3) ), + vec4( texelFetch(instancing_buffer,offset+4),texelFetch(instancing_buffer,offset+5),0.0,texelFetch(instancing_buffer,offset+7) ), + vec4( 0.0,0.0,1.0,0.0), + vec4( 0.0,0.0,0.0,1.0 ) ); + offset+=8; + if ( draw_data.flags&FLAGS_INSTANCING_HAS_COLORS ) { + vec4 instance_color; + if (draw_data.flags&FLAGS_INSTANCING_COLOR_8_BIT ) { + uint bits = floatBitsToUint(texelFetch(instancing_buffer,offset)); + instance_color = unpackUnorm4x8(bits); + offset+=1; + } else { + instance_color = vec4(texelFetch(instancing_buffer,offset+0),texelFetch(instancing_buffer,offset+1),texelFetch(instancing_buffer,offset+2),texelFetch(instancing_buffer,offset+3)); + offser+=4; + } + + color*=instance_color; + } + if ( draw_data.flags&FLAGS_INSTANCING_HAS_CUSTOM_DATA ) { + if (draw_data.flags&FLAGS_INSTANCING_CUSTOM_DATA_8_BIT ) { + uint bits = floatBitsToUint(texelFetch(instancing_buffer,offset)); + instance_custom = unpackUnorm4x8(bits); + } else { + instance_custom = vec4(texelFetch(instancing_buffer,offset+0),texelFetch(instancing_buffer,offset+1),texelFetch(instancing_buffer,offset+2),texelFetch(instancing_buffer,offset+3)); + } + } + + } + +#endif + +#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) + if (bool(draw_data.flags&FLAGS_USING_PARTICLES)) { + //scale by texture size + vertex /= draw_data.color_texture_pixel_size; + } +#endif + +#ifdef USE_POINT_SIZE + float point_size = 1.0; +#endif + { + /* clang-format off */ +VERTEX_SHADER_CODE + /* clang-format on */ + } + + + +#ifdef USE_NINEPATCH + pixel_size_interp = abs(draw_data.dst_rect.zw) * vertex_base; +#endif + +#if !defined(SKIP_TRANSFORM_USED) + vertex = (world_matrix * vec4(vertex,0.0,1.0)).xy; +#endif + + color_interp = color; + + if (bool(draw_data.flags&FLAGS_USE_PIXEL_SNAP)) { + + vertex = floor(vertex + 0.5); + // precision issue on some hardware creates artifacts within texture + // offset uv by a small amount to avoid + uv += 1e-5; + } + +#ifdef USE_ATTRIBUTES +#if 0 + if (bool(draw_data.flags&FLAGS_USE_SKELETON) && bone_weights != vec4(0.0)) { //must be a valid bone + //skeleton transform + + ivec4 bone_indicesi = ivec4(bone_indices); + + uvec2 tex_ofs = bone_indicesi.x *2; + + mat2x4 m; + m = mat2x4( + texelFetch(skeleton_buffer, tex_ofs+0), + texelFetch(skeleton_buffer, tex_ofs+1) ) * + bone_weights.x; + + tex_ofs = bone_indicesi.y * 2; + + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs+0), + texelFetch(skeleton_buffer, tex_ofs+1) ) * + bone_weights.y; + + tex_ofs = bone_indicesi.z * 2; + + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs+0), + texelFetch(skeleton_buffer, tex_ofs+1) ) * + bone_weights.z; + + tex_ofs = bone_indicesi.w * 2; + + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs+0), + texelFetch(skeleton_buffer, tex_ofs+1) ) * + bone_weights.w; + + mat4 bone_matrix = skeleton_data.skeleton_transform * transpose(mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))) * skeleton_data.skeleton_transform_inverse; + + //outvec = bone_matrix * outvec; + } +#endif +#endif + + + vertex = (canvas_data.canvas_transform * vec4(vertex,0.0,1.0)).xy; + + vertex_interp = vertex; + uv_interp = uv; + + gl_Position = canvas_data.screen_transform * vec4(vertex,0.0,1.0); + +#ifdef USE_POINT_SIZE + gl_PointSize=point_size; +#endif + +} + +/* clang-format off */ +[fragment] + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +#include "canvas_uniforms_inc.glsl" + +layout(location=0) in vec2 uv_interp; +layout(location=1) in vec4 color_interp; +layout(location=2) in vec2 vertex_interp; + +#ifdef USE_NINEPATCH + +layout(location=3) in vec2 pixel_size_interp; + +#endif + +layout(location = 0) out vec4 frag_color; + +#ifdef USE_MATERIAL_UNIFORMS +layout(set = 1, binding = 1, std140) uniform MaterialUniforms { +/* clang-format off */ +MATERIAL_UNIFORMS +/* clang-format on */ +} material; +#endif + + +/* clang-format off */ +FRAGMENT_SHADER_GLOBALS +/* clang-format on */ + +#ifdef LIGHT_SHADER_CODE_USED + +vec4 light_compute( + vec3 light_vertex, + vec3 light_position, + vec3 normal, + vec4 light_color, + float light_energy, + vec4 specular_shininess, + inout vec4 shadow_modulate, + vec2 screen_uv, + vec2 uv, + vec4 color) { + + vec4 light = vec4(0.0); + /* clang-format off */ +LIGHT_SHADER_CODE + /* clang-format on */ + return light; +} + +#endif + +#ifdef USE_NINEPATCH + +float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) { + + float tex_size = 1.0 / tex_pixel_size; + + if (pixel < margin_begin) { + return pixel * tex_pixel_size; + } else if (pixel >= draw_size - margin_end) { + return (tex_size - (draw_size - pixel)) * tex_pixel_size; + } else { + if (!bool(draw_data.flags&FLAGS_NINEPACH_DRAW_CENTER)) { + draw_center--; + } + + if (np_repeat == 0) { //stretch + //convert to ratio + float ratio = (pixel - margin_begin) / (draw_size - margin_begin - margin_end); + //scale to source texture + return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size; + } else if (np_repeat == 1) { //tile + //convert to ratio + float ofs = mod((pixel - margin_begin), tex_size - margin_begin - margin_end); + //scale to source texture + return (margin_begin + ofs) * tex_pixel_size; + } else if (np_repeat == 2) { //tile fit + //convert to ratio + float src_area = draw_size - margin_begin - margin_end; + float dst_area = tex_size - margin_begin - margin_end; + float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5)); + + //convert to ratio + float ratio = (pixel - margin_begin) / src_area; + ratio = mod(ratio * scale, 1.0); + return (margin_begin + ratio * dst_area) * tex_pixel_size; + } + } +} + + +#endif + +void main() { + + vec4 color = color_interp; + vec2 uv = uv_interp; + vec2 vertex = vertex_interp; + +#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) + +#ifdef USE_NINEPATCH + + int draw_center = 2; + uv = vec2( + map_ninepatch_axis(pixel_size_interp.x, abs(draw_data.dst_rect.z), draw_data.color_texture_pixel_size.x, draw_data.ninepatch_margins.x, draw_data.ninepatch_margins.z, int(draw_data.flags>>FLAGS_NINEPATCH_H_MODE_SHIFT)&0x3, draw_center), + map_ninepatch_axis(pixel_size_interp.y, abs(draw_data.dst_rect.w), draw_data.color_texture_pixel_size.y, draw_data.ninepatch_margins.y, draw_data.ninepatch_margins.w, int(draw_data.flags>>FLAGS_NINEPATCH_V_MODE_SHIFT)&0x3, draw_center)); + + if (draw_center == 0) { + color.a = 0.0; + } + + uv = uv * draw_data.src_rect.zw + draw_data.src_rect.xy; //apply region if needed + +#endif + if (bool(draw_data.flags&FLAGS_CLIP_RECT_UV)) { + + uv = clamp(uv, draw_data.src_rect.xy, draw_data.src_rect.xy + abs(draw_data.src_rect.zw)); + } + +#endif + + color *= texture(sampler2D(color_texture,texture_sampler), uv); + + uint light_count = (draw_data.flags>>FLAGS_LIGHT_COUNT_SHIFT)&0xF; //max 16 lights + + + vec3 normal; + +#if defined(NORMAL_USED) + + bool normal_used = true; +#else + bool normal_used = false; +#endif + + + if (normal_used || (light_count > 0 && bool(draw_data.flags&FLAGS_DEFAULT_NORMAL_MAP_USED))) { + normal.xy = texture(sampler2D(normal_texture,texture_sampler), uv).xy * vec2(2.0,-2.0) - vec2(1.0,-1.0); + normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); + normal_used = true; + } else { + normal = vec3(0.0, 0.0, 1.0); + } + + vec4 specular_shininess; + +#if defined(SPECULAR_SHININESS_USED) + + bool specular_shininess_used = true; +#else + bool specular_shininess_used = false; +#endif + + if (specular_shininess_used || (light_count > 0 && normal_used && bool(draw_data.flags&FLAGS_DEFAULT_SPECULAR_MAP_USED))) { + specular_shininess = texture(sampler2D(specular_texture,texture_sampler ), uv); + specular_shininess *= unpackUnorm4x8(draw_data.specular_shininess); + specular_shininess_used=true; + } else { + specular_shininess = vec4(1.0); + } + + +#if defined(SCREEN_UV_USED) + vec2 screen_uv = gl_FragCoord.xy * canvas_data.screen_pixel_size; +#else + vec2 screen_uv = vec2(0.0); +#endif + + vec3 light_vertex = vec3(vertex,0.0); + vec2 shadow_vertex = vertex; + + { + float normal_depth = 1.0; + +#if defined(NORMALMAP_USED) + vec3 normal_map = vec3(0.0, 0.0, 1.0); + normal_used = true; +#endif + + /* clang-format off */ + +FRAGMENT_SHADER_CODE + + /* clang-format on */ + +#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 + } + + if (normal_used) { + //convert by item transform + normal.xy = mat2(normalize(draw_data.world_x), normalize(draw_data.world_y)) * normal.xy; + //convert by canvas transform + normal = normalize((canvas_data.canvas_normal_transform * vec4(normal,0.0)).xyz); + } + + + vec4 base_color=color; + if (bool(draw_data.flags&FLAGS_USING_LIGHT_MASK)) { + color=vec4(0.0); //inivisible by default due to using light mask + } + + color*=canvas_data.canvas_modulation; +#ifdef USE_LIGHTING + for(uint i=0;i<MAX_LIGHT_TEXTURES;i++) { + if (i>=light_count) { + break; + } + uint light_base; + if (i<8) { + if (i<4) { + light_base=draw_data.lights[0]; + } else { + light_base=draw_data.lights[1]; + } + } else { + if (i<12) { + light_base=draw_data.lights[2]; + } else { + light_base=draw_data.lights[3]; + } + } + light_base>>=(i&3)*8; + light_base&=0xFF; + + vec2 tex_uv = (vec4(vertex,0.0,1.0) * mat4(light_array.data[light_base].matrix[0],light_array.data[light_base].matrix[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. + vec4 light_color = texture(sampler2D(light_textures[i],texture_sampler),tex_uv); + vec4 light_base_color = light_array.data[light_base].color; + +#ifdef LIGHT_SHADER_CODE_USED + + vec4 shadow_modulate = vec4(1.0); + vec3 light_position = vec3(light_array.data[light_base].position,light_array.data[light_base].height); + + light_color.rgb*=light_base_color.rgb; + light_color = light_compute(light_vertex,light_position,normal,light_color,light_base_color.a,specular_shininess,shadow_modulate,screen_uv,color,uv); +#else + + + light_color.rgb*=light_base_color.rgb*light_base_color.a; + + if (normal_used) { + + vec3 light_pos = vec3(light_array.data[light_base].position,light_array.data[light_base].height); + vec3 pos = light_vertex; + vec3 light_vec = normalize(light_pos-pos); + float cNdotL = max(0.0,dot(normal,light_vec)); + + if (specular_shininess_used) { + //blinn + vec3 view = vec3(0.0,0.0,1.0);// not great but good enough + vec3 half_vec = normalize(view+light_vec); + + float cNdotV = max(dot(normal, view), 0.0); + float cNdotH = max(dot(normal, half_vec), 0.0); + float cVdotH = max(dot(view, half_vec), 0.0); + float cLdotH = max(dot(light_vec, half_vec), 0.0); + float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); + + light_color.rgb = specular_shininess.rgb * light_base_color.rgb * s + light_color.rgb * cNdotL; + } else { + light_color.rgb *= cNdotL; + } + + } +#endif + if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) { + //if outside the light texture, light color is zero + light_color.a = 0.0; + } + + if (bool(light_array.data[light_base].flags&LIGHT_FLAGS_HAS_SHADOW)) { + + vec2 shadow_pos = (vec4(shadow_vertex,0.0,1.0) * mat4(light_array.data[light_base].shadow_matrix[0],light_array.data[light_base].shadow_matrix[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. + + vec2 pos_norm = normalize(shadow_pos); + vec2 pos_abs = abs(pos_norm); + vec2 pos_box = pos_norm / max(pos_abs.x,pos_abs.y); + vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476,-0.7071067811865476),vec2(0.7071067811865476,0.7071067811865476)); //is there a faster way to 45 degrees rot? + float tex_ofs; + float distance; + if (pos_rot.y>0) { + if (pos_rot.x>0) { + tex_ofs=pos_box.y*0.125+0.125; + distance=shadow_pos.x; + } else { + tex_ofs=pos_box.x*-0.125+(0.25+0.125); + distance=shadow_pos.y; + } + } else { + if (pos_rot.x<0) { + tex_ofs=pos_box.y*-0.125+(0.5+0.125); + distance=-shadow_pos.x; + } else { + tex_ofs=pos_box.x*0.125+(0.75+0.125); + distance=-shadow_pos.y; + } + } + + //float distance = length(shadow_pos); + float shadow; + uint shadow_mode = light_array.data[light_base].flags&LIGHT_FLAGS_FILTER_MASK; + + vec4 shadow_uv = vec4(tex_ofs,0.0,distance,1.0); + + if (shadow_mode==LIGHT_FLAGS_SHADOW_NEAREST) { + shadow = textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv).x; + } else if (shadow_mode==LIGHT_FLAGS_SHADOW_PCF5) { + vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size,0.0,0.0,0.0); + shadow = 0.0; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv-shadow_pixel_size*2.0).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv-shadow_pixel_size).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv+shadow_pixel_size).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv+shadow_pixel_size*2.0).x; + shadow/=5.0; + } else { //PCF13 + vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size,0.0,0.0,0.0); + shadow = 0.0; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv-shadow_pixel_size*6.0).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv-shadow_pixel_size*5.0).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv-shadow_pixel_size*4.0).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv-shadow_pixel_size*3.0).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv-shadow_pixel_size*2.0).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv-shadow_pixel_size).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv+shadow_pixel_size).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv+shadow_pixel_size*2.0).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv+shadow_pixel_size*3.0).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv+shadow_pixel_size*4.0).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv+shadow_pixel_size*5.0).x; + shadow += textureProj(sampler2DShadow(shadow_textures[i],shadow_sampler),shadow_uv+shadow_pixel_size*6.0).x; + shadow/=13.0; + } + + vec4 shadow_color = light_array.data[light_base].shadow_color; +#ifdef LIGHT_SHADER_CODE_USED + shadow_color*=shadow_modulate; +#endif + light_color = mix(light_color,shadow_color,shadow); + + } + + uint blend_mode = light_array.data[light_base].flags&LIGHT_FLAGS_BLEND_MASK; + + switch(blend_mode) { + case LIGHT_FLAGS_BLEND_MODE_ADD: { + color.rgb+=light_color.rgb*light_color.a; + } break; + case LIGHT_FLAGS_BLEND_MODE_SUB: { + color.rgb-=light_color.rgb*light_color.a; + } break; + case LIGHT_FLAGS_BLEND_MODE_MIX: { + color.rgb=mix(color.rgb,light_color.rgb,light_color.a); + } break; + case LIGHT_FLAGS_BLEND_MODE_MASK: { + light_color.a*=base_color.a; + color.rgb=mix(color.rgb,light_color.rgb,light_color.a); + } break; + } + } +#endif + + frag_color = color; + +} diff --git a/servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl b/servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl new file mode 100644 index 0000000000..01e87411d3 --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl @@ -0,0 +1,40 @@ +/* clang-format off */ +[vertex] +/* clang-format on */ + +#version 450 + +layout(location = 0) in highp vec3 vertex; + +layout(push_constant, binding = 0, std430) uniform Constants { + + mat4 projection; + mat2x4 modelview; + vec2 direction; + vec2 pad; +} constants; + +layout(location = 0) out highp float depth; + +void main() { + + highp vec4 vtx = vec4(vertex, 1.0) * mat4(constants.modelview[0],constants.modelview[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0)); + depth = dot(constants.direction,vtx.xy); + + gl_Position = constants.projection * vtx; + +} + +/* clang-format off */ +[fragment] +/* clang-format on */ + +#version 450 + +layout(location = 0) in highp float depth; +layout(location = 0) out highp float distance_buf; + +void main() { + + distance_buf=depth; +} diff --git a/servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl new file mode 100644 index 0000000000..400c13ba68 --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl @@ -0,0 +1,145 @@ + + + +#define M_PI 3.14159265359 + +#define FLAGS_INSTANCING_STRIDE_MASK 0xF +#define FLAGS_INSTANCING_ENABLED (1<<4) +#define FLAGS_INSTANCING_HAS_COLORS (1 << 5) +#define FLAGS_INSTANCING_COLOR_8BIT (1 << 6) +#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 7) +#define FLAGS_INSTANCING_CUSTOM_DATA_8_BIT (1 << 8) + +#define FLAGS_CLIP_RECT_UV (1 << 9) +#define FLAGS_TRANSPOSE_RECT (1 << 10) +#define FLAGS_USING_LIGHT_MASK (1 << 11) +#define FLAGS_NINEPACH_DRAW_CENTER (1 << 12) +#define FLAGS_USING_PARTICLES (1 << 13) +#define FLAGS_USE_PIXEL_SNAP (1 << 14) + +#define FLAGS_NINEPATCH_H_MODE_SHIFT 16 +#define FLAGS_NINEPATCH_V_MODE_SHIFT 18 + +#define FLAGS_LIGHT_COUNT_SHIFT 20 + +#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26) +#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27) + +// In vulkan, sets should always be ordered using the following logic: +// Lower Sets: Sets that change format and layout less often +// Higher sets: Sets that change format and layout very often +// This is because changing a set for another with a different layout or format, +// invalidates all the upper ones. + +/* SET0: Draw Primitive */ + +layout(push_constant, binding = 0, std430) uniform DrawData { + vec2 world_x; + vec2 world_y; + vec2 world_ofs; + uint flags; + uint specular_shininess; +#ifdef USE_PRIMITIVE + vec2 points[3]; + vec2 uvs[3]; + uint colors[6]; +#else + vec4 modulation; + vec4 ninepatch_margins; + vec4 dst_rect; //for built-in rect and UV + vec4 src_rect; + vec2 pad; + +#endif + vec2 color_texture_pixel_size; + uint lights[4]; + +} draw_data; + +// The values passed per draw primitives are cached within it + +layout(set = 0, binding = 1) uniform texture2D color_texture; +layout(set = 0, binding = 2) uniform texture2D normal_texture; +layout(set = 0, binding = 3) uniform texture2D specular_texture; +layout(set = 0, binding = 4) uniform sampler texture_sampler; + +layout(set = 0, binding = 5) uniform textureBuffer instancing_buffer; + +/* SET1: Is reserved for the material */ + + +#ifdef USE_MATERIAL_SAMPLERS + +layout(set = 1, binding = 0) uniform sampler material_samplers[12]; + +#endif + +/* SET2: Canvas Item State (including lighting) */ + + +layout(set = 2, binding = 0, std140) uniform CanvasData { + mat4 canvas_transform; + mat4 screen_transform; + mat4 canvas_normal_transform; + vec4 canvas_modulation; + vec2 screen_pixel_size; + float time; + float time_pad; + //uint light_count; +} canvas_data; + +layout(set = 2, binding = 1) uniform textureBuffer skeleton_buffer; + +layout(set = 2, binding = 2, std140) uniform SkeletonData { + mat4 skeleton_transform; //in world coordinates + mat4 skeleton_transform_inverse; +} skeleton_data; + + +#ifdef USE_LIGHTING + +#define LIGHT_FLAGS_BLEND_MASK (3<<16) +#define LIGHT_FLAGS_BLEND_MODE_ADD (0<<16) +#define LIGHT_FLAGS_BLEND_MODE_SUB (1<<16) +#define LIGHT_FLAGS_BLEND_MODE_MIX (2<<16) +#define LIGHT_FLAGS_BLEND_MODE_MASK (3<<16) +#define LIGHT_FLAGS_HAS_SHADOW (1<<20) +#define LIGHT_FLAGS_FILTER_SHIFT 22 +#define LIGHT_FLAGS_FILTER_MASK (3<<22) +#define LIGHT_FLAGS_SHADOW_NEAREST (0<<22) +#define LIGHT_FLAGS_SHADOW_PCF5 (1<<22) +#define LIGHT_FLAGS_SHADOW_PCF13 (2<<22) + + +struct Light { + mat2x4 matrix; //light to texture coordinate matrix (transposed) + mat2x4 shadow_matrix; //light to shadow coordinate matrix (transposed) + vec4 color; + vec4 shadow_color; + vec2 position; + uint flags; //index to light texture + float height; + float shadow_pixel_size; + float pad0; + float pad1; + float pad2; +}; + +layout(set = 2, binding = 3, std140) uniform LightData { + Light data[MAX_LIGHTS]; +} light_array; + +layout(set = 2, binding = 4) uniform texture2D light_textures[MAX_LIGHT_TEXTURES]; +layout(set = 2, binding = 5) uniform texture2D shadow_textures[MAX_LIGHT_TEXTURES]; + +layout(set = 2, binding = 6) uniform sampler shadow_sampler; + +#endif + +/* SET3: Render Target Data */ + +#ifdef SCREEN_TEXTURE_USED + +layout(set = 3, binding = 0) uniform texture2D screen_texture; + +#endif |