diff options
Diffstat (limited to 'drivers/gles3/shaders')
-rw-r--r-- | drivers/gles3/shaders/SCsub | 3 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas.glsl | 300 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas_uniforms_inc.glsl | 37 | ||||
-rw-r--r-- | drivers/gles3/shaders/cubemap_filter.glsl | 4 | ||||
-rw-r--r-- | drivers/gles3/shaders/particles.glsl | 501 | ||||
-rw-r--r-- | drivers/gles3/shaders/particles_copy.glsl | 122 | ||||
-rw-r--r-- | drivers/gles3/shaders/scene.glsl | 114 | ||||
-rw-r--r-- | drivers/gles3/shaders/skeleton.glsl | 282 | ||||
-rw-r--r-- | drivers/gles3/shaders/sky.glsl | 38 | ||||
-rw-r--r-- | drivers/gles3/shaders/stdlib_inc.glsl | 36 |
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 |