summaryrefslogtreecommitdiff
path: root/servers/visual/rasterizer_rd/shaders
diff options
context:
space:
mode:
Diffstat (limited to 'servers/visual/rasterizer_rd/shaders')
-rw-r--r--servers/visual/rasterizer_rd/shaders/SCsub8
-rw-r--r--servers/visual/rasterizer_rd/shaders/blur.glsl274
-rw-r--r--servers/visual/rasterizer_rd/shaders/blur_inc.glsl35
-rw-r--r--servers/visual/rasterizer_rd/shaders/canvas.glsl605
-rw-r--r--servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl40
-rw-r--r--servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl145
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