summaryrefslogtreecommitdiff
path: root/drivers/gles3/shaders
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gles3/shaders')
-rw-r--r--drivers/gles3/shaders/SCsub3
-rw-r--r--drivers/gles3/shaders/canvas.glsl300
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl37
-rw-r--r--drivers/gles3/shaders/cubemap_filter.glsl4
-rw-r--r--drivers/gles3/shaders/particles.glsl501
-rw-r--r--drivers/gles3/shaders/particles_copy.glsl122
-rw-r--r--drivers/gles3/shaders/scene.glsl114
-rw-r--r--drivers/gles3/shaders/skeleton.glsl282
-rw-r--r--drivers/gles3/shaders/sky.glsl38
-rw-r--r--drivers/gles3/shaders/stdlib_inc.glsl36
10 files changed, 1224 insertions, 213 deletions
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index b8bb08ec34..34713e7e29 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -19,3 +19,6 @@ if "GLES3_GLSL" in env["BUILDERS"]:
env.GLES3_GLSL("cubemap_filter.glsl")
env.GLES3_GLSL("canvas_occlusion.glsl")
env.GLES3_GLSL("canvas_sdf.glsl")
+ env.GLES3_GLSL("particles.glsl")
+ env.GLES3_GLSL("particles_copy.glsl")
+ env.GLES3_GLSL("skeleton.glsl")
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index ca806304c5..ea0a0b660d 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -11,6 +11,7 @@ mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING
DISABLE_LIGHTING = false
USE_RGBA_SHADOWS = false
+SINGLE_INSTANCE = false
#[vertex]
@@ -19,18 +20,80 @@ layout(location = 0) in vec2 vertex_attrib;
layout(location = 3) in vec4 color_attrib;
layout(location = 4) in vec2 uv_attrib;
-layout(location = 10) in uvec4 bone_attrib;
-layout(location = 11) in vec4 weight_attrib;
-
#ifdef USE_INSTANCING
layout(location = 1) in highp vec4 instance_xform0;
layout(location = 2) in highp vec4 instance_xform1;
layout(location = 5) in highp uvec4 instance_color_custom_data; // Color packed into xy, custom_data packed into zw for compatibility with 3D
+#endif // USE_INSTANCING
+
+#endif // USE_ATTRIBUTES
+
+#include "stdlib_inc.glsl"
+
+layout(location = 6) in highp vec4 attrib_A;
+layout(location = 7) in highp vec4 attrib_B;
+layout(location = 8) in highp vec4 attrib_C;
+layout(location = 9) in highp vec4 attrib_D;
+layout(location = 10) in highp vec4 attrib_E;
+#ifdef USE_PRIMITIVE
+layout(location = 11) in highp uvec4 attrib_F;
+#else
+layout(location = 11) in highp vec4 attrib_F;
#endif
+layout(location = 12) in highp uvec4 attrib_G;
+layout(location = 13) in highp uvec4 attrib_H;
+
+#define read_draw_data_world_x attrib_A.xy
+#define read_draw_data_world_y attrib_A.zw
+#define read_draw_data_world_ofs attrib_B.xy
+#define read_draw_data_color_texture_pixel_size attrib_B.zw
+
+#ifdef USE_PRIMITIVE
+
+#define read_draw_data_point_a attrib_C.xy
+#define read_draw_data_point_b attrib_C.zw
+#define read_draw_data_point_c attrib_D.xy
+#define read_draw_data_uv_a attrib_D.zw
+#define read_draw_data_uv_b attrib_E.xy
+#define read_draw_data_uv_c attrib_E.zw
+
+#define read_draw_data_color_a_rg attrib_F.x
+#define read_draw_data_color_a_ba attrib_F.y
+#define read_draw_data_color_b_rg attrib_F.z
+#define read_draw_data_color_b_ba attrib_F.w
+#define read_draw_data_color_c_rg attrib_G.x
+#define read_draw_data_color_c_ba attrib_G.y
+
+#else
+
+#define read_draw_data_modulation attrib_C
+#define read_draw_data_ninepatch_margins attrib_D
+#define read_draw_data_dst_rect attrib_E
+#define read_draw_data_src_rect attrib_F
+
+#endif
+
+#define read_draw_data_flags attrib_G.z
+#define read_draw_data_specular_shininess attrib_G.w
+#define read_draw_data_lights attrib_H
+
+// Varyings so the per-instance info can be used in the fragment shader
+flat out vec4 varying_A;
+flat out vec2 varying_B;
+#ifndef USE_PRIMITIVE
+flat out vec4 varying_C;
+#ifndef USE_ATTRIBUTES
+#ifdef USE_NINEPATCH
+flat out vec2 varying_D;
+#endif
+flat out vec4 varying_E;
+#endif
#endif
+flat out uvec2 varying_F;
+flat out uvec4 varying_G;
// This needs to be outside clang-format so the ubo comment is in the right place
#ifdef MATERIAL_UNIFORMS_USED
@@ -42,14 +105,10 @@ layout(std140) uniform MaterialUniforms{ //ubo:4
#endif
/* clang-format on */
#include "canvas_uniforms_inc.glsl"
-#include "stdlib_inc.glsl"
-
-uniform sampler2D transforms_texture; //texunit:-1
out vec2 uv_interp;
out vec4 color_interp;
out vec2 vertex_interp;
-flat out int draw_data_instance;
#ifdef USE_NINEPATCH
@@ -60,74 +119,82 @@ out vec2 pixel_size_interp;
#GLOBALS
void main() {
+ varying_A = vec4(read_draw_data_world_x, read_draw_data_world_y);
+ varying_B = read_draw_data_color_texture_pixel_size;
+#ifndef USE_PRIMITIVE
+ varying_C = read_draw_data_ninepatch_margins;
+
+#ifndef USE_ATTRIBUTES
+#ifdef USE_NINEPATCH
+ varying_D = vec2(read_draw_data_dst_rect.z, read_draw_data_dst_rect.w);
+#endif // USE_NINEPATCH
+ varying_E = read_draw_data_src_rect;
+#endif // !USE_ATTRIBUTES
+#endif // USE_PRIMITIVE
+
+ varying_F = uvec2(read_draw_data_flags, read_draw_data_specular_shininess);
+ varying_G = read_draw_data_lights;
+
vec4 instance_custom = vec4(0.0);
#ifdef USE_PRIMITIVE
- draw_data_instance = gl_InstanceID;
vec2 vertex;
vec2 uv;
vec4 color;
if (gl_VertexID % 3 == 0) {
- vertex = draw_data[draw_data_instance].point_a;
- uv = draw_data[draw_data_instance].uv_a;
- color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_a_rg), unpackHalf2x16(draw_data[draw_data_instance].color_a_ba));
+ vertex = read_draw_data_point_a;
+ uv = read_draw_data_uv_a;
+ color = vec4(unpackHalf2x16(read_draw_data_color_a_rg), unpackHalf2x16(read_draw_data_color_a_ba));
} else if (gl_VertexID % 3 == 1) {
- vertex = draw_data[draw_data_instance].point_b;
- uv = draw_data[draw_data_instance].uv_b;
- color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_b_rg), unpackHalf2x16(draw_data[draw_data_instance].color_b_ba));
+ vertex = read_draw_data_point_b;
+ uv = read_draw_data_uv_b;
+ color = vec4(unpackHalf2x16(read_draw_data_color_b_rg), unpackHalf2x16(read_draw_data_color_b_ba));
} else {
- vertex = draw_data[draw_data_instance].point_c;
- uv = draw_data[draw_data_instance].uv_c;
- color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_c_rg), unpackHalf2x16(draw_data[draw_data_instance].color_c_ba));
+ vertex = read_draw_data_point_c;
+ uv = read_draw_data_uv_c;
+ color = vec4(unpackHalf2x16(read_draw_data_color_c_rg), unpackHalf2x16(read_draw_data_color_c_ba));
}
- uvec4 bones = uvec4(0, 0, 0, 0);
- vec4 bone_weights = vec4(0.0);
#elif defined(USE_ATTRIBUTES)
- draw_data_instance = gl_InstanceID;
-#ifdef USE_INSTANCING
- draw_data_instance = 0;
-#endif
vec2 vertex = vertex_attrib;
- vec4 color = color_attrib * draw_data[draw_data_instance].modulation;
+ vec4 color = color_attrib * read_draw_data_modulation;
vec2 uv = uv_attrib;
- uvec4 bones = bone_attrib;
- vec4 bone_weights = weight_attrib;
-
#ifdef USE_INSTANCING
- vec4 instance_color = vec4(unpackHalf2x16(instance_color_custom_data.x), unpackHalf2x16(instance_color_custom_data.y));
- color *= instance_color;
- instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w));
+ if (bool(read_draw_data_flags & FLAGS_INSTANCING_HAS_COLORS)) {
+ vec4 instance_color = vec4(unpackHalf2x16(instance_color_custom_data.x), unpackHalf2x16(instance_color_custom_data.y));
+ color *= instance_color;
+ }
+ if (bool(read_draw_data_flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+ instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w));
+ }
#endif
#else
- draw_data_instance = gl_VertexID / 6;
vec2 vertex_base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 vertex_base = vertex_base_arr[gl_VertexID % 6];
- vec2 uv = draw_data[draw_data_instance].src_rect.xy + abs(draw_data[draw_data_instance].src_rect.zw) * ((draw_data[draw_data_instance].flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
- vec4 color = draw_data[draw_data_instance].modulation;
- vec2 vertex = draw_data[draw_data_instance].dst_rect.xy + abs(draw_data[draw_data_instance].dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data[draw_data_instance].src_rect.zw, vec2(0.0, 0.0)));
- uvec4 bones = uvec4(0, 0, 0, 0);
+ vec2 uv = read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) * ((read_draw_data_flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
+ vec4 color = read_draw_data_modulation;
+ vec2 vertex = read_draw_data_dst_rect.xy + abs(read_draw_data_dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(read_draw_data_src_rect.zw, vec2(0.0, 0.0)));
#endif
- mat4 model_matrix = mat4(vec4(draw_data[draw_data_instance].world_x, 0.0, 0.0), vec4(draw_data[draw_data_instance].world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data[draw_data_instance].world_ofs, 0.0, 1.0));
+ mat4 model_matrix = mat4(vec4(read_draw_data_world_x, 0.0, 0.0), vec4(read_draw_data_world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(read_draw_data_world_ofs, 0.0, 1.0));
#ifdef USE_INSTANCING
model_matrix = model_matrix * transpose(mat4(instance_xform0, instance_xform1, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)));
#endif // USE_INSTANCING
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
- if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_PARTICLES)) {
+ if (bool(read_draw_data_flags & FLAGS_USING_PARTICLES)) {
//scale by texture size
- vertex /= draw_data[draw_data_instance].color_texture_pixel_size;
+ vertex /= read_draw_data_color_texture_pixel_size;
}
#endif
- vec2 color_texture_pixel_size = draw_data[draw_data_instance].color_texture_pixel_size.xy;
+ vec2 color_texture_pixel_size = read_draw_data_color_texture_pixel_size;
#ifdef USE_POINT_SIZE
float point_size = 1.0;
@@ -137,7 +204,7 @@ void main() {
}
#ifdef USE_NINEPATCH
- pixel_size_interp = abs(draw_data[draw_data_instance].dst_rect.zw) * vertex_base;
+ pixel_size_interp = abs(read_draw_data_dst_rect.zw) * vertex_base;
#endif
#if !defined(SKIP_TRANSFORM_USED)
@@ -153,87 +220,74 @@ void main() {
uv += 1e-5;
}
-#ifdef USE_ATTRIBUTES
-#if 0
- if (bool(draw_data[draw_data_instance].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;
+ vertex = (canvas_transform * vec4(vertex, 0.0, 1.0)).xy;
- mat2x4 m;
- m = mat2x4(
- texelFetch(skeleton_buffer, tex_ofs + 0),
- texelFetch(skeleton_buffer, tex_ofs + 1)) *
- bone_weights.x;
+ vertex_interp = vertex;
+ uv_interp = uv;
- tex_ofs = bone_indicesi.y * 2;
+ gl_Position = screen_transform * vec4(vertex, 0.0, 1.0);
- m += mat2x4(
- texelFetch(skeleton_buffer, tex_ofs + 0),
- texelFetch(skeleton_buffer, tex_ofs + 1)) *
- bone_weights.y;
+#ifdef USE_POINT_SIZE
+ gl_PointSize = point_size;
+#endif
+}
- tex_ofs = bone_indicesi.z * 2;
+#[fragment]
- m += mat2x4(
- texelFetch(skeleton_buffer, tex_ofs + 0),
- texelFetch(skeleton_buffer, tex_ofs + 1)) *
- bone_weights.z;
+#include "canvas_uniforms_inc.glsl"
+#include "stdlib_inc.glsl"
- tex_ofs = bone_indicesi.w * 2;
+in vec2 uv_interp;
+in vec2 vertex_interp;
+in vec4 color_interp;
- m += mat2x4(
- texelFetch(skeleton_buffer, tex_ofs + 0),
- texelFetch(skeleton_buffer, tex_ofs + 1)) *
- bone_weights.w;
+#ifdef USE_NINEPATCH
- 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;
+in vec2 pixel_size_interp;
- //outvec = bone_matrix * outvec;
- }
-#endif
#endif
- vertex = (canvas_transform * vec4(vertex, 0.0, 1.0)).xy;
+// Can all be flat as they are the same for the whole batched instance
+flat in vec4 varying_A;
+flat in vec2 varying_B;
+#define read_draw_data_world_x varying_A.xy
+#define read_draw_data_world_y varying_A.zw
+#define read_draw_data_color_texture_pixel_size varying_B
- vertex_interp = vertex;
- uv_interp = uv;
+#ifndef USE_PRIMITIVE
+flat in vec4 varying_C;
+#define read_draw_data_ninepatch_margins varying_C
- gl_Position = screen_transform * vec4(vertex, 0.0, 1.0);
+#ifndef USE_ATTRIBUTES
+#ifdef USE_NINEPATCH
-#ifdef USE_POINT_SIZE
- gl_PointSize = point_size;
+flat in vec2 varying_D;
+#define read_draw_data_dst_rect_z varying_D.x
+#define read_draw_data_dst_rect_w varying_D.y
#endif
-}
-#[fragment]
+flat in vec4 varying_E;
+#define read_draw_data_src_rect varying_E
+#endif // USE_ATTRIBUTES
+#endif // USE_PRIMITIVE
-#include "canvas_uniforms_inc.glsl"
-#include "stdlib_inc.glsl"
+flat in uvec2 varying_F;
+flat in uvec4 varying_G;
+#define read_draw_data_flags varying_F.x
+#define read_draw_data_specular_shininess varying_F.y
+#define read_draw_data_lights varying_G
#ifndef DISABLE_LIGHTING
uniform sampler2D atlas_texture; //texunit:-2
uniform sampler2D shadow_atlas_texture; //texunit:-3
#endif // DISABLE_LIGHTING
-uniform sampler2D screen_texture; //texunit:-4
+uniform sampler2D color_buffer; //texunit:-4
uniform sampler2D sdf_texture; //texunit:-5
uniform sampler2D normal_texture; //texunit:-6
uniform sampler2D specular_texture; //texunit:-7
uniform sampler2D color_texture; //texunit:0
-in vec2 uv_interp;
-in vec4 color_interp;
-in vec2 vertex_interp;
-flat in int draw_data_instance;
-
-#ifdef USE_NINEPATCH
-
-in vec2 pixel_size_interp;
-
-#endif
-
layout(location = 0) out vec4 frag_color;
#ifdef MATERIAL_UNIFORMS_USED
@@ -339,11 +393,9 @@ vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 lig
#endif
-#define SHADOW_TEST(m_uv) \
- { \
- highp float sd = SHADOW_DEPTH(m_uv); \
- shadow += step(sd, shadow_uv.z / shadow_uv.w); \
- }
+/* clang-format off */
+#define SHADOW_TEST(m_uv) { highp float sd = SHADOW_DEPTH(m_uv); shadow += step(sd, shadow_uv.z / shadow_uv.w); }
+/* clang-format on */
//float distance = length(shadow_pos);
vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
@@ -383,7 +435,7 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
shadow /= 13.0;
}
- vec4 shadow_color = unpackUnorm4x8(light_array[light_base].shadow_color);
+ vec4 shadow_color = godot_unpackUnorm4x8(light_array[light_base].shadow_color);
#ifdef LIGHT_CODE_USED
shadow_color.rgb *= shadow_modulate;
#endif
@@ -421,7 +473,7 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
} else if (pixel >= draw_size - margin_end) {
return (tex_size - (draw_size - pixel)) * tex_pixel_size;
} else {
- if (!bool(draw_data[draw_data_instance].flags & FLAGS_NINEPACH_DRAW_CENTER)) {
+ if (!bool(read_draw_data_flags & FLAGS_NINEPACH_DRAW_CENTER)) {
draw_center--;
}
@@ -469,28 +521,26 @@ void main() {
int draw_center = 2;
uv = vec2(
- map_ninepatch_axis(pixel_size_interp.x, abs(draw_data[draw_data_instance].dst_rect.z), draw_data[draw_data_instance].color_texture_pixel_size.x, draw_data[draw_data_instance].ninepatch_margins.x, draw_data[draw_data_instance].ninepatch_margins.z, int(draw_data[draw_data_instance].flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
- map_ninepatch_axis(pixel_size_interp.y, abs(draw_data[draw_data_instance].dst_rect.w), draw_data[draw_data_instance].color_texture_pixel_size.y, draw_data[draw_data_instance].ninepatch_margins.y, draw_data[draw_data_instance].ninepatch_margins.w, int(draw_data[draw_data_instance].flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
+ map_ninepatch_axis(pixel_size_interp.x, abs(read_draw_data_dst_rect_z), read_draw_data_color_texture_pixel_size.x, read_draw_data_ninepatch_margins.x, read_draw_data_ninepatch_margins.z, int(read_draw_data_flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
+ map_ninepatch_axis(pixel_size_interp.y, abs(read_draw_data_dst_rect_w), read_draw_data_color_texture_pixel_size.y, read_draw_data_ninepatch_margins.y, read_draw_data_ninepatch_margins.w, int(read_draw_data_flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
if (draw_center == 0) {
color.a = 0.0;
}
- uv = uv * draw_data[draw_data_instance].src_rect.zw + draw_data[draw_data_instance].src_rect.xy; //apply region if needed
+ uv = uv * read_draw_data_src_rect.zw + read_draw_data_src_rect.xy; //apply region if needed
#endif
- if (bool(draw_data[draw_data_instance].flags & FLAGS_CLIP_RECT_UV)) {
- uv = clamp(uv, draw_data[draw_data_instance].src_rect.xy, draw_data[draw_data_instance].src_rect.xy + abs(draw_data[draw_data_instance].src_rect.zw));
+ if (bool(read_draw_data_flags & FLAGS_CLIP_RECT_UV)) {
+ uv = clamp(uv, read_draw_data_src_rect.xy, read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw));
}
#endif
#ifndef USE_PRIMITIVE
- if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_MSDF)) {
- float px_range = draw_data[draw_data_instance].ninepatch_margins.x;
- float outline_thickness = draw_data[draw_data_instance].ninepatch_margins.y;
- //float reserved1 = draw_data[draw_data_instance].ninepatch_margins.z;
- //float reserved2 = draw_data[draw_data_instance].ninepatch_margins.w;
+ if (bool(read_draw_data_flags & FLAGS_USE_MSDF)) {
+ float px_range = read_draw_data_ninepatch_margins.x;
+ float outline_thickness = read_draw_data_ninepatch_margins.y;
vec4 msdf_sample = texture(color_texture, uv);
vec2 msdf_size = vec2(textureSize(color_texture, 0));
@@ -506,7 +556,7 @@ void main() {
float a = clamp(d * px_size + 0.5, 0.0, 1.0);
color.a = a * color.a;
}
- } else if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_LCD)) {
+ } else if (bool(read_draw_data_flags & FLAGS_USE_LCD)) {
vec4 lcd_sample = texture(color_texture, uv);
if (lcd_sample.a == 1.0) {
color.rgb = lcd_sample.rgb * color.a;
@@ -520,7 +570,7 @@ void main() {
color *= texture(color_texture, uv);
}
- uint light_count = (draw_data[draw_data_instance].flags >> uint(FLAGS_LIGHT_COUNT_SHIFT)) & uint(0xF); //max 16 lights
+ uint light_count = (read_draw_data_flags >> uint(FLAGS_LIGHT_COUNT_SHIFT)) & uint(0xF); //max 16 lights
bool using_light = light_count > 0u || directional_light_count > 0u;
vec3 normal;
@@ -531,8 +581,14 @@ void main() {
bool normal_used = false;
#endif
- if (normal_used || (using_light && bool(draw_data[draw_data_instance].flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
+ if (normal_used || (using_light && bool(read_draw_data_flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
+ if (bool(read_draw_data_flags & FLAGS_FLIP_H)) {
+ normal.x = -normal.x;
+ }
+ if (bool(read_draw_data_flags & FLAGS_FLIP_V)) {
+ normal.y = -normal.y;
+ }
normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
normal_used = true;
} else {
@@ -548,9 +604,9 @@ void main() {
bool specular_shininess_used = false;
#endif
- if (specular_shininess_used || (using_light && normal_used && bool(draw_data[draw_data_instance].flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
+ if (specular_shininess_used || (using_light && normal_used && bool(read_draw_data_flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(specular_texture, uv);
- specular_shininess *= unpackUnorm4x8(draw_data[draw_data_instance].specular_shininess);
+ specular_shininess *= godot_unpackUnorm4x8(read_draw_data_specular_shininess);
specular_shininess_used = true;
} else {
specular_shininess = vec4(1.0);
@@ -562,7 +618,7 @@ void main() {
vec2 screen_uv = vec2(0.0);
#endif
- vec2 color_texture_pixel_size = draw_data[draw_data_instance].color_texture_pixel_size.xy;
+ vec2 color_texture_pixel_size = read_draw_data_color_texture_pixel_size.xy;
vec3 light_vertex = vec3(vertex, 0.0);
vec2 shadow_vertex = vertex;
@@ -584,7 +640,7 @@ void main() {
if (normal_used) {
//convert by item transform
- normal.xy = mat2(normalize(draw_data[draw_data_instance].world_x), normalize(draw_data[draw_data_instance].world_y)) * normal.xy;
+ normal.xy = mat2(normalize(read_draw_data_world_x), normalize(read_draw_data_world_y)) * normal.xy;
//convert by canvas transform
normal = normalize((canvas_normal_transform * vec4(normal, 0.0)).xyz);
}
@@ -593,7 +649,7 @@ void main() {
#ifdef MODE_LIGHT_ONLY
color = vec4(0.0);
-#else
+#elif !defined(MODE_UNSHADED)
color *= canvas_modulation;
#endif
@@ -646,15 +702,15 @@ void main() {
uint light_base;
if (i < 8u) {
if (i < 4u) {
- light_base = draw_data[draw_data_instance].lights[0];
+ light_base = read_draw_data_lights[0];
} else {
- light_base = draw_data[draw_data_instance].lights[1];
+ light_base = read_draw_data_lights[1];
}
} else {
if (i < 12u) {
- light_base = draw_data[draw_data_instance].lights[2];
+ light_base = read_draw_data_lights[2];
} else {
- light_base = draw_data[draw_data_instance].lights[3];
+ light_base = read_draw_data_lights[3];
}
}
light_base >>= (i & 3u) * 8u;
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index dd5ebecb1a..d53c0fcb26 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -27,37 +27,8 @@
#define FLAGS_USE_MSDF uint(1 << 28)
#define FLAGS_USE_LCD uint(1 << 29)
-// must be always 128 bytes long
-struct DrawData {
- vec2 world_x;
- vec2 world_y;
- vec2 world_ofs;
- vec2 color_texture_pixel_size;
-#ifdef USE_PRIMITIVE
- vec2 point_a;
- vec2 point_b;
- vec2 point_c;
- vec2 uv_a;
- vec2 uv_b;
- vec2 uv_c;
- uint color_a_rg;
- uint color_a_ba;
- uint color_b_rg;
- uint color_b_ba;
- uint color_c_rg;
- uint color_c_ba;
-#else
- vec4 modulation;
- vec4 ninepatch_margins;
- vec4 dst_rect; //for built-in rect and UV
- vec4 src_rect;
- uint pad;
- uint pad2;
-#endif
- uint flags;
- uint specular_shininess;
- uvec4 lights;
-};
+#define FLAGS_FLIP_H uint(1 << 30)
+#define FLAGS_FLIP_V uint(1 << 31)
layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
@@ -116,7 +87,3 @@ layout(std140) uniform LightData { //ubo:2
Light light_array[MAX_LIGHTS];
};
#endif // DISABLE_LIGHTING
-layout(std140) uniform DrawDataInstances { //ubo:3
-
- DrawData draw_data[MAX_DRAW_DATA_INSTANCES];
-};
diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl
index 88464876f1..6fcb23204d 100644
--- a/drivers/gles3/shaders/cubemap_filter.glsl
+++ b/drivers/gles3/shaders/cubemap_filter.glsl
@@ -31,7 +31,7 @@ uniform samplerCube source_cube; //texunit:0
uniform int face_id;
#ifndef MODE_DIRECT_WRITE
-uniform int sample_count;
+uniform uint sample_count;
uniform vec4 sample_directions_mip[MAX_SAMPLE_COUNT];
uniform float weight;
#endif
@@ -105,7 +105,7 @@ void main() {
T[1] = cross(N, T[0]);
T[2] = N;
- for (int sample_num = 0; sample_num < sample_count; sample_num++) {
+ for (uint sample_num = 0u; sample_num < sample_count; sample_num++) {
vec4 sample_direction_mip = sample_directions_mip[sample_num];
vec3 L = T * sample_direction_mip.xyz;
vec3 val = textureLod(source_cube, L, sample_direction_mip.w).rgb;
diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl
new file mode 100644
index 0000000000..f8741a22ab
--- /dev/null
+++ b/drivers/gles3/shaders/particles.glsl
@@ -0,0 +1,501 @@
+/* clang-format off */
+#[modes]
+
+mode_default =
+
+#[specializations]
+
+MODE_3D = false
+USERDATA1_USED = false
+USERDATA2_USED = false
+USERDATA3_USED = false
+USERDATA4_USED = false
+USERDATA5_USED = false
+USERDATA6_USED = false
+
+#[vertex]
+
+#define SDF_MAX_LENGTH 16384.0
+
+layout(std140) uniform GlobalShaderUniformData { //ubo:1
+ vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
+};
+
+// This needs to be outside clang-format so the ubo comment is in the right place
+#ifdef MATERIAL_UNIFORMS_USED
+layout(std140) uniform MaterialUniforms{ //ubo:2
+
+#MATERIAL_UNIFORMS
+
+};
+#endif
+
+/* clang-format on */
+
+#define MAX_ATTRACTORS 32
+
+#define ATTRACTOR_TYPE_SPHERE uint(0)
+#define ATTRACTOR_TYPE_BOX uint(1)
+#define ATTRACTOR_TYPE_VECTOR_FIELD uint(2)
+
+struct Attractor {
+ mat4 transform;
+ vec4 extents; // Extents or radius. w-channel is padding.
+
+ uint type;
+ float strength;
+ float attenuation;
+ float directionality;
+};
+
+#define MAX_COLLIDERS 32
+
+#define COLLIDER_TYPE_SPHERE uint(0)
+#define COLLIDER_TYPE_BOX uint(1)
+#define COLLIDER_TYPE_SDF uint(2)
+#define COLLIDER_TYPE_HEIGHT_FIELD uint(3)
+#define COLLIDER_TYPE_2D_SDF uint(4)
+
+struct Collider {
+ mat4 transform;
+ vec4 extents; // Extents or radius. w-channel is padding.
+
+ uint type;
+ float scale;
+ float pad0;
+ float pad1;
+};
+
+layout(std140) uniform FrameData { //ubo:0
+ bool emitting;
+ uint cycle;
+ float system_phase;
+ float prev_system_phase;
+
+ float explosiveness;
+ float randomness;
+ float time;
+ float delta;
+
+ float particle_size;
+ float pad0;
+ float pad1;
+ float pad2;
+
+ uint random_seed;
+ uint attractor_count;
+ uint collider_count;
+ uint frame;
+
+ mat4 emission_transform;
+
+ Attractor attractors[MAX_ATTRACTORS];
+ Collider colliders[MAX_COLLIDERS];
+};
+
+#define PARTICLE_FLAG_ACTIVE uint(1)
+#define PARTICLE_FLAG_STARTED uint(2)
+#define PARTICLE_FLAG_TRAILED uint(4)
+#define PARTICLE_FRAME_MASK uint(0xFFFF)
+#define PARTICLE_FRAME_SHIFT uint(16)
+
+// ParticleData
+layout(location = 0) in highp vec4 color;
+layout(location = 1) in highp vec4 velocity_flags;
+layout(location = 2) in highp vec4 custom;
+layout(location = 3) in highp vec4 xform_1;
+layout(location = 4) in highp vec4 xform_2;
+#ifdef MODE_3D
+layout(location = 5) in highp vec4 xform_3;
+#endif
+#ifdef USERDATA1_USED
+layout(location = 6) in highp vec4 userdata1;
+#endif
+#ifdef USERDATA2_USED
+layout(location = 7) in highp vec4 userdata2;
+#endif
+#ifdef USERDATA3_USED
+layout(location = 8) in highp vec4 userdata3;
+#endif
+#ifdef USERDATA4_USED
+layout(location = 9) in highp vec4 userdata4;
+#endif
+#ifdef USERDATA5_USED
+layout(location = 10) in highp vec4 userdata5;
+#endif
+#ifdef USERDATA6_USED
+layout(location = 11) in highp vec4 userdata6;
+#endif
+
+out highp vec4 out_color; //tfb:
+out highp vec4 out_velocity_flags; //tfb:
+out highp vec4 out_custom; //tfb:
+out highp vec4 out_xform_1; //tfb:
+out highp vec4 out_xform_2; //tfb:
+#ifdef MODE_3D
+out highp vec4 out_xform_3; //tfb:MODE_3D
+#endif
+#ifdef USERDATA1_USED
+out highp vec4 out_userdata1; //tfb:USERDATA1_USED
+#endif
+#ifdef USERDATA2_USED
+out highp vec4 out_userdata2; //tfb:USERDATA2_USED
+#endif
+#ifdef USERDATA3_USED
+out highp vec4 out_userdata3; //tfb:USERDATA3_USED
+#endif
+#ifdef USERDATA4_USED
+out highp vec4 out_userdata4; //tfb:USERDATA4_USED
+#endif
+#ifdef USERDATA5_USED
+out highp vec4 out_userdata5; //tfb:USERDATA5_USED
+#endif
+#ifdef USERDATA6_USED
+out highp vec4 out_userdata6; //tfb:USERDATA6_USED
+#endif
+
+uniform sampler2D height_field_texture; //texunit:0
+
+uniform float lifetime;
+uniform bool clear;
+uniform uint total_particles;
+uniform bool use_fractional_delta;
+
+uint hash(uint x) {
+ x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
+ x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
+ x = (x >> uint(16)) ^ x;
+ return x;
+}
+
+vec3 safe_normalize(vec3 direction) {
+ const float EPSILON = 0.001;
+ if (length(direction) < EPSILON) {
+ return vec3(0.0);
+ }
+ return normalize(direction);
+}
+
+// Needed whenever 2D sdf texture is read from as it is packed in RGBA8.
+float vec4_to_float(vec4 p_vec) {
+ return dot(p_vec, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) * 2.0 - 1.0;
+}
+
+#GLOBALS
+
+void main() {
+ bool apply_forces = true;
+ bool apply_velocity = true;
+ float local_delta = delta;
+
+ float mass = 1.0;
+
+ bool restart = false;
+
+ bool restart_position = false;
+ bool restart_rotation_scale = false;
+ bool restart_velocity = false;
+ bool restart_color = false;
+ bool restart_custom = false;
+
+ mat4 xform = mat4(1.0);
+ uint flags = 0u;
+
+ if (clear) {
+ out_color = vec4(1.0);
+ out_custom = vec4(0.0);
+ out_velocity_flags = vec4(0.0);
+ } else {
+ out_color = color;
+ out_velocity_flags = velocity_flags;
+ out_custom = custom;
+ xform[0] = xform_1;
+ xform[1] = xform_2;
+#ifdef MODE_3D
+ xform[2] = xform_3;
+#endif
+ xform = transpose(xform);
+ flags = floatBitsToUint(velocity_flags.w);
+ }
+
+ //clear started flag if set
+ flags &= ~PARTICLE_FLAG_STARTED;
+
+ bool collided = false;
+ vec3 collision_normal = vec3(0.0);
+ float collision_depth = 0.0;
+
+ vec3 attractor_force = vec3(0.0);
+
+#if !defined(DISABLE_VELOCITY)
+
+ if (bool(flags & PARTICLE_FLAG_ACTIVE)) {
+ xform[3].xyz += out_velocity_flags.xyz * local_delta;
+ }
+#endif
+ uint index = uint(gl_VertexID);
+ if (emitting) {
+ float restart_phase = float(index) / float(total_particles);
+
+ if (randomness > 0.0) {
+ uint seed = cycle;
+ if (restart_phase >= system_phase) {
+ seed -= uint(1);
+ }
+ seed *= uint(total_particles);
+ seed += index;
+ float random = float(hash(seed) % uint(65536)) / 65536.0;
+ restart_phase += randomness * random * 1.0 / float(total_particles);
+ }
+
+ restart_phase *= (1.0 - explosiveness);
+
+ if (system_phase > prev_system_phase) {
+ // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
+
+ if (restart_phase >= prev_system_phase && restart_phase < system_phase) {
+ restart = true;
+ if (use_fractional_delta) {
+ local_delta = (system_phase - restart_phase) * lifetime;
+ }
+ }
+
+ } else if (delta > 0.0) {
+ if (restart_phase >= prev_system_phase) {
+ restart = true;
+ if (use_fractional_delta) {
+ local_delta = (1.0 - restart_phase + system_phase) * lifetime;
+ }
+
+ } else if (restart_phase < system_phase) {
+ restart = true;
+ if (use_fractional_delta) {
+ local_delta = (system_phase - restart_phase) * lifetime;
+ }
+ }
+ }
+
+ if (restart) {
+ flags = emitting ? (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (cycle << PARTICLE_FRAME_SHIFT)) : 0u;
+ restart_position = true;
+ restart_rotation_scale = true;
+ restart_velocity = true;
+ restart_color = true;
+ restart_custom = true;
+ }
+ }
+
+ bool particle_active = bool(flags & PARTICLE_FLAG_ACTIVE);
+
+ uint particle_number = (flags >> PARTICLE_FRAME_SHIFT) * uint(total_particles) + index;
+
+ if (restart && particle_active) {
+#CODE : START
+ }
+
+ if (particle_active) {
+ for (uint i = 0u; i < attractor_count; i++) {
+ vec3 dir;
+ float amount;
+ vec3 rel_vec = xform[3].xyz - attractors[i].transform[3].xyz;
+ vec3 local_pos = rel_vec * mat3(attractors[i].transform);
+
+ switch (attractors[i].type) {
+ case ATTRACTOR_TYPE_SPHERE: {
+ dir = safe_normalize(rel_vec);
+ float d = length(local_pos) / attractors[i].extents.x;
+ if (d > 1.0) {
+ continue;
+ }
+ amount = max(0.0, 1.0 - d);
+ } break;
+ case ATTRACTOR_TYPE_BOX: {
+ dir = safe_normalize(rel_vec);
+
+ vec3 abs_pos = abs(local_pos / attractors[i].extents.xyz);
+ float d = max(abs_pos.x, max(abs_pos.y, abs_pos.z));
+ if (d > 1.0) {
+ continue;
+ }
+ amount = max(0.0, 1.0 - d);
+
+ } break;
+ case ATTRACTOR_TYPE_VECTOR_FIELD: {
+ } break;
+ }
+ amount = pow(amount, attractors[i].attenuation);
+ dir = safe_normalize(mix(dir, attractors[i].transform[2].xyz, attractors[i].directionality));
+ attractor_force -= amount * dir * attractors[i].strength;
+ }
+
+ float particle_size = particle_size;
+
+#ifdef USE_COLLISION_SCALE
+
+ particle_size *= dot(vec3(length(xform[0].xyz), length(xform[1].xyz), length(xform[2].xyz)), vec3(0.33333333333));
+
+#endif
+
+ if (collider_count == 1u && colliders[0].type == COLLIDER_TYPE_2D_SDF) {
+ //2D collision
+
+ vec2 pos = xform[3].xy;
+ vec4 to_sdf_x = colliders[0].transform[0];
+ vec4 to_sdf_y = colliders[0].transform[1];
+ vec2 sdf_pos = vec2(dot(vec4(pos, 0, 1), to_sdf_x), dot(vec4(pos, 0, 1), to_sdf_y));
+
+ vec4 sdf_to_screen = vec4(colliders[0].extents.xyz, colliders[0].scale);
+
+ vec2 uv_pos = sdf_pos * sdf_to_screen.xy + sdf_to_screen.zw;
+
+ if (all(greaterThan(uv_pos, vec2(0.0))) && all(lessThan(uv_pos, vec2(1.0)))) {
+ vec2 pos2 = pos + vec2(0, particle_size);
+ vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y));
+ float sdf_particle_size = distance(sdf_pos, sdf_pos2);
+
+ float d = vec4_to_float(texture(height_field_texture, uv_pos)) * SDF_MAX_LENGTH;
+
+ d -= sdf_particle_size;
+
+ if (d < 0.0) {
+ const float EPSILON = 0.001;
+ vec2 n = normalize(vec2(
+ vec4_to_float(texture(height_field_texture, uv_pos + vec2(EPSILON, 0.0))) - vec4_to_float(texture(height_field_texture, uv_pos - vec2(EPSILON, 0.0))),
+ vec4_to_float(texture(height_field_texture, uv_pos + vec2(0.0, EPSILON))) - vec4_to_float(texture(height_field_texture, uv_pos - vec2(0.0, EPSILON)))));
+
+ collided = true;
+ sdf_pos2 = sdf_pos + n * d;
+ pos2 = vec2(dot(vec4(sdf_pos2, 0, 1), colliders[0].transform[2]), dot(vec4(sdf_pos2, 0, 1), colliders[0].transform[3]));
+
+ n = pos - pos2;
+
+ collision_normal = normalize(vec3(n, 0.0));
+ collision_depth = length(n);
+ }
+ }
+
+ } else {
+ for (uint i = 0u; i < collider_count; i++) {
+ vec3 normal;
+ float depth;
+ bool col = false;
+
+ vec3 rel_vec = xform[3].xyz - colliders[i].transform[3].xyz;
+ vec3 local_pos = rel_vec * mat3(colliders[i].transform);
+
+ switch (colliders[i].type) {
+ case COLLIDER_TYPE_SPHERE: {
+ float d = length(rel_vec) - (particle_size + colliders[i].extents.x);
+
+ if (d < 0.0) {
+ col = true;
+ depth = -d;
+ normal = normalize(rel_vec);
+ }
+
+ } break;
+ case COLLIDER_TYPE_BOX: {
+ vec3 abs_pos = abs(local_pos);
+ vec3 sgn_pos = sign(local_pos);
+
+ if (any(greaterThan(abs_pos, colliders[i].extents.xyz))) {
+ //point outside box
+
+ vec3 closest = min(abs_pos, colliders[i].extents.xyz);
+ vec3 rel = abs_pos - closest;
+ depth = length(rel) - particle_size;
+ if (depth < 0.0) {
+ col = true;
+ normal = mat3(colliders[i].transform) * (normalize(rel) * sgn_pos);
+ depth = -depth;
+ }
+ } else {
+ //point inside box
+ vec3 axis_len = colliders[i].extents.xyz - abs_pos;
+ // there has to be a faster way to do this?
+ if (all(lessThan(axis_len.xx, axis_len.yz))) {
+ normal = vec3(1, 0, 0);
+ } else if (all(lessThan(axis_len.yy, axis_len.xz))) {
+ normal = vec3(0, 1, 0);
+ } else {
+ normal = vec3(0, 0, 1);
+ }
+
+ col = true;
+ depth = dot(normal * axis_len, vec3(1)) + particle_size;
+ normal = mat3(colliders[i].transform) * (normal * sgn_pos);
+ }
+
+ } break;
+ case COLLIDER_TYPE_SDF: {
+ } break;
+ case COLLIDER_TYPE_HEIGHT_FIELD: {
+ vec3 local_pos_bottom = local_pos;
+ local_pos_bottom.y -= particle_size;
+
+ if (any(greaterThan(abs(local_pos_bottom), colliders[i].extents.xyz))) {
+ continue;
+ }
+ const float DELTA = 1.0 / 8192.0;
+
+ vec3 uvw_pos = vec3(local_pos_bottom / colliders[i].extents.xyz) * 0.5 + 0.5;
+
+ float y = 1.0 - texture(height_field_texture, uvw_pos.xz).r;
+
+ if (y > uvw_pos.y) {
+ //inside heightfield
+
+ vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
+ vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
+ vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * colliders[i].extents.xyz;
+
+ normal = normalize(cross(pos1 - pos2, pos1 - pos3));
+ float local_y = (vec3(local_pos / colliders[i].extents.xyz) * 0.5 + 0.5).y;
+
+ col = true;
+ depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
+ }
+
+ } break;
+ }
+
+ if (col) {
+ if (!collided) {
+ collided = true;
+ collision_normal = normal;
+ collision_depth = depth;
+ } else {
+ vec3 c = collision_normal * collision_depth;
+ c += normal * max(0.0, depth - dot(normal, c));
+ collision_normal = normalize(c);
+ collision_depth = length(c);
+ }
+ }
+ }
+ }
+ }
+
+ if (particle_active) {
+#CODE : PROCESS
+ }
+
+ flags &= ~PARTICLE_FLAG_ACTIVE;
+ if (particle_active) {
+ flags |= PARTICLE_FLAG_ACTIVE;
+ }
+
+ xform = transpose(xform);
+ out_xform_1 = xform[0];
+ out_xform_2 = xform[1];
+#ifdef MODE_3D
+ out_xform_3 = xform[2];
+#endif
+ out_velocity_flags.w = uintBitsToFloat(flags);
+}
+
+/* clang-format off */
+#[fragment]
+
+void main() {
+}
+/* clang-format on */
diff --git a/drivers/gles3/shaders/particles_copy.glsl b/drivers/gles3/shaders/particles_copy.glsl
new file mode 100644
index 0000000000..f273cb7b64
--- /dev/null
+++ b/drivers/gles3/shaders/particles_copy.glsl
@@ -0,0 +1,122 @@
+/* clang-format off */
+#[modes]
+
+mode_default =
+
+#[specializations]
+
+MODE_3D = false
+
+#[vertex]
+
+#include "stdlib_inc.glsl"
+
+// ParticleData
+layout(location = 0) in highp vec4 color;
+layout(location = 1) in highp vec4 velocity_flags;
+layout(location = 2) in highp vec4 custom;
+layout(location = 3) in highp vec4 xform_1;
+layout(location = 4) in highp vec4 xform_2;
+#ifdef MODE_3D
+layout(location = 5) in highp vec4 xform_3;
+#endif
+
+/* clang-format on */
+out highp vec4 out_xform_1; //tfb:
+out highp vec4 out_xform_2; //tfb:
+#ifdef MODE_3D
+out highp vec4 out_xform_3; //tfb:MODE_3D
+#endif
+flat out highp uvec4 instance_color_custom_data; //tfb:
+
+uniform lowp vec3 sort_direction;
+uniform highp float frame_remainder;
+
+uniform highp vec3 align_up;
+uniform highp uint align_mode;
+
+uniform highp mat4 inv_emission_transform;
+
+#define TRANSFORM_ALIGN_DISABLED uint(0)
+#define TRANSFORM_ALIGN_Z_BILLBOARD uint(1)
+#define TRANSFORM_ALIGN_Y_TO_VELOCITY uint(2)
+#define TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY uint(3)
+
+#define PARTICLE_FLAG_ACTIVE uint(1)
+
+void main() {
+ mat4 txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); // zero scale, becomes invisible.
+ if (bool(floatBitsToUint(velocity_flags.w) & PARTICLE_FLAG_ACTIVE)) {
+#ifdef MODE_3D
+ txform = transpose(mat4(xform_1, xform_2, xform_3, vec4(0.0, 0.0, 0.0, 1.0)));
+#else
+ txform = transpose(mat4(xform_1, xform_2, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)));
+#endif
+
+ switch (align_mode) {
+ case TRANSFORM_ALIGN_DISABLED: {
+ } break; //nothing
+ case TRANSFORM_ALIGN_Z_BILLBOARD: {
+ mat3 local = mat3(normalize(cross(align_up, sort_direction)), align_up, sort_direction);
+ local = local * mat3(txform);
+ txform[0].xyz = local[0];
+ txform[1].xyz = local[1];
+ txform[2].xyz = local[2];
+
+ } break;
+ case TRANSFORM_ALIGN_Y_TO_VELOCITY: {
+ vec3 v = velocity_flags.xyz;
+ float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
+ if (length(v) > 0.0) {
+ txform[1].xyz = normalize(v);
+ } else {
+ txform[1].xyz = normalize(txform[1].xyz);
+ }
+
+ txform[0].xyz = normalize(cross(txform[1].xyz, txform[2].xyz));
+ txform[2].xyz = vec3(0.0, 0.0, 1.0) * s;
+ txform[0].xyz *= s;
+ txform[1].xyz *= s;
+ } break;
+ case TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY: {
+ vec3 sv = velocity_flags.xyz - sort_direction * dot(sort_direction, velocity_flags.xyz); //screen velocity
+ float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
+
+ if (length(sv) == 0.0) {
+ sv = align_up;
+ }
+
+ sv = normalize(sv);
+
+ txform[0].xyz = normalize(cross(sv, sort_direction)) * s;
+ txform[1].xyz = sv * s;
+ txform[2].xyz = sort_direction * s;
+
+ } break;
+ }
+
+ txform[3].xyz += velocity_flags.xyz * frame_remainder;
+
+#ifndef MODE_3D
+ // In global mode, bring 2D particles to local coordinates
+ // as they will be drawn with the node position as origin.
+ txform = inv_emission_transform * txform;
+#endif
+
+ txform = transpose(txform);
+ }
+
+ instance_color_custom_data = uvec4(packHalf2x16(color.xy), packHalf2x16(color.zw), packHalf2x16(custom.xy), packHalf2x16(custom.zw));
+ out_xform_1 = txform[0];
+ out_xform_2 = txform[1];
+#ifdef MODE_3D
+ out_xform_3 = txform[2];
+#endif
+}
+
+/* clang-format off */
+#[fragment]
+
+void main() {
+}
+/* clang-format on */
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index ed176c7829..0b389b0478 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -102,7 +102,7 @@ vec3 oct_to_vec3(vec2 e) {
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
float t = max(-v.z, 0.0);
v.xy += t * -sign(v.xy);
- return v;
+ return normalize(v);
}
#ifdef USE_INSTANCING
@@ -129,7 +129,7 @@ layout(std140) uniform SceneData { // ubo:2
mediump float ambient_color_sky_mix;
bool material_uv2_mode;
- float pad2;
+ float emissive_exposure_normalization;
bool use_ambient_light;
bool use_ambient_cubemap;
bool use_reflection_cubemap;
@@ -142,7 +142,7 @@ layout(std140) uniform SceneData { // ubo:2
uint directional_light_count;
float z_far;
float z_near;
- float pad;
+ float IBL_exposure_normalization;
bool fog_enabled;
float fog_density;
@@ -151,6 +151,10 @@ layout(std140) uniform SceneData { // ubo:2
vec3 fog_light_color;
float fog_sun_scatter;
+ uint camera_visible_layers;
+ uint pad3;
+ uint pad4;
+ uint pad5;
}
scene_data;
@@ -197,7 +201,7 @@ out vec3 tangent_interp;
out vec3 binormal_interp;
#endif
-#if defined(MATERIAL_UNIFORMS_USED)
+#ifdef MATERIAL_UNIFORMS_USED
/* clang-format off */
layout(std140) uniform MaterialUniforms { // ubo:3
@@ -264,9 +268,11 @@ void main() {
#ifdef USE_MULTIVIEW
mat4 projection_matrix = multiview_data.projection_matrix_view[ViewIndex];
mat4 inv_projection_matrix = multiview_data.inv_projection_matrix_view[ViewIndex];
+ vec3 eye_offset = multiview_data.eye_offset[ViewIndex].xyz;
#else
mat4 projection_matrix = scene_data.projection_matrix;
mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
+ vec3 eye_offset = vec3(0.0, 0.0, 0.0);
#endif //USE_MULTIVIEW
#ifdef USE_INSTANCING
@@ -366,7 +372,9 @@ void main() {
#endif
#endif
+#ifndef MODE_RENDER_DEPTH
#include "tonemap_inc.glsl"
+#endif
#include "stdlib_inc.glsl"
/* texture unit usage, N is max_texture_unity-N
@@ -428,7 +436,7 @@ layout(std140) uniform GlobalShaderUniformData { //ubo:1
/* Material Uniforms */
-#if defined(MATERIAL_UNIFORMS_USED)
+#ifdef MATERIAL_UNIFORMS_USED
/* clang-format off */
layout(std140) uniform MaterialUniforms { // ubo:3
@@ -453,7 +461,7 @@ layout(std140) uniform SceneData { // ubo:2
mediump float ambient_color_sky_mix;
bool material_uv2_mode;
- float pad2;
+ float emissive_exposure_normalization;
bool use_ambient_light;
bool use_ambient_cubemap;
bool use_reflection_cubemap;
@@ -466,7 +474,7 @@ layout(std140) uniform SceneData { // ubo:2
uint directional_light_count;
float z_far;
float z_near;
- float pad;
+ float IBL_exposure_normalization;
bool fog_enabled;
float fog_density;
@@ -475,6 +483,10 @@ layout(std140) uniform SceneData { // ubo:2
vec3 fog_light_color;
float fog_sun_scatter;
+ uint camera_visible_layers;
+ uint pad3;
+ uint pad4;
+ uint pad5;
}
scene_data;
@@ -493,8 +505,7 @@ multiview_data;
/* clang-format on */
-//directional light data
-
+// Directional light data.
#ifndef DISABLE_LIGHT_DIRECTIONAL
struct DirectionalLightData {
@@ -510,11 +521,12 @@ layout(std140) uniform DirectionalLights { // ubo:7
DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
};
-#endif
+#endif // !DISABLE_LIGHT_DIRECTIONAL
-// omni and spot
-#if !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
-struct LightData { //this structure needs to be as packed as possible
+// Omni and spot light data.
+#if !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
+
+struct LightData { // This structure needs to be as packed as possible.
highp vec3 position;
highp float inv_radius;
@@ -529,37 +541,41 @@ struct LightData { //this structure needs to be as packed as possible
mediump float specular_amount;
mediump float shadow_opacity;
};
+
#ifndef DISABLE_LIGHT_OMNI
layout(std140) uniform OmniLightData { // ubo:5
-
LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
};
uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
-uniform int omni_light_count;
+uniform uint omni_light_count;
#endif
#ifndef DISABLE_LIGHT_SPOT
-
layout(std140) uniform SpotLightData { // ubo:6
-
LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
};
uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
-uniform int spot_light_count;
+uniform uint spot_light_count;
#endif
#ifdef USE_ADDITIVE_LIGHTING
uniform highp samplerCubeShadow positional_shadow; // texunit:-4
#endif
-#endif // !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
+#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
#ifdef USE_MULTIVIEW
uniform highp sampler2DArray depth_buffer; // texunit:-6
-uniform highp sampler2DArray screen_texture; // texunit:-5
+uniform highp sampler2DArray color_buffer; // texunit:-5
+vec3 multiview_uv(vec2 uv) {
+ return vec3(uv, ViewIndex);
+}
#else
uniform highp sampler2D depth_buffer; // texunit:-6
-uniform highp sampler2D screen_texture; // texunit:-5
+uniform highp sampler2D color_buffer; // texunit:-5
+vec2 multiview_uv(vec2 uv) {
+ return uv;
+}
#endif
uniform highp mat4 world_transform;
@@ -575,6 +591,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
}
#if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
+
float D_GGX(float cos_theta_m, float alpha) {
float a = cos_theta_m * alpha;
float k = alpha / (1.0 - cos_theta_m * cos_theta_m + a * a);
@@ -631,7 +648,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
/* clang-format off */
-
#CODE : LIGHT
/* clang-format on */
@@ -662,11 +678,8 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
// https://web.archive.org/web/20210228210901/http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/
diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))) * (1.0 / M_PI);
#elif defined(DIFFUSE_TOON)
-
diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL) * (1.0 / M_PI);
-
#elif defined(DIFFUSE_BURLEY)
-
{
float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5;
float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV);
@@ -674,7 +687,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL;
}
#else
- // lambert
+ // Lambert
diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
#endif
@@ -685,7 +698,8 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
#endif
#if defined(LIGHT_RIM_USED)
- float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
+ // Epsilon min to prevent pow(0, 0) singularity which results in undefined behavior.
+ float rim_light = pow(max(1e-4, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color;
#endif
}
@@ -710,7 +724,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
// shlick+ggx as default
float alpha_ggx = roughness * roughness;
#if defined(LIGHT_ANISOTROPY_USED)
-
float aspect = sqrt(1.0 - anisotropy * 0.9);
float ax = alpha_ggx / aspect;
float ay = alpha_ggx * aspect;
@@ -718,7 +731,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
float YdotH = dot(B, H);
float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH);
float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL);
-#else // LIGHT_ANISOTROPY_USED
+#else
float D = D_GGX(cNdotH, alpha_ggx);
float G = V_GGX(cNdotL, cNdotV, alpha_ggx);
#endif // LIGHT_ANISOTROPY_USED
@@ -758,10 +771,10 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0));
#endif
-#endif //defined(LIGHT_CODE_USED)
+#endif // LIGHT_CODE_USED
}
-float get_omni_attenuation(float distance, float inv_range, float decay) {
+float get_omni_spot_attenuation(float distance, float inv_range, float decay) {
float nd = distance * inv_range;
nd *= nd;
nd *= nd; // nd^4
@@ -770,6 +783,7 @@ float get_omni_attenuation(float distance, float inv_range, float decay) {
return nd * pow(max(distance, 0.0001), -decay);
}
+#ifndef DISABLE_LIGHT_OMNI
void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
@@ -786,7 +800,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
inout vec3 diffuse_light, inout vec3 specular_light) {
vec3 light_rel_vec = omni_lights[idx].position - vertex;
float light_length = length(light_rel_vec);
- float omni_attenuation = get_omni_attenuation(light_length, omni_lights[idx].inv_radius, omni_lights[idx].attenuation);
+ float omni_attenuation = get_omni_spot_attenuation(light_length, omni_lights[idx].inv_radius, omni_lights[idx].attenuation);
vec3 color = omni_lights[idx].color;
float size_A = 0.0;
@@ -811,7 +825,9 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
diffuse_light,
specular_light);
}
+#endif // !DISABLE_LIGHT_OMNI
+#ifndef DISABLE_LIGHT_SPOT
void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
@@ -830,7 +846,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
vec3 light_rel_vec = spot_lights[idx].position - vertex;
float light_length = length(light_rel_vec);
- float spot_attenuation = get_omni_attenuation(light_length, spot_lights[idx].inv_radius, spot_lights[idx].attenuation);
+ float spot_attenuation = get_omni_spot_attenuation(light_length, spot_lights[idx].inv_radius, spot_lights[idx].attenuation);
vec3 spot_dir = spot_lights[idx].direction;
float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights[idx].cone_angle);
float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights[idx].cone_angle));
@@ -859,7 +875,9 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
#endif
diffuse_light, specular_light);
}
-#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
+#endif // !DISABLE_LIGHT_SPOT
+
+#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
#ifndef MODE_RENDER_DEPTH
vec4 fog_process(vec3 vertex) {
@@ -914,10 +932,17 @@ void main() {
//lay out everything, whatever is unused is optimized away anyway
vec3 vertex = vertex_interp;
#ifdef USE_MULTIVIEW
- vec3 view = -normalize(vertex_interp - multiview_data.eye_offset[ViewIndex].xyz);
+ vec3 eye_offset = multiview_data.eye_offset[ViewIndex].xyz;
+ vec3 view = -normalize(vertex_interp - eye_offset);
+ mat4 projection_matrix = multiview_data.projection_matrix_view[ViewIndex];
+ mat4 inv_projection_matrix = multiview_data.inv_projection_matrix_view[ViewIndex];
#else
+ vec3 eye_offset = vec3(0.0, 0.0, 0.0);
vec3 view = -normalize(vertex_interp);
+ mat4 projection_matrix = scene_data.projection_matrix;
+ mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
#endif
+ highp mat4 model_matrix = world_transform;
vec3 albedo = vec3(1.0);
vec3 backlight = vec3(0.0);
vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0);
@@ -1056,15 +1081,11 @@ void main() {
fog = fog_process(vertex);
}
#endif // !DISABLE_FOG
-#endif //!CUSTOM_FOG_USED
+#endif // !CUSTOM_FOG_USED
uint fog_rg = packHalf2x16(fog.rg);
uint fog_ba = packHalf2x16(fog.ba);
-#endif //!MODE_RENDER_DEPTH
-
-#ifndef MODE_RENDER_DEPTH
-
// Convert colors to linear
albedo = srgb_to_linear(albedo);
emission = srgb_to_linear(emission);
@@ -1097,7 +1118,7 @@ void main() {
ref_vec = mix(ref_vec, normal, roughness * roughness);
float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
- specular_light = textureLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).rgb;
+ specular_light = textureLod(radiance_map, ref_vec, sqrt(roughness) * RADIANCE_MAX_LOD).rgb;
specular_light = srgb_to_linear(specular_light);
specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
@@ -1159,7 +1180,7 @@ void main() {
float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
- specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, 0.0, 1.0);
+ specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, metallic, 1.0);
#endif
}
@@ -1185,10 +1206,10 @@ void main() {
diffuse_light,
specular_light);
}
-#endif //!DISABLE_LIGHT_DIRECTIONAL
+#endif // !DISABLE_LIGHT_DIRECTIONAL
#ifndef DISABLE_LIGHT_OMNI
- for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) {
+ for (uint i = 0u; i < MAX_FORWARD_LIGHTS; i++) {
if (i >= omni_light_count) {
break;
}
@@ -1211,7 +1232,7 @@ void main() {
#endif // !DISABLE_LIGHT_OMNI
#ifndef DISABLE_LIGHT_SPOT
- for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) {
+ for (uint i = 0u; i < MAX_FORWARD_LIGHTS; i++) {
if (i >= spot_light_count) {
break;
}
@@ -1232,9 +1253,10 @@ void main() {
#endif
diffuse_light, specular_light);
}
-
#endif // !DISABLE_LIGHT_SPOT
+
#endif // !MODE_UNSHADED
+
#endif // !MODE_RENDER_DEPTH
#if defined(USE_SHADOW_TO_OPACITY)
diff --git a/drivers/gles3/shaders/skeleton.glsl b/drivers/gles3/shaders/skeleton.glsl
new file mode 100644
index 0000000000..aad856a5a2
--- /dev/null
+++ b/drivers/gles3/shaders/skeleton.glsl
@@ -0,0 +1,282 @@
+/* clang-format off */
+#[modes]
+
+mode_base_pass =
+mode_blend_pass = #define MODE_BLEND_PASS
+
+#[specializations]
+
+MODE_2D = true
+USE_BLEND_SHAPES = false
+USE_SKELETON = false
+USE_NORMAL = false
+USE_TANGENT = false
+FINAL_PASS = false
+USE_EIGHT_WEIGHTS = false
+
+#[vertex]
+
+#include "stdlib_inc.glsl"
+
+#ifdef MODE_2D
+#define VFORMAT vec2
+#else
+#define VFORMAT vec3
+#endif
+
+#ifdef FINAL_PASS
+#define OFORMAT vec2
+#else
+#define OFORMAT uvec2
+#endif
+
+// These come from the source mesh and the output from previous passes.
+layout(location = 0) in highp VFORMAT in_vertex;
+#ifdef MODE_BLEND_PASS
+#ifdef USE_NORMAL
+layout(location = 1) in highp uvec2 in_normal;
+#endif
+#ifdef USE_TANGENT
+layout(location = 2) in highp uvec2 in_tangent;
+#endif
+#else // MODE_BLEND_PASS
+#ifdef USE_NORMAL
+layout(location = 1) in highp vec2 in_normal;
+#endif
+#ifdef USE_TANGENT
+layout(location = 2) in highp vec2 in_tangent;
+#endif
+#endif // MODE_BLEND_PASS
+
+#ifdef USE_SKELETON
+#ifdef USE_EIGHT_WEIGHTS
+layout(location = 10) in highp uvec4 in_bone_attrib;
+layout(location = 11) in highp uvec4 in_bone_attrib2;
+layout(location = 12) in mediump vec4 in_weight_attrib;
+layout(location = 13) in mediump vec4 in_weight_attrib2;
+#else
+layout(location = 10) in highp uvec4 in_bone_attrib;
+layout(location = 11) in mediump vec4 in_weight_attrib;
+#endif
+
+uniform mediump sampler2D skeleton_texture; // texunit:0
+#endif
+
+/* clang-format on */
+#ifdef MODE_BLEND_PASS
+layout(location = 3) in highp VFORMAT blend_vertex;
+#ifdef USE_NORMAL
+layout(location = 4) in highp vec2 blend_normal;
+#endif
+#ifdef USE_TANGENT
+layout(location = 5) in highp vec2 blend_tangent;
+#endif
+#endif // MODE_BLEND_PASS
+
+out highp VFORMAT out_vertex; //tfb:
+
+#ifdef USE_NORMAL
+flat out highp OFORMAT out_normal; //tfb:USE_NORMAL
+#endif
+#ifdef USE_TANGENT
+flat out highp OFORMAT out_tangent; //tfb:USE_TANGENT
+#endif
+
+#ifdef USE_BLEND_SHAPES
+uniform highp float blend_weight;
+uniform lowp float blend_shape_count;
+#endif
+
+#ifdef USE_SKELETON
+uniform mediump vec2 skeleton_transform_x;
+uniform mediump vec2 skeleton_transform_y;
+uniform mediump vec2 skeleton_transform_offset;
+
+uniform mediump vec2 inverse_transform_x;
+uniform mediump vec2 inverse_transform_y;
+uniform mediump vec2 inverse_transform_offset;
+#endif
+
+vec2 signNotZero(vec2 v) {
+ return mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0)));
+}
+
+vec3 oct_to_vec3(vec2 oct) {
+ oct = oct * 2.0 - 1.0;
+ vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));
+ if (v.z < 0.0) {
+ v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);
+ }
+ return normalize(v);
+}
+
+vec2 vec3_to_oct(vec3 e) {
+ e /= abs(e.x) + abs(e.y) + abs(e.z);
+ vec2 oct = e.z >= 0.0f ? e.xy : (vec2(1.0f) - abs(e.yx)) * signNotZero(e.xy);
+ return oct * 0.5f + 0.5f;
+}
+
+vec4 oct_to_tang(vec2 oct_sign_encoded) {
+ // Binormal sign encoded in y component
+ vec2 oct = vec2(oct_sign_encoded.x, abs(oct_sign_encoded.y) * 2.0 - 1.0);
+ return vec4(oct_to_vec3(oct), sign(oct_sign_encoded.y));
+}
+
+vec2 tang_to_oct(vec4 base) {
+ vec2 oct = vec3_to_oct(base.xyz);
+ // Encode binormal sign in y component
+ oct.y = oct.y * 0.5f + 0.5f;
+ oct.y = base.w >= 0.0f ? oct.y : 1.0 - oct.y;
+ return oct;
+}
+
+// Our original input for normals and tangents is 2 16-bit floats.
+// Transform Feedback has to write out 32-bits per channel.
+// Octahedral compression requires normalized vectors, but we need to store
+// non-normalized vectors until the very end.
+// Therefore, we will compress our normals into 16 bits using signed-normalized
+// fixed point precision. This works well, because we know that each normal
+// is no larger than |1| so we can normalize by dividing by the number of blend
+// shapes.
+uvec2 vec4_to_vec2(vec4 p_vec) {
+ return uvec2(packSnorm2x16(p_vec.xy), packSnorm2x16(p_vec.zw));
+}
+
+vec4 vec2_to_vec4(uvec2 p_vec) {
+ return vec4(unpackSnorm2x16(p_vec.x), unpackSnorm2x16(p_vec.y));
+}
+
+void main() {
+#ifdef MODE_2D
+ out_vertex = in_vertex;
+
+#ifdef USE_BLEND_SHAPES
+#ifdef MODE_BLEND_PASS
+ out_vertex = in_vertex + blend_vertex * blend_weight;
+#else
+ out_vertex = in_vertex * blend_weight;
+#endif
+#ifdef FINAL_PASS
+ out_vertex = normalize(out_vertex);
+#endif
+#endif // USE_BLEND_SHAPES
+
+#ifdef USE_SKELETON
+
+#define TEX(m) texelFetch(skeleton_texture, ivec2(m % 256u, m / 256u), 0)
+#define GET_BONE_MATRIX(a, b, w) mat2x4(TEX(a), TEX(b)) * w
+
+ uvec4 bones = in_bone_attrib * uvec4(2u);
+ uvec4 bones_a = bones + uvec4(1u);
+
+ highp mat2x4 m = GET_BONE_MATRIX(bones.x, bones_a.x, in_weight_attrib.x);
+ m += GET_BONE_MATRIX(bones.y, bones_a.y, in_weight_attrib.y);
+ m += GET_BONE_MATRIX(bones.z, bones_a.z, in_weight_attrib.z);
+ m += GET_BONE_MATRIX(bones.w, bones_a.w, in_weight_attrib.w);
+
+ mat4 skeleton_matrix = mat4(vec4(skeleton_transform_x, 0.0, 0.0), vec4(skeleton_transform_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(skeleton_transform_offset, 0.0, 1.0));
+ mat4 inverse_matrix = mat4(vec4(inverse_transform_x, 0.0, 0.0), vec4(inverse_transform_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(inverse_transform_offset, 0.0, 1.0));
+ mat4 bone_matrix = mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
+
+ bone_matrix = skeleton_matrix * transpose(bone_matrix) * inverse_matrix;
+
+ out_vertex = (bone_matrix * vec4(out_vertex, 0.0, 1.0)).xy;
+#endif // USE_SKELETON
+
+#else // MODE_2D
+
+#ifdef USE_BLEND_SHAPES
+#ifdef MODE_BLEND_PASS
+ out_vertex = in_vertex + blend_vertex * blend_weight;
+
+#ifdef USE_NORMAL
+ vec3 normal = vec2_to_vec4(in_normal).xyz * blend_shape_count;
+ vec3 normal_blend = oct_to_vec3(blend_normal) * blend_weight;
+#ifdef FINAL_PASS
+ out_normal = vec3_to_oct(normalize(normal + normal_blend));
+#else
+ out_normal = vec4_to_vec2(vec4(normal + normal_blend, 0.0) / blend_shape_count);
+#endif
+#endif // USE_NORMAL
+
+#ifdef USE_TANGENT
+ vec4 tangent = vec2_to_vec4(in_tangent) * blend_shape_count;
+ vec4 tangent_blend = oct_to_tang(blend_tangent) * blend_weight;
+#ifdef FINAL_PASS
+ out_tangent = tang_to_oct(vec4(normalize(tangent.xyz + tangent_blend.xyz), tangent.w));
+#else
+ out_tangent = vec4_to_vec2(vec4((tangent.xyz + tangent_blend.xyz) / blend_shape_count, tangent.w));
+#endif
+#endif // USE_TANGENT
+
+#else // MODE_BLEND_PASS
+ out_vertex = in_vertex * blend_weight;
+
+#ifdef USE_NORMAL
+ vec3 normal = oct_to_vec3(in_normal);
+ out_normal = vec4_to_vec2(vec4(normal * blend_weight / blend_shape_count, 0.0));
+#endif
+#ifdef USE_TANGENT
+ vec4 tangent = oct_to_tang(in_tangent);
+ out_tangent = vec4_to_vec2(vec4(tangent.rgb * blend_weight / blend_shape_count, tangent.w));
+#endif
+#endif // MODE_BLEND_PASS
+#else // USE_BLEND_SHAPES
+
+ // Make attributes available to the skeleton shader if not written by blend shapes.
+ out_vertex = in_vertex;
+#ifdef USE_NORMAL
+ out_normal = in_normal;
+#endif
+#ifdef USE_TANGENT
+ out_tangent = in_tangent;
+#endif
+#endif // USE_BLEND_SHAPES
+
+#ifdef USE_SKELETON
+
+#define TEX(m) texelFetch(skeleton_texture, ivec2(m % 256u, m / 256u), 0)
+#define GET_BONE_MATRIX(a, b, c, w) mat4(TEX(a), TEX(b), TEX(c), vec4(0.0, 0.0, 0.0, 1.0)) * w
+
+ uvec4 bones = in_bone_attrib * uvec4(3);
+ uvec4 bones_a = bones + uvec4(1);
+ uvec4 bones_b = bones + uvec4(2);
+
+ highp mat4 m;
+ m = GET_BONE_MATRIX(bones.x, bones_a.x, bones_b.x, in_weight_attrib.x);
+ m += GET_BONE_MATRIX(bones.y, bones_a.y, bones_b.y, in_weight_attrib.y);
+ m += GET_BONE_MATRIX(bones.z, bones_a.z, bones_b.z, in_weight_attrib.z);
+ m += GET_BONE_MATRIX(bones.w, bones_a.w, bones_b.w, in_weight_attrib.w);
+
+#ifdef USE_EIGHT_WEIGHTS
+ bones = in_bone_attrib2 * uvec4(3);
+ bones_a = bones + uvec4(1);
+ bones_b = bones + uvec4(2);
+
+ m += GET_BONE_MATRIX(bones.x, bones_a.x, bones_b.x, in_weight_attrib2.x);
+ m += GET_BONE_MATRIX(bones.y, bones_a.y, bones_b.y, in_weight_attrib2.y);
+ m += GET_BONE_MATRIX(bones.z, bones_a.z, bones_b.z, in_weight_attrib2.z);
+ m += GET_BONE_MATRIX(bones.w, bones_a.w, bones_b.w, in_weight_attrib2.w);
+#endif
+
+ // Reverse order because its transposed.
+ out_vertex = (vec4(out_vertex, 1.0) * m).xyz;
+#ifdef USE_NORMAL
+ vec3 vertex_normal = oct_to_vec3(out_normal);
+ out_normal = vec3_to_oct(normalize((vec4(vertex_normal, 0.0) * m).xyz));
+#endif // USE_NORMAL
+#ifdef USE_TANGENT
+ vec4 vertex_tangent = oct_to_tang(out_tangent);
+ out_tangent = tang_to_oct(vec4(normalize((vec4(vertex_tangent.xyz, 0.0) * m).xyz), vertex_tangent.w));
+#endif // USE_TANGENT
+#endif // USE_SKELETON
+#endif // MODE_2D
+}
+
+/* clang-format off */
+#[fragment]
+
+void main() {
+
+}
+/* clang-format on */
diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl
index 4c0fe47f6b..e59bca8b07 100644
--- a/drivers/gles3/shaders/sky.glsl
+++ b/drivers/gles3/shaders/sky.glsl
@@ -10,6 +10,9 @@ mode_cubemap_quarter_res = #define USE_CUBEMAP_PASS \n#define USE_QUARTER_RES_PA
#[specializations]
+USE_MULTIVIEW = false
+USE_INVERTED_Y = true
+
#[vertex]
layout(location = 0) in vec2 vertex_attrib;
@@ -19,7 +22,11 @@ out vec2 uv_interp;
void main() {
uv_interp = vertex_attrib;
+#ifdef USE_INVERTED_Y
gl_Position = vec4(uv_interp, 1.0, 1.0);
+#else
+ gl_Position = vec4(uv_interp.x, uv_interp.y * -1.0, 1.0, 1.0);
+#endif
}
/* clang-format off */
@@ -37,6 +44,9 @@ uniform samplerCube radiance; //texunit:-1
#ifdef USE_CUBEMAP_PASS
uniform samplerCube half_res; //texunit:-2
uniform samplerCube quarter_res; //texunit:-3
+#elif defined(USE_MULTIVIEW)
+uniform sampler2DArray half_res; //texunit:-2
+uniform sampler2DArray quarter_res; //texunit:-3
#else
uniform sampler2D half_res; //texunit:-2
uniform sampler2D quarter_res; //texunit:-3
@@ -102,6 +112,15 @@ uniform float fog_density;
uniform float z_far;
uniform uint directional_light_count;
+#ifdef USE_MULTIVIEW
+layout(std140) uniform MultiviewData { // ubo:5
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
+ highp vec4 eye_offset[MAX_VIEWS];
+}
+multiview_data;
+#endif
+
layout(location = 0) out vec4 frag_color;
#ifdef USE_DEBANDING
@@ -115,9 +134,20 @@ vec3 interleaved_gradient_noise(vec2 pos) {
void main() {
vec3 cube_normal;
+#ifdef USE_MULTIVIEW
+ // In multiview our projection matrices will contain positional and rotational offsets that we need to properly unproject.
+ vec4 unproject = vec4(uv_interp.x, uv_interp.y, 1.0, 1.0);
+ vec4 unprojected = multiview_data.inv_projection_matrix_view[ViewIndex] * unproject;
+ cube_normal = unprojected.xyz / unprojected.w;
+ cube_normal += multiview_data.eye_offset[ViewIndex].xyz;
+#else
cube_normal.z = -1.0;
cube_normal.x = (uv_interp.x + projection.x) / projection.y;
cube_normal.y = (-uv_interp.y - projection.z) / projection.w;
+#endif
+#ifndef USE_INVERTED_Y
+ cube_normal.y *= -1.0;
+#endif
cube_normal = mat3(orientation) * cube_normal;
cube_normal = normalize(cube_normal);
@@ -146,12 +176,20 @@ void main() {
#endif
#else
#ifdef USES_HALF_RES_COLOR
+#ifdef USE_MULTIVIEW
+ half_res_color = textureLod(sampler2DArray(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(uv, ViewIndex), 0.0);
+#else
half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
#endif
+#endif
#ifdef USES_QUARTER_RES_COLOR
+#ifdef USE_MULTIVIEW
+ quarter_res_color = textureLod(sampler2DArray(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(uv, ViewIndex), 0.0);
+#else
quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
#endif
#endif
+#endif
{
diff --git a/drivers/gles3/shaders/stdlib_inc.glsl b/drivers/gles3/shaders/stdlib_inc.glsl
index d5051760d7..0b76c4334a 100644
--- a/drivers/gles3/shaders/stdlib_inc.glsl
+++ b/drivers/gles3/shaders/stdlib_inc.glsl
@@ -2,13 +2,23 @@
#ifdef USE_GLES_OVER_GL
// Floating point pack/unpack functions are part of the GLSL ES 300 specification used by web and mobile.
uint float2half(uint f) {
- return ((f >> uint(16)) & uint(0x8000)) |
- ((((f & uint(0x7f800000)) - uint(0x38000000)) >> uint(13)) & uint(0x7c00)) |
- ((f >> uint(13)) & uint(0x03ff));
+ uint e = f & uint(0x7f800000);
+ if (e <= uint(0x38000000)) {
+ return uint(0);
+ } else {
+ return ((f >> uint(16)) & uint(0x8000)) |
+ (((e - uint(0x38000000)) >> uint(13)) & uint(0x7c00)) |
+ ((f >> uint(13)) & uint(0x03ff));
+ }
}
uint half2float(uint h) {
- return ((h & uint(0x8000)) << uint(16)) | (((h & uint(0x7c00)) + uint(0x1c000)) << uint(13)) | ((h & uint(0x03ff)) << uint(13));
+ uint h_e = h & uint(0x7c00);
+ if (h_e == uint(0x0000)) {
+ return uint(0);
+ } else {
+ return ((h & uint(0x8000)) << uint(16)) | ((h_e + uint(0x1c000)) << uint(13)) | ((h & uint(0x03ff)) << uint(13));
+ }
}
uint packHalf2x16(vec2 v) {
@@ -38,23 +48,33 @@ vec2 unpackSnorm2x16(uint p) {
vec2 v = vec2(float(p & uint(0xffff)), float(p >> uint(16)));
return clamp((v - 32767.0) * vec2(0.00003051851), vec2(-1.0), vec2(1.0));
}
+
#endif
-uint packUnorm4x8(vec4 v) {
+// Compatibility renames. These are exposed with the "godot_" prefix
+// to work around an Adreno bug which was exposing these ES310 functions
+// in ES300 shaders. Internally, we must use the "godot_" prefix, but user shaders
+// will be mapped automatically.
+uint godot_packUnorm4x8(vec4 v) {
uvec4 uv = uvec4(round(clamp(v, vec4(0.0), vec4(1.0)) * 255.0));
return uv.x | (uv.y << uint(8)) | (uv.z << uint(16)) | (uv.w << uint(24));
}
-vec4 unpackUnorm4x8(uint p) {
+vec4 godot_unpackUnorm4x8(uint p) {
return vec4(float(p & uint(0xff)), float((p >> uint(8)) & uint(0xff)), float((p >> uint(16)) & uint(0xff)), float(p >> uint(24))) * 0.00392156862; // 1.0 / 255.0
}
-uint packSnorm4x8(vec4 v) {
+uint godot_packSnorm4x8(vec4 v) {
uvec4 uv = uvec4(round(clamp(v, vec4(-1.0), vec4(1.0)) * 127.0) + 127.0);
return uv.x | uv.y << uint(8) | uv.z << uint(16) | uv.w << uint(24);
}
-vec4 unpackSnorm4x8(uint p) {
+vec4 godot_unpackSnorm4x8(uint p) {
vec4 v = vec4(float(p & uint(0xff)), float((p >> uint(8)) & uint(0xff)), float((p >> uint(16)) & uint(0xff)), float(p >> uint(24)));
return clamp((v - vec4(127.0)) * vec4(0.00787401574), vec4(-1.0), vec4(1.0));
}
+
+#define packUnorm4x8 godot_packUnorm4x8
+#define unpackUnorm4x8 godot_unpackUnorm4x8
+#define packSnorm4x8 godot_packSnorm4x8
+#define unpackSnorm4x8 godot_unpackSnorm4x8