diff options
Diffstat (limited to 'drivers/gles3/shaders')
-rw-r--r-- | drivers/gles3/shaders/SCsub | 17 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas.glsl | 993 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas_shadow.glsl | 6 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas_uniforms_inc.glsl | 120 | ||||
-rw-r--r-- | drivers/gles3/shaders/copy.glsl | 180 | ||||
-rw-r--r-- | drivers/gles3/shaders/cube_to_dp.glsl | 4 | ||||
-rw-r--r-- | drivers/gles3/shaders/cubemap_filter.glsl | 218 | ||||
-rw-r--r-- | drivers/gles3/shaders/effect_blur.glsl | 4 | ||||
-rw-r--r-- | drivers/gles3/shaders/lens_distorted.glsl | 2 | ||||
-rw-r--r-- | drivers/gles3/shaders/scene.glsl | 2406 | ||||
-rw-r--r-- | drivers/gles3/shaders/sky.glsl | 168 | ||||
-rw-r--r-- | drivers/gles3/shaders/stdlib_inc.glsl | 60 | ||||
-rw-r--r-- | drivers/gles3/shaders/tonemap.glsl | 16 | ||||
-rw-r--r-- | drivers/gles3/shaders/tonemap_inc.glsl | 127 |
14 files changed, 1853 insertions, 2468 deletions
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index 47d56b9947..83ffe8b1e1 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -3,12 +3,17 @@ Import("env") if "GLES3_GLSL" in env["BUILDERS"]: - env.GLES3_GLSL("copy.glsl") + # find all include files + gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + + # find all shader code(all glsl files excluding our include files) + glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] + + # make sure we recompile shaders if include files change + env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#gles3_builders.py"]) + env.GLES3_GLSL("canvas.glsl") - env.GLES3_GLSL("canvas_shadow.glsl") + env.GLES3_GLSL("copy.glsl") env.GLES3_GLSL("scene.glsl") + env.GLES3_GLSL("sky.glsl") env.GLES3_GLSL("cubemap_filter.glsl") - env.GLES3_GLSL("cube_to_dp.glsl") - env.GLES3_GLSL("effect_blur.glsl") - env.GLES3_GLSL("tonemap.glsl") - env.GLES3_GLSL("lens_distorted.glsl") diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index f2b141252a..4df818cd4c 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -1,665 +1,696 @@ /* clang-format off */ -[vertex] +#[modes] -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif +mode_quad = +mode_ninepatch = #define USE_NINEPATCH +mode_primitive = #define USE_PRIMITIVE +mode_attributes = #define USE_ATTRIBUTES +mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING -uniform highp mat4 projection_matrix; -/* clang-format on */ +#[specializations] -uniform highp mat4 modelview_matrix; -uniform highp mat4 extra_matrix; -layout(location = 0) in highp vec2 vertex; +DISABLE_LIGHTING = false -#ifdef USE_ATTRIB_LIGHT_ANGLE -// shared with tangent, not used in canvas shader -layout(location = 2) in highp float light_angle; -#endif +#[vertex] +#ifdef USE_ATTRIBUTES +layout(location = 0) in vec2 vertex_attrib; layout(location = 3) in vec4 color_attrib; layout(location = 4) in vec2 uv_attrib; -#ifdef USE_ATTRIB_MODULATE -layout(location = 5) in highp vec4 modulate_attrib; -#endif - -#ifdef USE_ATTRIB_LARGE_VERTEX -// shared with skeleton attributes, not used in batched shader -layout(location = 6) in highp vec2 translate_attrib; -layout(location = 7) in highp vec4 basis_attrib; -#endif - -#ifdef USE_SKELETON -layout(location = 6) in highp vec4 bone_indices; -layout(location = 7) in highp vec4 bone_weights; -#endif +layout(location = 10) in uvec4 bone_attrib; +layout(location = 11) in vec4 weight_attrib; #ifdef USE_INSTANCING -layout(location = 8) in highp vec4 instance_xform0; -layout(location = 9) in highp vec4 instance_xform1; -layout(location = 10) in highp vec4 instance_xform2; -layout(location = 11) in highp vec4 instance_color; +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 -#ifdef USE_INSTANCE_CUSTOM -layout(location = 12) in highp vec4 instance_custom_data; #endif #endif -#ifdef USE_SKELETON -uniform highp sampler2D skeleton_texture; // texunit:-3 -uniform highp ivec2 skeleton_texture_size; -uniform highp mat4 skeleton_transform; -uniform highp mat4 skeleton_transform_inverse; -#endif +// 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:4 -out vec2 uv_interp; -out vec4 color_interp; +#MATERIAL_UNIFORMS -#ifdef USE_ATTRIB_MODULATE -// modulate doesn't need interpolating but we need to send it to the fragment shader -flat out vec4 modulate_interp; +}; #endif +/* clang-format on */ +#include "canvas_uniforms_inc.glsl" +#include "stdlib_inc.glsl" -#ifdef MODULATE_USED -uniform vec4 final_modulate; -#endif +uniform sampler2D transforms_texture; //texunit:-1 -uniform highp vec2 color_texpixel_size; +out vec2 uv_interp; +out vec4 color_interp; +out vec2 vertex_interp; +flat out int draw_data_instance; -#ifdef USE_TEXTURE_RECT +#ifdef USE_NINEPATCH -uniform vec4 dst_rect; -uniform vec4 src_rect; +out vec2 pixel_size_interp; #endif -uniform highp float time; +#GLOBALS -#ifdef USE_LIGHTING - -// light matrices -uniform highp mat4 light_matrix; -uniform highp mat4 light_matrix_inverse; -uniform highp mat4 light_local_matrix; -uniform highp mat4 shadow_matrix; -uniform highp vec4 light_color; -uniform highp vec4 light_shadow_color; -uniform highp vec2 light_pos; -uniform highp float shadowpixel_size; -uniform highp float shadow_gradient; -uniform highp float light_height; -uniform highp float light_outside_alpha; -uniform highp float shadow_distance_mult; - -out vec4 light_uv_interp; -out vec2 transformed_light_uv; -out vec4 local_rot; +void main() { + vec4 instance_custom = vec4(0.0); + draw_data_instance = gl_InstanceID; +#ifdef USE_PRIMITIVE -#ifdef USE_SHADOWS -out highp vec2 pos; -#endif + //weird bug, + //this works + vec2 vertex; + vec2 uv; + vec4 color; + + if (gl_VertexID == 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)); + } else if (gl_VertexID == 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)); + } 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)); + } + uvec4 bones = uvec4(0, 0, 0, 0); + vec4 bone_weights = vec4(0.0); -const bool at_light_pass = true; -#else -const bool at_light_pass = false; +#elif defined(USE_ATTRIBUTES) +#ifdef USE_INSTANCING + draw_data_instance = 0; #endif + vec2 vertex = vertex_attrib; + vec4 color = color_attrib * draw_data[draw_data_instance].modulation; + vec2 uv = uv_attrib; -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -vec2 select(vec2 a, vec2 b, bvec2 c) { - vec2 ret; - - ret.x = c.x ? b.x : a.x; - ret.y = c.y ? b.y : a.y; - - return ret; -} - -void main() { - vec4 color = color_attrib; - vec2 uv; + uvec4 bones = bone_attrib; + vec4 bone_weights = weight_attrib; #ifdef USE_INSTANCING - mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0))); + vec4 instance_color = vec4(unpackHalf2x16(instance_color_custom_data.x), unpackHalf2x16(instance_color_custom_data.y)); color *= instance_color; - -#ifdef USE_INSTANCE_CUSTOM - vec4 instance_custom = instance_custom_data; -#else - vec4 instance_custom = vec4(0.0); + instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w)); #endif #else - mat4 extra_matrix_instance = extra_matrix; - vec4 instance_custom = vec4(0.0); -#endif - -#ifdef USE_TEXTURE_RECT - if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z - uv = src_rect.xy + abs(src_rect.zw) * vertex.yx; - } else { - uv = src_rect.xy + abs(src_rect.zw) * vertex; - } + vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); + vec2 vertex_base = vertex_base_arr[gl_VertexID]; - vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0); + 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); - // This is what is done in the GLES 3 bindings and should - // take care of flipped rects. - // - // But it doesn't. - // I don't know why, will need to investigate further. +#endif - outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0))); + 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)); - // outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex; -#else - vec4 outvec = vec4(vertex.xy, 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 - uv = uv_attrib; +#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) + if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_PARTICLES)) { + //scale by texture size + vertex /= draw_data[draw_data_instance].color_texture_pixel_size; + } #endif +#ifdef USE_POINT_SIZE float point_size = 1.0; - +#endif { - vec2 src_vtx = outvec.xy; - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ +#CODE : VERTEX } - gl_PointSize = point_size; +#ifdef USE_NINEPATCH + pixel_size_interp = abs(draw_data[draw_data_instance].dst_rect.zw) * vertex_base; +#endif -#ifdef USE_ATTRIB_MODULATE - // modulate doesn't need interpolating but we need to send it to the fragment shader - modulate_interp = modulate_attrib; +#if !defined(SKIP_TRANSFORM_USED) + vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy; #endif -#ifdef USE_ATTRIB_LARGE_VERTEX - // transform is in attributes - vec2 temp; + color_interp = color; - temp = outvec.xy; - temp.x = (outvec.x * basis_attrib.x) + (outvec.y * basis_attrib.z); - temp.y = (outvec.x * basis_attrib.y) + (outvec.y * basis_attrib.w); + if (use_pixel_snap) { + vertex = floor(vertex + 0.5); + // precision issue on some hardware creates artifacts within texture + // offset uv by a small amount to avoid + uv += 1e-5; + } - temp += translate_attrib; - outvec.xy = temp; +#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); -#else + uvec2 tex_ofs = bone_indicesi.x * 2; - // transform is in uniforms -#if !defined(SKIP_TRANSFORM_USED) - outvec = extra_matrix_instance * outvec; - outvec = modelview_matrix * outvec; -#endif + mat2x4 m; + m = mat2x4( + texelFetch(skeleton_buffer, tex_ofs + 0), + texelFetch(skeleton_buffer, tex_ofs + 1)) * + bone_weights.x; -#endif // not large integer + tex_ofs = bone_indicesi.y * 2; - color_interp = color; + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs + 0), + texelFetch(skeleton_buffer, tex_ofs + 1)) * + bone_weights.y; -#ifdef USE_PIXEL_SNAP - outvec.xy = floor(outvec + 0.5).xy; - // precision issue on some hardware creates artifacts within texture - // offset uv by a small amount to avoid - uv += 1e-5; -#endif + tex_ofs = bone_indicesi.z * 2; -#ifdef USE_SKELETON + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs + 0), + texelFetch(skeleton_buffer, tex_ofs + 1)) * + bone_weights.z; - // look up transform from the "pose texture" - if (bone_weights != vec4(0.0)) { - highp mat4 bone_transform = mat4(0.0); + tex_ofs = bone_indicesi.w * 2; - for (int i = 0; i < 4; i++) { - ivec2 tex_ofs = ivec2(int(bone_indices[i]) * 2, 0); + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs + 0), + texelFetch(skeleton_buffer, tex_ofs + 1)) * + bone_weights.w; - highp mat4 b = mat4( - texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(0, 0)), - texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(1, 0)), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(0.0, 0.0, 0.0, 1.0)); + 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; - bone_transform += b * bone_weights[i]; - } - - mat4 bone_matrix = skeleton_transform * transpose(bone_transform) * skeleton_transform_inverse; - - outvec = bone_matrix * outvec; + //outvec = bone_matrix * outvec; } - +#endif #endif - uv_interp = uv; - gl_Position = projection_matrix * outvec; - -#ifdef USE_LIGHTING + vertex = (canvas_transform * vec4(vertex, 0.0, 1.0)).xy; - light_uv_interp.xy = (light_matrix * outvec).xy; - light_uv_interp.zw = (light_local_matrix * outvec).xy; + vertex_interp = vertex; + uv_interp = uv; - transformed_light_uv = (mat3(light_matrix_inverse) * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping + gl_Position = screen_transform * vec4(vertex, 0.0, 1.0); -#ifdef USE_SHADOWS - pos = outvec.xy; +#ifdef USE_POINT_SIZE + gl_PointSize = point_size; #endif +} -#ifdef USE_ATTRIB_LIGHT_ANGLE - // we add a fixed offset because we are using the sign later, - // and don't want floating point error around 0.0 - float la = abs(light_angle) - 1.0; +#[fragment] - // vector light angle - vec4 vla; - vla.xy = vec2(cos(la), sin(la)); - vla.zw = vec2(-vla.y, vla.x); +#include "canvas_uniforms_inc.glsl" +#include "stdlib_inc.glsl" - // vertical flip encoded in the sign - vla.zw *= sign(light_angle); +uniform sampler2D atlas_texture; //texunit:-2 +uniform sampler2D shadow_atlas_texture; //texunit:-3 +uniform sampler2D screen_texture; //texunit:-4 +uniform sampler2D sdf_texture; //texunit:-5 +uniform sampler2D normal_texture; //texunit:-6 +uniform sampler2D specular_texture; //texunit:-7 - // apply the transform matrix. - // The rotate will be encoded in the transform matrix for single rects, - // and just the flips in the light angle. - // For batching we will encode the rotation and the flips - // in the light angle, and can use the same shader. - local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.xy, 0.0, 0.0))).xy); - local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.zw, 0.0, 0.0))).xy); -#else - local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy); - local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy); -#ifdef USE_TEXTURE_RECT - local_rot.xy *= sign(src_rect.z); - local_rot.zw *= sign(src_rect.w); -#endif -#endif // not using light angle +uniform sampler2D color_texture; //texunit:0 -#endif -} +in vec2 uv_interp; +in vec4 color_interp; +in vec2 vertex_interp; +flat in int draw_data_instance; -/* clang-format off */ -[fragment] +#ifdef USE_NINEPATCH + +in vec2 pixel_size_interp; -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif #endif -uniform sampler2D color_texture; // texunit:-1 -/* clang-format on */ -uniform highp vec2 color_texpixel_size; -uniform mediump sampler2D normal_texture; // texunit:-2 +layout(location = 0) out vec4 frag_color; + +#ifdef MATERIAL_UNIFORMS_USED +layout(std140) uniform MaterialUniforms{ +//ubo:4 -in mediump vec2 uv_interp; -in mediump vec4 color_interp; +#MATERIAL_UNIFORMS -#ifdef USE_ATTRIB_MODULATE -in mediump vec4 modulate_interp; +}; #endif -uniform highp float time; +vec2 screen_uv_to_sdf(vec2 p_uv) { + return screen_to_sdf * p_uv; +} -uniform vec4 final_modulate; +float texture_sdf(vec2 p_sdf) { + vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw; + float d = texture(sdf_texture, uv).r; + d *= SDF_MAX_LENGTH; + return d * tex_to_sdf; +} -#ifdef SCREEN_TEXTURE_USED +vec2 texture_sdf_normal(vec2 p_sdf) { + vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw; -uniform sampler2D screen_texture; // texunit:-4 + const float EPSILON = 0.001; + return normalize(vec2( + texture(sdf_texture, uv + vec2(EPSILON, 0.0)).r - texture(sdf_texture, uv - vec2(EPSILON, 0.0)).r, + texture(sdf_texture, uv + vec2(0.0, EPSILON)).r - texture(sdf_texture, uv - vec2(0.0, EPSILON)).r)); +} -#endif +vec2 sdf_to_screen_uv(vec2 p_sdf) { + return p_sdf * sdf_to_screen; +} -#ifdef SCREEN_UV_USED +#GLOBALS -uniform vec2 screen_pixel_size; +#ifdef LIGHT_CODE_USED -#endif +vec4 light_compute( + vec3 light_vertex, + vec3 light_position, + vec3 normal, + vec4 light_color, + float light_energy, + vec4 specular_shininess, + inout vec4 shadow_modulate, + vec2 screen_uv, + vec2 uv, + vec4 color, bool is_directional) { + vec4 light = vec4(0.0); -#ifdef USE_LIGHTING +#CODE : LIGHT -uniform highp mat4 light_matrix; -uniform highp mat4 light_local_matrix; -uniform highp mat4 shadow_matrix; -uniform highp vec4 light_color; -uniform highp vec4 light_shadow_color; -uniform highp vec2 light_pos; -uniform highp float shadowpixel_size; -uniform highp float shadow_gradient; -uniform highp float light_height; -uniform highp float light_outside_alpha; -uniform highp float shadow_distance_mult; + return light; +} -uniform lowp sampler2D light_texture; // texunit:-6 -in vec4 light_uv_interp; -in vec2 transformed_light_uv; +#endif -in vec4 local_rot; +#ifdef USE_NINEPATCH -#ifdef USE_SHADOWS +float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) { + float tex_size = 1.0 / tex_pixel_size; -uniform highp sampler2D shadow_texture; // texunit:-5 -in highp vec2 pos; + if (pixel < margin_begin) { + return pixel * tex_pixel_size; + } else if (pixel >= draw_size - margin_end) { + return (tex_size - (draw_size - pixel)) * tex_pixel_size; + } else { + if (!bool(draw_data[draw_data_instance].flags & FLAGS_NINEPACH_DRAW_CENTER)) { + draw_center--; + } -#endif + // np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum. + if (np_repeat == 0) { // Stretch. + // Convert to ratio. + float ratio = (pixel - margin_begin) / (draw_size - margin_begin - margin_end); + // Scale to source texture. + return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size; + } else if (np_repeat == 1) { // Tile. + // Convert to offset. + float ofs = mod((pixel - margin_begin), tex_size - margin_begin - margin_end); + // Scale to source texture. + return (margin_begin + ofs) * tex_pixel_size; + } else if (np_repeat == 2) { // Tile Fit. + // Calculate scale. + float src_area = draw_size - margin_begin - margin_end; + float dst_area = tex_size - margin_begin - margin_end; + float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5)); + // Convert to ratio. + float ratio = (pixel - margin_begin) / src_area; + ratio = mod(ratio * scale, 1.0); + // Scale to source texture. + return (margin_begin + ratio * dst_area) * tex_pixel_size; + } else { // Shouldn't happen, but silences compiler warning. + return 0.0; + } + } +} -const bool at_light_pass = true; -#else -const bool at_light_pass = false; #endif -uniform bool use_default_normal; +vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) { + float cNdotL = max(0.0, dot(normal, light_vec)); -layout(location = 0) out mediump vec4 frag_color; + if (specular_shininess_used) { + //blinn + vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough + vec3 half_vec = normalize(view + light_vec); -/* clang-format off */ + float cNdotV = max(dot(normal, view), 0.0); + float cNdotH = max(dot(normal, half_vec), 0.0); + float cVdotH = max(dot(view, half_vec), 0.0); + float cLdotH = max(dot(light_vec, half_vec), 0.0); + float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); -FRAGMENT_SHADER_GLOBALS + return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL; + } else { + return light_color * base_color * cNdotL; + } +} -/* clang-format on */ +//float distance = length(shadow_pos); +vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv +#ifdef LIGHT_CODE_USED + , + vec3 shadow_modulate +#endif +) { + float shadow; + uint shadow_mode = light_data[light_base].flags & LIGHT_FLAGS_FILTER_MASK; + + if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) { + shadow = textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x; + } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) { + vec4 shadow_pixel_size = vec4(light_data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); + shadow = 0.0; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 2.0, 0.0).x; + shadow /= 5.0; + } else { //PCF13 + vec4 shadow_pixel_size = vec4(light_data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); + shadow = 0.0; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 6.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 5.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 4.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 3.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 3.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 4.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 5.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 6.0, 0.0).x; + shadow /= 13.0; + } -void light_compute( - inout vec4 light, - inout vec2 light_vec, - inout float light_height, - inout vec4 light_color, - vec2 light_uv, - inout vec4 shadow_color, - inout vec2 shadow_vec, - vec3 normal, - vec2 uv, -#if defined(SCREEN_UV_USED) - vec2 screen_uv, + vec4 shadow_color = unpackUnorm4x8(light_data[light_base].shadow_color); +#ifdef LIGHT_CODE_USED + shadow_color.rgb *= shadow_modulate; #endif - vec4 color) { - -#if defined(USE_LIGHT_SHADER_CODE) - /* clang-format off */ + shadow_color.a *= light_color.a; //respect light alpha -LIGHT_SHADER_CODE + return mix(light_color, shadow_color, shadow); +} - /* clang-format on */ +void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) { + uint blend_mode = light_data[light_base].flags & LIGHT_FLAGS_BLEND_MASK; + + switch (blend_mode) { + case LIGHT_FLAGS_BLEND_MODE_ADD: { + color.rgb += light_color.rgb * light_color.a; + } break; + case LIGHT_FLAGS_BLEND_MODE_SUB: { + color.rgb -= light_color.rgb * light_color.a; + } break; + case LIGHT_FLAGS_BLEND_MODE_MIX: { + color.rgb = mix(color.rgb, light_color.rgb, light_color.a); + } break; + } +} -#endif +float msdf_median(float r, float g, float b, float a) { + return min(max(min(r, g), min(max(r, g), b)), a); } void main() { vec4 color = color_interp; vec2 uv = uv_interp; -#ifdef USE_FORCE_REPEAT - //needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that don't support it - uv = mod(uv, vec2(1.0, 1.0)); + vec2 vertex = vertex_interp; + +#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) + +#ifdef USE_NINEPATCH + + int draw_center = 2; + uv = vec2( + map_ninepatch_axis(pixel_size_interp.x, abs(draw_data[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)); + + 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 + #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 !defined(COLOR_USED) - //default behavior, texture by color - color *= texture(color_texture, uv); #endif -#ifdef SCREEN_UV_USED - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; +#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; + + vec4 msdf_sample = texture(color_texture, uv); + vec2 msdf_size = vec2(textureSize(color_texture, 0)); + vec2 dest_size = vec2(1.0) / fwidth(uv); + float px_size = max(0.5 * dot((vec2(px_range) / msdf_size), dest_size), 1.0); + float d = msdf_median(msdf_sample.r, msdf_sample.g, msdf_sample.b, msdf_sample.a) - 0.5; + + if (outline_thickness > 0.0) { + float cr = clamp(outline_thickness, 0.0, px_range / 2.0) / px_range; + float a = clamp((d + cr) * px_size, 0.0, 1.0); + color.a = a * color.a; + } else { + float a = clamp(d * px_size + 0.5, 0.0, 1.0); + color.a = a * color.a; + } + + } else { +#else + { #endif + color *= texture(color_texture, uv); + } + + uint light_count = (draw_data[draw_data_instance].flags >> FLAGS_LIGHT_COUNT_SHIFT) & uint(0xF); //max 16 lights + bool using_light = light_count > uint(0) || directional_light_count > uint(0); vec3 normal; #if defined(NORMAL_USED) - bool normal_used = true; #else bool normal_used = false; #endif - if (use_default_normal) { - normal.xy = texture(normal_texture, uv).xy * 2.0 - 1.0; + if (normal_used || (using_light && bool(draw_data[draw_data_instance].flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { + normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); normal_used = true; } else { normal = vec3(0.0, 0.0, 1.0); } - { - float normal_depth = 1.0; + vec4 specular_shininess; -#if defined(NORMALMAP_USED) - vec3 normal_map = vec3(0.0, 0.0, 1.0); - normal_used = true; -#endif - - /* clang-format off */ - -FRAGMENT_SHADER_CODE - - /* clang-format on */ +#if defined(SPECULAR_SHININESS_USED) -#if defined(NORMALMAP_USED) - normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); -#endif - } - -#ifdef USE_ATTRIB_MODULATE - color *= modulate_interp; + bool specular_shininess_used = true; #else -#if !defined(MODULATE_USED) - color *= final_modulate; + bool specular_shininess_used = false; #endif -#endif - -#ifdef USE_LIGHTING - - vec2 light_vec = transformed_light_uv; - vec2 shadow_vec = transformed_light_uv; - if (normal_used) { - normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy; + if (specular_shininess_used || (using_light && normal_used && bool(draw_data[draw_data_instance].flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) { + specular_shininess = texture(specular_texture, uv); + specular_shininess *= unpackUnorm4x8(draw_data[draw_data_instance].specular_shininess); + specular_shininess_used = true; + } else { + specular_shininess = vec4(1.0); } - float att = 1.0; - - vec2 light_uv = light_uv_interp.xy; - vec4 light = texture(light_texture, light_uv); - - if (any(lessThan(light_uv_interp.xy, vec2(0.0, 0.0))) || any(greaterThanEqual(light_uv_interp.xy, vec2(1.0, 1.0)))) { - color.a *= light_outside_alpha; //invisible - - } else { - float real_light_height = light_height; - vec4 real_light_color = light_color; - vec4 real_light_shadow_color = light_shadow_color; - -#if defined(USE_LIGHT_SHADER_CODE) - //light is written by the light shader - light_compute( - light, - light_vec, - real_light_height, - real_light_color, - light_uv, - real_light_shadow_color, - shadow_vec, - normal, - uv, #if defined(SCREEN_UV_USED) - screen_uv, -#endif - color); + vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; +#else + vec2 screen_uv = vec2(0.0); #endif - light *= real_light_color; - - if (normal_used) { - vec3 light_normal = normalize(vec3(light_vec, -real_light_height)); - light *= max(dot(-light_normal, normal), 0.0); - } + vec3 light_vertex = vec3(vertex, 0.0); + vec2 shadow_vertex = vertex; - color *= light; + { + float normal_map_depth = 1.0; -#ifdef USE_SHADOWS +#if defined(NORMAL_MAP_USED) + vec3 normal_map = vec3(0.0, 0.0, 1.0); + normal_used = true; +#endif -#ifdef SHADOW_VEC_USED - mat3 inverse_light_matrix = mat3(light_matrix); - inverse_light_matrix[0] = normalize(inverse_light_matrix[0]); - inverse_light_matrix[1] = normalize(inverse_light_matrix[1]); - inverse_light_matrix[2] = normalize(inverse_light_matrix[2]); - shadow_vec = (inverse_light_matrix * vec3(shadow_vec, 0.0)).xy; -#else - shadow_vec = light_uv_interp.zw; -#endif - - float angle_to_light = -atan(shadow_vec.x, shadow_vec.y); - float PI = 3.14159265358979323846264; - /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays - float ang*/ - - float su, sz; - - float abs_angle = abs(angle_to_light); - vec2 point; - float sh; - if (abs_angle < 45.0 * PI / 180.0) { - point = shadow_vec; - sh = 0.0 + (1.0 / 8.0); - } else if (abs_angle > 135.0 * PI / 180.0) { - point = -shadow_vec; - sh = 0.5 + (1.0 / 8.0); - } else if (angle_to_light > 0.0) { - point = vec2(shadow_vec.y, -shadow_vec.x); - sh = 0.25 + (1.0 / 8.0); - } else { - point = vec2(-shadow_vec.y, shadow_vec.x); - sh = 0.75 + (1.0 / 8.0); - } +#CODE : FRAGMENT - highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0); - s.xyz /= s.w; - su = s.x * 0.5 + 0.5; - sz = s.z * 0.5 + 0.5; - //sz=lightlength(light_vec); +#if defined(NORMAL_MAP_USED) + normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_map_depth); +#endif + } - highp float shadow_attenuation = 0.0; + 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; + //convert by canvas transform + normal = normalize((canvas_normal_transform * vec4(normal, 0.0)).xyz); + } -#ifdef USE_RGBA_SHADOWS -#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) + vec3 base_color = color.rgb; + if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_LIGHT_MASK)) { + color = vec4(0.0); //invisible by default due to using light mask + } +#ifdef MODE_LIGHT_ONLY + color = vec4(0.0); #else + color *= canvas_modulation; +#endif -#define SHADOW_DEPTH(m_tex, m_uv) (texture((m_tex), (m_uv)).r) +#if !defined(DISABLE_LIGHTING) && !defined(MODE_UNSHADED) -#endif + for (uint i = uint(0); i < directional_light_count; i++) { + uint light_base = i; -#ifdef SHADOW_USE_GRADIENT + vec2 direction = light_data[light_base].position; + vec4 light_color = light_data[light_base].color; - /* clang-format off */ - /* GLSL es 100 doesn't support line continuation characters(backslashes) */ -#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); } +#ifdef LIGHT_CODE_USED + vec4 shadow_modulate = vec4(1.0); + light_color = light_compute(light_vertex, vec3(direction, light_data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true); #else -#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += step(sz, sd); } - /* clang-format on */ - + if (normal_used) { + vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_data[light_base].height)); + light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used); + } #endif -#ifdef SHADOW_FILTER_NEAREST + if (bool(light_data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) { + vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_data[light_base].shadow_matrix[0], light_data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. - SHADOW_TEST(su); + vec4 shadow_uv = vec4(shadow_pos.x, light_data[light_base].shadow_y_ofs, shadow_pos.y * light_data[light_base].shadow_zfar_inv, 1.0); + light_color = light_shadow_compute(light_base, light_color, shadow_uv +#ifdef LIGHT_CODE_USED + , + shadow_modulate.rgb #endif + ); + } -#ifdef SHADOW_FILTER_PCF3 - - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - shadow_attenuation /= 3.0; - -#endif + light_blend_compute(light_base, light_color, color.rgb); + } -#ifdef SHADOW_FILTER_PCF5 + // Positional Lights - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - shadow_attenuation /= 5.0; + for (uint i = uint(0); i < MAX_LIGHTS_PER_ITEM; i++) { + if (i >= light_count) { + break; + } + uint light_base; + if (i < uint(8)) { + if (i < uint(4)) { + light_base = draw_data[draw_data_instance].lights.x; + } else { + light_base = draw_data[draw_data_instance].lights.y; + } + } else { + if (i < uint(12)) { + light_base = draw_data[draw_data_instance].lights.z; + } else { + light_base = draw_data[draw_data_instance].lights.w; + } + } + light_base >>= (i & uint(3)) * uint(8); + light_base &= uint(0xFF); -#endif + vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_data[light_base].texture_matrix[0], light_data[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. + vec2 tex_uv_atlas = tex_uv * light_data[light_base].atlas_rect.zw + light_data[light_base].atlas_rect.xy; + vec4 light_color = textureLod(atlas_texture, tex_uv_atlas, 0.0); + vec4 light_base_color = light_data[light_base].color; -#ifdef SHADOW_FILTER_PCF7 +#ifdef LIGHT_CODE_USED - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - shadow_attenuation /= 7.0; + vec4 shadow_modulate = vec4(1.0); + vec3 light_position = vec3(light_data[light_base].position, light_data[light_base].height); -#endif + light_color.rgb *= light_base_color.rgb; + light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, false); +#else -#ifdef SHADOW_FILTER_PCF9 + light_color.rgb *= light_base_color.rgb * light_base_color.a; - SHADOW_TEST(su + shadowpixel_size * 4.0); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - SHADOW_TEST(su - shadowpixel_size * 4.0); - shadow_attenuation /= 9.0; + if (normal_used) { + vec3 light_pos = vec3(light_data[light_base].position, light_data[light_base].height); + vec3 pos = light_vertex; + vec3 light_vec = normalize(light_pos - pos); + float cNdotL = max(0.0, dot(normal, light_vec)); + light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used); + } #endif + if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) { + //if outside the light texture, light color is zero + light_color.a = 0.0; + } -#ifdef SHADOW_FILTER_PCF13 - - SHADOW_TEST(su + shadowpixel_size * 6.0); - SHADOW_TEST(su + shadowpixel_size * 5.0); - SHADOW_TEST(su + shadowpixel_size * 4.0); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - SHADOW_TEST(su - shadowpixel_size * 4.0); - SHADOW_TEST(su - shadowpixel_size * 5.0); - SHADOW_TEST(su - shadowpixel_size * 6.0); - shadow_attenuation /= 13.0; - -#endif + if (bool(light_data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) { + vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_data[light_base].shadow_matrix[0], light_data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. + + vec2 pos_norm = normalize(shadow_pos); + vec2 pos_abs = abs(pos_norm); + vec2 pos_box = pos_norm / max(pos_abs.x, pos_abs.y); + vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot? + float tex_ofs; + float distance; + if (pos_rot.y > 0.0) { + if (pos_rot.x > 0.0) { + tex_ofs = pos_box.y * 0.125 + 0.125; + distance = shadow_pos.x; + } else { + tex_ofs = pos_box.x * -0.125 + (0.25 + 0.125); + distance = shadow_pos.y; + } + } else { + if (pos_rot.x < 0.0) { + tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125); + distance = -shadow_pos.x; + } else { + tex_ofs = pos_box.x * 0.125 + (0.75 + 0.125); + distance = -shadow_pos.y; + } + } + + distance *= light_data[light_base].shadow_zfar_inv; + + //float distance = length(shadow_pos); + vec4 shadow_uv = vec4(tex_ofs, light_data[light_base].shadow_y_ofs, distance, 1.0); + + light_color = light_shadow_compute(light_base, light_color, shadow_uv +#ifdef LIGHT_CODE_USED + , + shadow_modulate.rgb +#endif + ); + } - //color *= shadow_attenuation; - color = mix(real_light_shadow_color, color, shadow_attenuation); -//use shadows -#endif + light_blend_compute(light_base, light_color, color.rgb); } - -//use lighting -#endif +#endif // UNSHADED frag_color = color; } diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl index 2b3be43f6e..94485abd11 100644 --- a/drivers/gles3/shaders/canvas_shadow.glsl +++ b/drivers/gles3/shaders/canvas_shadow.glsl @@ -10,18 +10,18 @@ precision highp float; precision highp int; #endif -layout(location = 0) highp vec3 vertex; +layout(location = 0) in highp vec3 vertex; uniform highp mat4 projection_matrix; /* clang-format on */ uniform highp mat4 light_matrix; -uniform highp mat4 world_matrix; +uniform highp mat4 model_matrix; uniform highp float distance_norm; out highp vec4 position_interp; void main() { - gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex, 1.0))); + gl_Position = projection_matrix * (light_matrix * (model_matrix * vec4(vertex, 1.0))); position_interp = gl_Position; } diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl new file mode 100644 index 0000000000..852dccf415 --- /dev/null +++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl @@ -0,0 +1,120 @@ + +#define MAX_LIGHTS_PER_ITEM uint(16) + +#define M_PI 3.14159265359 + +#define SDF_MAX_LENGTH 16384.0 + +//1 means enabled, 2+ means trails in use +#define FLAGS_INSTANCING_MASK uint(0x7F) +#define FLAGS_INSTANCING_HAS_COLORS uint(1 << 7) +#define FLAGS_INSTANCING_HAS_CUSTOM_DATA uint(1 << 8) + +#define FLAGS_CLIP_RECT_UV uint(1 << 9) +#define FLAGS_TRANSPOSE_RECT uint(1 << 10) +#define FLAGS_USING_LIGHT_MASK uint(1 << 11) +#define FLAGS_NINEPACH_DRAW_CENTER uint(1 << 12) +#define FLAGS_USING_PARTICLES uint(1 << 13) + +#define FLAGS_NINEPATCH_H_MODE_SHIFT 16 +#define FLAGS_NINEPATCH_V_MODE_SHIFT 18 + +#define FLAGS_LIGHT_COUNT_SHIFT 20 + +#define FLAGS_DEFAULT_NORMAL_MAP_USED uint(1 << 26) +#define FLAGS_DEFAULT_SPECULAR_MAP_USED uint(1 << 27) + +#define FLAGS_USE_MSDF uint(1 << 28) + +// 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; +}; + +layout(std140) uniform GlobalShaderUniformData { //ubo:1 + vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS]; +}; + +layout(std140) uniform CanvasData { //ubo:0 + mat4 canvas_transform; + mat4 screen_transform; + mat4 canvas_normal_transform; + vec4 canvas_modulation; + vec2 screen_pixel_size; + float time; + bool use_pixel_snap; + + vec4 sdf_to_tex; + vec2 screen_to_sdf; + vec2 sdf_to_screen; + + uint directional_light_count; + float tex_to_sdf; + uint pad1; + uint pad2; +}; + +#define LIGHT_FLAGS_BLEND_MASK uint(3 << 16) +#define LIGHT_FLAGS_BLEND_MODE_ADD uint(0 << 16) +#define LIGHT_FLAGS_BLEND_MODE_SUB uint(1 << 16) +#define LIGHT_FLAGS_BLEND_MODE_MIX uint(2 << 16) +#define LIGHT_FLAGS_BLEND_MODE_MASK uint(3 << 16) +#define LIGHT_FLAGS_HAS_SHADOW uint(1 << 20) +#define LIGHT_FLAGS_FILTER_SHIFT 22 +#define LIGHT_FLAGS_FILTER_MASK uint(3 << 22) +#define LIGHT_FLAGS_SHADOW_NEAREST uint(0 << 22) +#define LIGHT_FLAGS_SHADOW_PCF5 uint(1 << 22) +#define LIGHT_FLAGS_SHADOW_PCF13 uint(2 << 22) + +struct Light { + mat2x4 texture_matrix; //light to texture coordinate matrix (transposed) + mat2x4 shadow_matrix; //light to shadow coordinate matrix (transposed) + vec4 color; + + uint shadow_color; // packed + uint flags; //index to light texture + float shadow_pixel_size; + float height; + + vec2 position; + float shadow_zfar_inv; + float shadow_y_ofs; + + vec4 atlas_rect; +}; + +layout(std140) uniform LightData { //ubo:2 + Light light_data[MAX_LIGHTS]; +}; + +layout(std140) uniform DrawDataInstances { //ubo:3 + + DrawData draw_data[MAX_DRAW_DATA_INSTANCES]; +}; diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index 598c6fd614..ca2fc7e36d 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -1,193 +1,59 @@ /* clang-format off */ -[vertex] +#[modes] -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif +mode_default = #define MODE_SIMPLE_COPY +mode_copy_section = #define USE_COPY_SECTION +mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR +mode_mipmap = #define MODE_MIPMAP +mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION -layout(location = 0) highp vec4 vertex_attrib; -/* clang-format on */ +#[specializations] -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -layout(location = 4) vec3 cube_in; -#else -layout(location = 4) vec2 uv_in; -#endif +#[vertex] -layout(location = 5) vec2 uv2_in; +layout(location = 0) in vec2 vertex_attrib; -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -out vec3 cube_interp; -#else out vec2 uv_interp; -#endif -out vec2 uv2_interp; - -// These definitions are here because the shader-wrapper builder does -// not understand `#elif defined()` -#ifdef USE_DISPLAY_TRANSFORM -#endif +/* clang-format on */ #ifdef USE_COPY_SECTION uniform highp vec4 copy_section; -#elif defined(USE_DISPLAY_TRANSFORM) -uniform highp mat4 display_transform; #endif void main() { -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) - cube_interp = cube_in; -#elif defined(USE_ASYM_PANO) - uv_interp = vertex_attrib.xy; -#else - uv_interp = uv_in; -#endif - - uv2_interp = uv2_in; - gl_Position = vertex_attrib; + uv_interp = vertex_attrib * 0.5 + 0.5; + gl_Position = vec4(vertex_attrib, 1.0, 1.0); #ifdef USE_COPY_SECTION + gl_Position.xy = (copy_section.xy + (uv_interp.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; uv_interp = copy_section.xy + uv_interp * copy_section.zw; - gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; -#elif defined(USE_DISPLAY_TRANSFORM) - uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy; #endif } /* clang-format off */ -[fragment] - -#define M_PI 3.14159265359 - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif +#[fragment] -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -in vec3 cube_interp; -#else in vec2 uv_interp; -#endif /* clang-format on */ - -#ifdef USE_ASYM_PANO -uniform highp mat4 pano_transform; -uniform highp vec4 asym_proj; -#endif - -#ifdef USE_CUBEMAP -uniform samplerCube source_cube; // texunit:0 -#else -uniform sampler2D source; // texunit:0 +#ifdef MODE_SIMPLE_COLOR +uniform vec4 color_in; #endif -#ifdef SEP_CBCR_TEXTURE -uniform sampler2D CbCr; //texunit:1 +#ifdef MODE_GAUSSIAN_BLUR +uniform highp vec2 pixel_size; #endif -in vec2 uv2_interp; - -#ifdef USE_MULTIPLIER -uniform float multiplier; -#endif - -#ifdef USE_CUSTOM_ALPHA -uniform float custom_alpha; -#endif - -#if defined(USE_PANORAMA) || defined(USE_ASYM_PANO) -uniform highp mat4 sky_transform; - -vec4 texturePanorama(sampler2D pano, vec3 normal) { - vec2 st = vec2( - atan(normal.x, normal.z), - acos(normal.y)); - - if (st.x < 0.0) - st.x += M_PI * 2.0; - - st /= vec2(M_PI * 2.0, M_PI); - - return texture(pano, st); -} - -#endif +uniform sampler2D source; // texunit:0 layout(location = 0) out vec4 frag_color; void main() { -#ifdef USE_PANORAMA - - vec3 cube_normal = normalize(cube_interp); - cube_normal.z = -cube_normal.z; - cube_normal = mat3(sky_transform) * cube_normal; - cube_normal.z = -cube_normal.z; - - vec4 color = texturePanorama(source, cube_normal); - -#elif defined(USE_ASYM_PANO) - - // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. - // Asymmetrical projection means the center of projection is no longer in the center of the screen but shifted. - // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image. - - vec3 cube_normal; - cube_normal.z = -1.0; - cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y; - cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a; - cube_normal = mat3(sky_transform) * mat3(pano_transform) * cube_normal; - cube_normal.z = -cube_normal.z; - - vec4 color = texturePanorama(source, normalize(cube_normal.xyz)); - -#elif defined(USE_CUBEMAP) - vec4 color = textureCube(source_cube, normalize(cube_interp)); -#elif defined(SEP_CBCR_TEXTURE) - vec4 color; - color.r = texture(source, uv_interp).r; - color.gb = texture(CbCr, uv_interp).rg - vec2(0.5, 0.5); - color.a = 1.0; -#else +#ifdef MODE_SIMPLE_COPY vec4 color = texture(source, uv_interp); + frag_color = color; #endif -#ifdef YCBCR_TO_RGB - // YCbCr -> RGB conversion - - // Using BT.601, which is the standard for SDTV is provided as a reference - color.rgb = mat3( - vec3(1.00000, 1.00000, 1.00000), - vec3(0.00000, -0.34413, 1.77200), - vec3(1.40200, -0.71414, 0.00000)) * - color.rgb; -#endif - -#ifdef USE_NO_ALPHA - color.a = 1.0; -#endif - -#ifdef USE_CUSTOM_ALPHA - color.a = custom_alpha; -#endif - -#ifdef USE_MULTIPLIER - color.rgb *= multiplier; +#ifdef MODE_SIMPLE_COLOR + frag_color = color_in; #endif - - frag_color = color; } diff --git a/drivers/gles3/shaders/cube_to_dp.glsl b/drivers/gles3/shaders/cube_to_dp.glsl index ea4df79d4e..2384529a89 100644 --- a/drivers/gles3/shaders/cube_to_dp.glsl +++ b/drivers/gles3/shaders/cube_to_dp.glsl @@ -10,9 +10,9 @@ precision mediump float; precision mediump int; #endif -layout(location = 0) highp vec4 vertex_attrib; +layout(location = 0) in highp vec4 vertex_attrib; /* clang-format on */ -layout(location = 4) vec2 uv_in; +layout(location = 4) in vec2 uv_in; out vec2 uv_interp; diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl index 04bf3ebf02..57f0d7d0b8 100644 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -1,214 +1,122 @@ /* clang-format off */ -[vertex] +#[modes] -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif +mode_default = +mode_copy = #define MODE_DIRECT_WRITE + +#[specializations] -layout(location = 0) highp vec2 vertex; +#[vertex] + +layout(location = 0) in highp vec2 vertex_attrib; /* clang-format on */ -layout(location = 4) highp vec2 uv; out highp vec2 uv_interp; void main() { - uv_interp = uv; - gl_Position = vec4(vertex, 0, 1); + uv_interp = vertex_attrib; + gl_Position = vec4(uv_interp, 0.0, 1.0); } /* clang-format off */ -[fragment] +#[fragment] -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif +#define M_PI 3.14159265359 -#ifdef USE_SOURCE_PANORAMA -uniform sampler2D source_panorama; //texunit:0 -#else uniform samplerCube source_cube; //texunit:0 -#endif + /* clang-format on */ uniform int face_id; -uniform float roughness; -in highp vec2 uv_interp; - -uniform sampler2D radical_inverse_vdc_cache; // texunit:1 - -#define M_PI 3.14159265359 - -#ifdef LOW_QUALITY - -#define SAMPLE_COUNT 64 - -#else - -#define SAMPLE_COUNT 512 +#ifndef MODE_DIRECT_WRITE +uniform int sample_count; +uniform vec4 sample_directions_mip[MAX_SAMPLE_COUNT]; +uniform float weight; #endif -#ifdef USE_SOURCE_PANORAMA - -vec4 texturePanorama(sampler2D pano, vec3 normal) { - vec2 st = vec2( - atan(normal.x, normal.z), - acos(normal.y)); +in highp vec2 uv_interp; - if (st.x < 0.0) - st.x += M_PI * 2.0; +layout(location = 0) out vec4 frag_color; - st /= vec2(M_PI * 2.0, M_PI); +#define M_PI 3.14159265359 - return textureLod(pano, st, 0.0); +// Don't include tonemap_inc.glsl because all we want is these functions, we don't want the uniforms +vec3 linear_to_srgb(vec3 color) { + return max(vec3(1.055) * pow(color, vec3(0.416666667)) - vec3(0.055), vec3(0.0)); } -#endif +vec3 srgb_to_linear(vec3 color) { + return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878); +} vec3 texelCoordToVec(vec2 uv, int faceID) { mat3 faceUvVectors[6]; // -x - faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z - faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face + faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z + faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face // +x - faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z - faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face + faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z + faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face // -y - faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z - faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face + faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z + faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face // +y - faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z - faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face + faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z + faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face // -z - faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x - faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face + faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x + faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face // +z - faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face + faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. - vec3 result; - for (int i = 0; i < 6; i++) { - if (i == faceID) { - result = (faceUvVectors[i][0] * uv.x) + (faceUvVectors[i][1] * uv.y) + faceUvVectors[i][2]; - break; - } - } + vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2]; return normalize(result); } -vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) { - float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph] - - // Compute distribution direction - float Phi = 2.0 * M_PI * Xi.x; - float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y)); - float SinTheta = sqrt(1.0 - CosTheta * CosTheta); - - // Convert to spherical direction - vec3 H; - H.x = SinTheta * cos(Phi); - H.y = SinTheta * sin(Phi); - H.z = CosTheta; - - vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); - vec3 TangentX = normalize(cross(UpVector, N)); - vec3 TangentY = cross(N, TangentX); - - // Tangent to world space - return TangentX * H.x + TangentY * H.y + N * H.z; -} - -float radical_inverse_VdC(int i) { - return texture(radical_inverse_vdc_cache, vec2(float(i) / 512.0, 0.0)).x; -} - -vec2 Hammersley(int i, int N) { - return vec2(float(i) / float(N), radical_inverse_VdC(i)); -} - -uniform bool z_flip; - -layout(location = 0) out vec4 frag_color; - void main() { vec3 color = vec3(0.0); - - vec2 uv = (uv_interp * 2.0) - 1.0; + vec2 uv = uv_interp; vec3 N = texelCoordToVec(uv, face_id); -#ifdef USE_DIRECT_WRITE - -#ifdef USE_SOURCE_PANORAMA - - frag_color = vec4(texturePanorama(source_panorama, N).rgb, 1.0); -#else - - frag_color = vec4(textureCube(source_cube, N).rgb, 1.0); -#endif //USE_SOURCE_PANORAMA - +#ifdef MODE_DIRECT_WRITE + frag_color = vec4(textureLod(source_cube, N, 0.0).rgb, 1.0); #else vec4 sum = vec4(0.0); - - for (int sample_num = 0; sample_num < SAMPLE_COUNT; sample_num++) { - vec2 xi = Hammersley(sample_num, SAMPLE_COUNT); - - vec3 H = ImportanceSampleGGX(xi, roughness, N); - vec3 V = N; - vec3 L = (2.0 * dot(V, H) * H - V); - - float NdotL = clamp(dot(N, L), 0.0, 1.0); - - if (NdotL > 0.0) { - -#ifdef USE_SOURCE_PANORAMA - vec3 val = texturePanorama(source_panorama, L).rgb; -#else - vec3 val = textureCubeLod(source_cube, L, 0.0).rgb; -#endif - //mix using Linear, to approximate high end back-end - val = mix(pow((val + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), val * (1.0 / 12.92), vec3(lessThan(val, vec3(0.04045)))); - - sum.rgb += val * NdotL; - - sum.a += NdotL; - } + vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + mat3 T; + T[0] = normalize(cross(UpVector, N)); + T[1] = cross(N, T[0]); + T[2] = N; + + for (int sample_num = 0; sample_num < sample_count; sample_num++) { + vec4 sample = sample_directions_mip[sample_num]; + vec3 L = T * sample.xyz; + vec3 val = textureLod(source_cube, L, sample.w).rgb; + // Mix using linear + val = srgb_to_linear(val); + sum.rgb += val * sample.z; } - sum /= sum.a; - - vec3 a = vec3(0.055); - sum.rgb = mix((vec3(1.0) + a) * pow(sum.rgb, vec3(1.0 / 2.4)) - a, 12.92 * sum.rgb, vec3(lessThan(sum.rgb, vec3(0.0031308)))); + sum /= weight; + sum.rgb = linear_to_srgb(sum.rgb); frag_color = vec4(sum.rgb, 1.0); #endif } diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl index 80063a7175..c9184cca77 100644 --- a/drivers/gles3/shaders/effect_blur.glsl +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -10,9 +10,9 @@ precision highp float; precision highp int; #endif -layout(location = 0) vec2 vertex_attrib; +layout(location = 0) in vec2 vertex_attrib; /* clang-format on */ -layout(location = 4) vec2 uv_in; +layout(location = 4) in vec2 uv_in; out vec2 uv_interp; diff --git a/drivers/gles3/shaders/lens_distorted.glsl b/drivers/gles3/shaders/lens_distorted.glsl index 64c2d70cc8..3aaf1050e5 100644 --- a/drivers/gles3/shaders/lens_distorted.glsl +++ b/drivers/gles3/shaders/lens_distorted.glsl @@ -10,7 +10,7 @@ precision highp float; precision highp int; #endif -layout(location = 0) highp vec2 vertex; +layout(location = 0) in highp vec2 vertex; /* clang-format on */ uniform vec2 offset; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index de2aa0fc48..cd88ba6cb7 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1,980 +1,532 @@ /* clang-format off */ -[vertex] +#[modes] -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif +mode_color = #define BASE_PASS +mode_color_instancing = #define BASE_PASS \n#define USE_INSTANCING +mode_additive = #define USE_ADDITIVE_LIGHTING +mode_additive_instancing = #define USE_ADDITIVE_LIGHTING \n#define USE_INSTANCING +mode_depth = #define MODE_RENDER_DEPTH +mode_depth_instancing = #define MODE_RENDER_DEPTH \n#define USE_INSTANCING -#define SHADER_IS_SRGB true //TODO remove +#[specializations] -#define M_PI 3.14159265359 +DISABLE_LIGHTMAP = false +DISABLE_LIGHT_DIRECTIONAL = false +DISABLE_LIGHT_OMNI = false +DISABLE_LIGHT_SPOT = false +DISABLE_FOG = false +USE_RADIANCE_MAP = true -// -// attributes -// -layout(location = 0) highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 1) vec3 normal_attrib; +#[vertex] -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) -layout(location = 2) vec4 tangent_attrib; -#endif +#define M_PI 3.14159265359 -#if defined(ENABLE_COLOR_INTERP) -layout(location = 3) vec4 color_attrib; -#endif +#define SHADER_IS_SRGB true -#if defined(ENABLE_UV_INTERP) -layout(location = 4) vec2 uv_attrib; -#endif +#include "stdlib_inc.glsl" -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -layout(location = 5) vec2 uv2_attrib; +#if !defined(MODE_RENDER_DEPTH) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) ||defined(LIGHT_CLEARCOAT_USED) +#ifndef NORMAL_USED +#define NORMAL_USED +#endif #endif -#ifdef USE_SKELETON - -#ifdef USE_SKELETON_SOFTWARE - -layout(location = 13) highp vec4 bone_transform_row_0; -layout(location = 14) highp vec4 bone_transform_row_1; -layout(location = 15) highp vec4 bone_transform_row_2; - -#else +/* +from RenderingServer: +ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit) +ARRAY_NORMAL = 1, // A2B10G10R10, A is ignored. +ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal. +ARRAY_COLOR = 3, // RGBA8 +ARRAY_TEX_UV = 4, // RG32F +ARRAY_TEX_UV2 = 5, // RG32F +ARRAY_CUSTOM0 = 6, // Depends on ArrayCustomFormat. +ARRAY_CUSTOM1 = 7, +ARRAY_CUSTOM2 = 8, +ARRAY_CUSTOM3 = 9, +ARRAY_BONES = 10, // RGBA16UI (x2 if 8 weights) +ARRAY_WEIGHTS = 11, // RGBA16UNORM (x2 if 8 weights) +*/ -layout(location = 6) vec4 bone_ids; -layout(location = 7) highp vec4 bone_weights; +/* INPUT ATTRIBS */ -uniform highp sampler2D bone_transforms; // texunit:-1 -uniform ivec2 skeleton_texture_size; +layout(location = 0) in highp vec3 vertex_attrib; +/* clang-format on */ +#ifdef NORMAL_USED +layout(location = 1) in vec3 normal_attrib; #endif +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +layout(location = 2) in vec4 tangent_attrib; #endif -#ifdef USE_INSTANCING - -layout(location = 8) highp vec4 instance_xform_row_0; -layout(location = 9) highp vec4 instance_xform_row_1; -layout(location = 10) highp vec4 instance_xform_row_2; - -layout(location = 11) highp vec4 instance_color; -layout(location = 12) highp vec4 instance_custom_data; - +#if defined(COLOR_USED) +layout(location = 3) in vec4 color_attrib; #endif -// -// uniforms -// - -uniform highp mat4 camera_matrix; -uniform highp mat4 camera_inverse_matrix; -uniform highp mat4 projection_matrix; -uniform highp mat4 projection_inverse_matrix; - -uniform highp mat4 world_transform; - -uniform highp float time; - -uniform highp vec2 viewport_size; - -#ifdef RENDER_DEPTH -uniform float light_bias; -uniform float light_normal_bias; +#ifdef UV_USED +layout(location = 4) in vec2 uv_attrib; #endif -// -// varyings -// - -#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) -out highp vec4 position_interp; +#if defined(UV2_USED) || defined(USE_LIGHTMAP) +layout(location = 5) in vec2 uv2_attrib; #endif -out highp vec3 vertex_interp; -out vec3 normal_interp; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) -out vec3 tangent_interp; -out vec3 binormal_interp; +#if defined(CUSTOM0_USED) +layout(location = 6) in vec4 custom0_attrib; #endif -#if defined(ENABLE_COLOR_INTERP) -out vec4 color_interp; +#if defined(CUSTOM1_USED) +layout(location = 7) in vec4 custom1_attrib; #endif -#if defined(ENABLE_UV_INTERP) -out vec2 uv_interp; +#if defined(CUSTOM2_USED) +layout(location = 8) in vec4 custom2_attrib; #endif -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -out vec2 uv2_interp; +#if defined(CUSTOM3_USED) +layout(location = 9) in vec4 custom3_attrib; #endif -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - -out highp float dp_clip; -uniform highp float shadow_dual_paraboloid_render_zfar; -uniform highp float shadow_dual_paraboloid_render_side; - +#if defined(BONES_USED) +layout(location = 10) in uvec4 bone_attrib; #endif -#if defined(USE_SHADOW) && defined(USE_LIGHTING) - -uniform highp mat4 light_shadow_matrix; -out highp vec4 shadow_coord; - -#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) -uniform highp mat4 light_shadow_matrix2; -out highp vec4 shadow_coord2; +#if defined(WEIGHTS_USED) +layout(location = 11) in vec4 weight_attrib; #endif -#if defined(LIGHT_USE_PSSM4) - -uniform highp mat4 light_shadow_matrix3; -uniform highp mat4 light_shadow_matrix4; -out highp vec4 shadow_coord3; -out highp vec4 shadow_coord4; - +#ifdef USE_INSTANCING +layout(location = 12) in highp vec4 instance_xform0; +layout(location = 13) in highp vec4 instance_xform1; +layout(location = 14) in highp vec4 instance_xform2; +layout(location = 15) in highp uvec4 instance_color_custom_data; // Color packed into xy, Custom data into zw. #endif -#endif +layout(std140) uniform GlobalShaderUniformData { //ubo:1 + vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS]; +}; -#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) +layout(std140) uniform SceneData { // ubo:2 + highp mat4 projection_matrix; + highp mat4 inv_projection_matrix; + highp mat4 inv_view_matrix; + highp mat4 view_matrix; -out highp vec3 diffuse_interp; -out highp vec3 specular_interp; + vec2 viewport_size; + vec2 screen_pixel_size; -// general for all lights -uniform highp vec4 light_color; -uniform highp vec4 shadow_color; -uniform highp float light_specular; + mediump vec4 ambient_light_color_energy; -// directional -uniform highp vec3 light_direction; + mediump float ambient_color_sky_mix; + bool material_uv2_mode; + float pad2; + bool use_ambient_light; + bool use_ambient_cubemap; + bool use_reflection_cubemap; -// omni -uniform highp vec3 light_position; + float fog_aerial_perspective; + float time; -uniform highp float light_range; -uniform highp float light_attenuation; + mat3 radiance_inverse_xform; -// spot -uniform highp float light_spot_attenuation; -uniform highp float light_spot_range; -uniform highp float light_spot_angle; + uint directional_light_count; + float z_far; + float z_near; + float pad; -void light_compute( - vec3 N, - vec3 L, - vec3 V, - vec3 light_color, - vec3 attenuation, - float roughness) { -//this makes lights behave closer to linear, but then addition of lights looks bad -//better left disabled + bool fog_enabled; + float fog_density; + float fog_height; + float fog_height_density; -//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); -/* -#define SRGB_APPROX(m_var) {\ - float S1 = sqrt(m_var);\ - float S2 = sqrt(S1);\ - float S3 = sqrt(S2);\ - m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ - } -*/ -#define SRGB_APPROX(m_var) + vec3 fog_light_color; + float fog_sun_scatter; +} +scene_data; - float NdotL = dot(N, L); - float cNdotL = max(NdotL, 0.0); // clamped NdotL - float NdotV = dot(N, V); - float cNdotV = max(NdotV, 0.0); +uniform highp mat4 world_transform; -#if defined(DIFFUSE_OREN_NAYAR) - vec3 diffuse_brdf_NL; -#else - float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance +#ifdef USE_LIGHTMAP +uniform highp vec4 lightmap_uv_rect; #endif -#if defined(DIFFUSE_LAMBERT_WRAP) - // energy conserving lambert wrap shader - diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); - -#elif defined(DIFFUSE_OREN_NAYAR) - - { - // see http://mimosa-pudica.net/improved-oren-nayar.html - float LdotV = dot(L, V); - - float s = LdotV - NdotL * NdotV; - float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); - - float sigma2 = roughness * roughness; // TODO: this needs checking - vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); - float B = 0.45 * sigma2 / (sigma2 + 0.09); +/* Varyings */ - diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); - } -#else - // lambert by default for everything else - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +out highp vec3 vertex_interp; +#ifdef NORMAL_USED +out vec3 normal_interp; #endif - SRGB_APPROX(diffuse_brdf_NL) - - diffuse_interp += light_color * diffuse_brdf_NL * attenuation; - - if (roughness > 0.0) { - // D - float specular_brdf_NL = 0.0; - -#if !defined(SPECULAR_DISABLED) - //normalized blinn always unless disabled - vec3 H = normalize(V + L); - float cNdotH = max(dot(N, H), 0.0); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess) * cNdotL; - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - specular_brdf_NL = blinn; +#if defined(COLOR_USED) +out vec4 color_interp; #endif - SRGB_APPROX(specular_brdf_NL) - specular_interp += specular_brdf_NL * light_color * attenuation * (1.0 / M_PI); - } -} - +#if defined(UV_USED) +out vec2 uv_interp; #endif -#ifdef USE_VERTEX_LIGHTING - -#ifdef USE_REFLECTION_PROBE1 - -uniform highp mat4 refprobe1_local_matrix; -out mediump vec4 refprobe1_reflection_normal_blend; -uniform highp vec3 refprobe1_box_extents; - -#ifndef USE_LIGHTMAP -out mediump vec3 refprobe1_ambient_normal; +#if defined(UV2_USED) +out vec2 uv2_interp; +#else +#ifdef USE_LIGHTMAP +out vec2 uv2_interp; +#endif #endif -#endif //reflection probe1 - -#ifdef USE_REFLECTION_PROBE2 - -uniform highp mat4 refprobe2_local_matrix; -out mediump vec4 refprobe2_reflection_normal_blend; -uniform highp vec3 refprobe2_box_extents; - -#ifndef USE_LIGHTMAP -out mediump vec3 refprobe2_ambient_normal; +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +out vec3 tangent_interp; +out vec3 binormal_interp; #endif -#endif //reflection probe2 +#if defined(MATERIAL_UNIFORMS_USED) -#endif //vertex lighting for refprobes +/* clang-format off */ +layout(std140) uniform MaterialUniforms { // ubo:3 -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) +#MATERIAL_UNIFORMS -out vec4 fog_interp; +}; +/* clang-format on */ -uniform mediump vec4 fog_color_base; -#ifdef LIGHT_MODE_DIRECTIONAL -uniform mediump vec4 fog_sun_color_amount; #endif -uniform bool fog_transmit_enabled; -uniform mediump float fog_transmit_curve; - -#ifdef FOG_DEPTH_ENABLED -uniform highp float fog_depth_begin; -uniform mediump float fog_depth_curve; -uniform mediump float fog_max_distance; -#endif +/* clang-format off */ -#ifdef FOG_HEIGHT_ENABLED -uniform highp float fog_height_min; -uniform highp float fog_height_max; -uniform mediump float fog_height_curve; -#endif +#GLOBALS -#endif //fog +/* clang-format on */ +invariant gl_Position; void main() { - highp vec4 vertex = vertex_attrib; - - mat4 world_matrix = world_transform; + highp vec3 vertex = vertex_attrib; + highp mat4 model_matrix = world_transform; #ifdef USE_INSTANCING - { - highp mat4 m = mat4( - instance_xform_row_0, - instance_xform_row_1, - instance_xform_row_2, - vec4(0.0, 0.0, 0.0, 1.0)); - world_matrix = world_matrix * transpose(m); - } - + highp mat4 m = mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)); + model_matrix = model_matrix * transpose(m); #endif - vec3 normal = normal_attrib; +#ifdef NORMAL_USED + vec3 normal = normal_attrib * 2.0 - 1.0; +#endif + highp mat3 model_normal_matrix = mat3(model_matrix); -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - vec3 tangent = tangent_attrib.xyz; - float binormalf = tangent_attrib.a; +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; + float binormalf = tangent_attrib.a * 2.0 - 1.0; vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif -#if defined(ENABLE_COLOR_INTERP) +#if defined(COLOR_USED) color_interp = color_attrib; #ifdef USE_INSTANCING + vec4 instance_color = vec4(unpackHalf2x16(instance_color_custom_data.x), unpackHalf2x16(instance_color_custom_data.y)); color_interp *= instance_color; #endif #endif -#if defined(ENABLE_UV_INTERP) +#if defined(UV_USED) uv_interp = uv_attrib; #endif -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) +#ifdef USE_LIGHTMAP + uv2_interp = lightmap_uv_rect.zw * uv2_attrib + lightmap_uv_rect.xy; +#else +#if defined(UV2_USED) uv2_interp = uv2_attrib; #endif +#endif #if defined(OVERRIDE_POSITION) highp vec4 position; #endif + highp mat4 projection_matrix = scene_data.projection_matrix; + highp mat4 inv_projection_matrix = scene_data.inv_projection_matrix; -#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - vertex = world_matrix * vertex; - normal = normalize((world_matrix * vec4(normal, 0.0)).xyz); -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - - tangent = normalize((world_matrix * vec4(tangent, 0.0)).xyz); - binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz); -#endif -#endif - -#ifdef USE_SKELETON - - highp mat4 bone_transform = mat4(0.0); - -#ifdef USE_SKELETON_SOFTWARE - // passing the transform as attributes - - bone_transform[0] = vec4(bone_transform_row_0.x, bone_transform_row_1.x, bone_transform_row_2.x, 0.0); - bone_transform[1] = vec4(bone_transform_row_0.y, bone_transform_row_1.y, bone_transform_row_2.y, 0.0); - bone_transform[2] = vec4(bone_transform_row_0.z, bone_transform_row_1.z, bone_transform_row_2.z, 0.0); - bone_transform[3] = vec4(bone_transform_row_0.w, bone_transform_row_1.w, bone_transform_row_2.w, 1.0); - +#ifdef USE_INSTANCING + vec4 instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w)); #else - // look up transform from the "pose texture" - { - for (int i = 0; i < 4; i++) { - ivec2 tex_ofs = ivec2(int(bone_ids[i]) * 3, 0); + vec4 instance_custom = vec4(0.0); +#endif - highp mat4 b = mat4( - texel2DFetch(bone_transforms, skeleton_texture_size, tex_ofs + ivec2(0, 0)), - texel2DFetch(bone_transforms, skeleton_texture_size, tex_ofs + ivec2(1, 0)), - texel2DFetch(bone_transforms, skeleton_texture_size, tex_ofs + ivec2(2, 0)), - vec4(0.0, 0.0, 0.0, 1.0)); + // Using world coordinates +#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - bone_transform += transpose(b) * bone_weights[i]; - } - } + vertex = (model_matrix * vec4(vertex, 1.0)).xyz; +#ifdef NORMAL_USED + normal = model_normal_matrix * normal; #endif - world_matrix = world_matrix * bone_transform; - -#endif +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -#ifdef USE_INSTANCING - vec4 instance_custom = instance_custom_data; -#else - vec4 instance_custom = vec4(0.0); + tangent = model_normal_matrix * tangent; + binormal = model_normal_matrix * binormal; #endif +#endif - mat4 local_projection_matrix = projection_matrix; - - mat4 modelview = camera_inverse_matrix * world_matrix; float roughness = 1.0; -#define projection_matrix local_projection_matrix -#define world_transform world_matrix + highp mat4 modelview = scene_data.view_matrix * model_matrix; + highp mat3 modelview_normal = mat3(scene_data.view_matrix) * model_normal_matrix; float point_size = 1.0; { - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ +#CODE : VERTEX } gl_PointSize = point_size; - vec4 outvec = vertex; - // use local coordinates + // Using local coordinates (default) #if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED) - vertex = modelview * vertex; - normal = normalize((modelview * vec4(normal, 0.0)).xyz); -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - tangent = normalize((modelview * vec4(tangent, 0.0)).xyz); - binormal = normalize((modelview * vec4(binormal, 0.0)).xyz); -#endif + vertex = (modelview * vec4(vertex, 1.0)).xyz; +#ifdef NORMAL_USED + normal = modelview_normal * normal; #endif -#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - vertex = camera_inverse_matrix * vertex; - normal = normalize((camera_inverse_matrix * vec4(normal, 0.0)).xyz); -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - tangent = normalize((camera_inverse_matrix * vec4(tangent, 0.0)).xyz); - binormal = normalize((camera_inverse_matrix * vec4(binormal, 0.0)).xyz); -#endif #endif - vertex_interp = vertex.xyz; - normal_interp = normal; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - tangent_interp = tangent; - binormal_interp = binormal; -#endif - -#ifdef RENDER_DEPTH - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - - vertex_interp.z *= shadow_dual_paraboloid_render_side; - normal_interp.z *= shadow_dual_paraboloid_render_side; - - dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias - - //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges - - highp vec3 vtx = vertex_interp + normalize(vertex_interp) * light_bias; - highp float distance = length(vtx); - vtx = normalize(vtx); - vtx.xy /= 1.0 - vtx.z; - vtx.z = (distance / shadow_dual_paraboloid_render_zfar); - vtx.z = vtx.z * 2.0 - 1.0; - - vertex_interp = vtx; - -#else - float z_ofs = light_bias; - z_ofs += (1.0 - abs(normal_interp.z)) * light_normal_bias; - - vertex_interp.z -= z_ofs; -#endif //dual parabolloid - -#endif //depth - -//vertex lighting -#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) - //vertex shaded version of lighting (more limited) - vec3 L; - vec3 light_att; - -#ifdef LIGHT_MODE_OMNI - vec3 light_vec = light_position - vertex_interp; - float light_length = length(light_vec); - - float normalized_distance = light_length / light_range; - - if (normalized_distance < 1.0) { - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); - - vec3 attenuation = vec3(omni_attenuation); - light_att = vec3(omni_attenuation); - } else { - light_att = vec3(0.0); - } - - L = normalize(light_vec); +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + binormal = modelview_normal * binormal; + tangent = modelview_normal * tangent; #endif -#ifdef LIGHT_MODE_SPOT - - vec3 light_rel_vec = light_position - vertex_interp; - float light_length = length(light_rel_vec); - float normalized_distance = light_length / light_range; - - if (normalized_distance < 1.0) { - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); - vec3 spot_dir = light_direction; - - float spot_cutoff = light_spot_angle; - - float angle = dot(-normalize(light_rel_vec), spot_dir); - - if (angle > spot_cutoff) { - float scos = max(angle, spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); - - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - - light_att = vec3(spot_attenuation); - } else { - light_att = vec3(0.0); - } - } else { - light_att = vec3(0.0); - } - - L = normalize(light_rel_vec); - -#endif - -#ifdef LIGHT_MODE_DIRECTIONAL - vec3 light_vec = -light_direction; - light_att = vec3(1.0); //no base attenuation - L = normalize(light_vec); -#endif - - diffuse_interp = vec3(0.0); - specular_interp = vec3(0.0); - light_compute(normal_interp, L, -normalize(vertex_interp), light_color.rgb, light_att, roughness); - -#endif - -//shadows (for both vertex and fragment) -#if defined(USE_SHADOW) && defined(USE_LIGHTING) - - vec4 vi4 = vec4(vertex_interp, 1.0); - shadow_coord = light_shadow_matrix * vi4; - -#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) - shadow_coord2 = light_shadow_matrix2 * vi4; -#endif - -#if defined(LIGHT_USE_PSSM4) - shadow_coord3 = light_shadow_matrix3 * vi4; - shadow_coord4 = light_shadow_matrix4 * vi4; - -#endif - -#endif //use shadow and use lighting - -#ifdef USE_VERTEX_LIGHTING - -#ifdef USE_REFLECTION_PROBE1 - { - vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); - vec3 local_pos = (refprobe1_local_matrix * vec4(vertex_interp, 1.0)).xyz; - vec3 inner_pos = abs(local_pos / refprobe1_box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - - { - vec3 local_ref_vec = (refprobe1_local_matrix * vec4(ref_normal, 0.0)).xyz; - refprobe1_reflection_normal_blend.xyz = local_ref_vec; - refprobe1_reflection_normal_blend.a = blend; - } -#ifndef USE_LIGHTMAP + // Using world coordinates +#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz; + vertex = (scene_data.view_matrix * vec4(vertex, 1.0)).xyz; +#ifdef NORMAL_USED + normal = (scene_data.view_matrix * vec4(normal, 0.0)).xyz; #endif - } - -#endif //USE_REFLECTION_PROBE1 - -#ifdef USE_REFLECTION_PROBE2 - { - vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); - vec3 local_pos = (refprobe2_local_matrix * vec4(vertex_interp, 1.0)).xyz; - vec3 inner_pos = abs(local_pos / refprobe2_box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - { - vec3 local_ref_vec = (refprobe2_local_matrix * vec4(ref_normal, 0.0)).xyz; - refprobe2_reflection_normal_blend.xyz = local_ref_vec; - refprobe2_reflection_normal_blend.a = blend; - } -#ifndef USE_LIGHTMAP - - refprobe2_ambient_normal = (refprobe2_local_matrix * vec4(normal_interp, 0.0)).xyz; +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + binormal = (scene_data.view_matrix * vec4(binormal, 0.0)).xyz; + tangent = (scene_data.view_matrix * vec4(tangent, 0.0)).xyz; #endif - } - -#endif //USE_REFLECTION_PROBE2 - -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - - float fog_amount = 0.0; - -#ifdef LIGHT_MODE_DIRECTIONAL - - vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(normalize(vertex_interp), light_direction), 0.0), 8.0)); -#else - vec3 fog_color = fog_color_base.rgb; #endif -#ifdef FOG_DEPTH_ENABLED - - { - float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); - - fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; - } + vertex_interp = vertex; +#ifdef NORMAL_USED + normal_interp = normal; #endif -#ifdef FOG_HEIGHT_ENABLED - { - float y = (camera_matrix * vec4(vertex_interp, 1.0)).y; - fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); - } +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + tangent_interp = tangent; + binormal_interp = binormal; #endif - fog_interp = vec4(fog_color, fog_amount); - -#endif //fog - -#endif //use vertex lighting #if defined(OVERRIDE_POSITION) gl_Position = position; #else gl_Position = projection_matrix * vec4(vertex_interp, 1.0); #endif - -#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) - position_interp = gl_Position; -#endif } /* clang-format off */ -[fragment] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -#define M_PI 3.14159265359 -#define SHADER_IS_SRGB true - -// -// uniforms -// - -uniform highp mat4 camera_matrix; -/* clang-format on */ -uniform highp mat4 camera_inverse_matrix; -uniform highp mat4 projection_matrix; -uniform highp mat4 projection_inverse_matrix; - -uniform highp mat4 world_transform; - -uniform highp float time; +#[fragment] -uniform highp vec2 viewport_size; -#if defined(SCREEN_UV_USED) -uniform vec2 screen_pixel_size; +// Default to SPECULAR_SCHLICK_GGX. +#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON) +#define SPECULAR_SCHLICK_GGX #endif -#if defined(SCREEN_TEXTURE_USED) -uniform highp sampler2D screen_texture; //texunit:-4 +#if !defined(MODE_RENDER_DEPTH) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) ||defined(LIGHT_CLEARCOAT_USED) +#ifndef NORMAL_USED +#define NORMAL_USED #endif -#if defined(DEPTH_TEXTURE_USED) -uniform highp sampler2D depth_texture; //texunit:-4 #endif -#ifdef USE_REFLECTION_PROBE1 - -#ifdef USE_VERTEX_LIGHTING +#include "tonemap_inc.glsl" +#include "stdlib_inc.glsl" -in mediump vec4 refprobe1_reflection_normal_blend; -#ifndef USE_LIGHTMAP -in mediump vec3 refprobe1_ambient_normal; -#endif +/* texture unit usage, N is max_texture_unity-N -#else +1-color correction // In tonemap_inc.glsl +2-radiance +3-directional_shadow +4-positional_shadow +5-screen +6-depth -uniform bool refprobe1_use_box_project; -uniform highp vec3 refprobe1_box_extents; -uniform vec3 refprobe1_box_offset; -uniform highp mat4 refprobe1_local_matrix; - -#endif //use vertex lighting - -uniform bool refprobe1_exterior; - -uniform highp samplerCube reflection_probe1; //texunit:-5 +*/ -uniform float refprobe1_intensity; -uniform vec4 refprobe1_ambient; +#define M_PI 3.14159265359 +/* clang-format on */ -#endif //USE_REFLECTION_PROBE1 +#define SHADER_IS_SRGB true -#ifdef USE_REFLECTION_PROBE2 +/* Varyings */ -#ifdef USE_VERTEX_LIGHTING +#if defined(COLOR_USED) +in vec4 color_interp; +#endif -in mediump vec4 refprobe2_reflection_normal_blend; -#ifndef USE_LIGHTMAP -in mediump vec3 refprobe2_ambient_normal; +#if defined(UV_USED) +in vec2 uv_interp; #endif +#if defined(UV2_USED) +in vec2 uv2_interp; #else - -uniform bool refprobe2_use_box_project; -uniform highp vec3 refprobe2_box_extents; -uniform vec3 refprobe2_box_offset; -uniform highp mat4 refprobe2_local_matrix; - -#endif //use vertex lighting - -uniform bool refprobe2_exterior; - -uniform highp samplerCube reflection_probe2; //texunit:-6 - -uniform float refprobe2_intensity; -uniform vec4 refprobe2_ambient; - -#endif //USE_REFLECTION_PROBE2 - -#define RADIANCE_MAX_LOD 6.0 - -#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) - -void reflection_process(samplerCube reflection_map, -#ifdef USE_VERTEX_LIGHTING - vec3 ref_normal, -#ifndef USE_LIGHTMAP - vec3 amb_normal, +#ifdef USE_LIGHTMAP +in vec2 uv2_interp; #endif - float ref_blend, - -#else //no vertex lighting - vec3 normal, vec3 vertex, - mat4 local_matrix, - bool use_box_project, vec3 box_extents, vec3 box_offset, -#endif //vertex lighting - bool exterior, float intensity, vec4 ref_ambient, float roughness, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) { - vec4 reflection; - -#ifdef USE_VERTEX_LIGHTING - - reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; - - float blend = ref_blend; //crappier blend formula for vertex - blend *= blend; - blend = max(0.0, 1.0 - blend); - -#else //fragment lighting - - vec3 local_pos = (local_matrix * vec4(vertex, 1.0)).xyz; - - if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box - return; - } - - vec3 inner_pos = abs(local_pos / box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - blend = mix(length(inner_pos), blend, blend); - blend *= blend; - blend = max(0.0, 1.0 - blend); - - //reflect and make local - vec3 ref_normal = normalize(reflect(vertex, normal)); - ref_normal = (local_matrix * vec4(ref_normal, 0.0)).xyz; - - if (use_box_project) { //box project - - vec3 nrdir = normalize(ref_normal); - vec3 rbmax = (box_extents - local_pos) / nrdir; - vec3 rbmin = (-box_extents - local_pos) / nrdir; - - vec3 rbminmax = mix(rbmin, rbmax, vec3(greaterThan(nrdir, vec3(0.0, 0.0, 0.0)))); - - float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - vec3 posonbox = local_pos + nrdir * fa; - ref_normal = posonbox - box_offset.xyz; - } - - reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; #endif - if (exterior) { - reflection.rgb = mix(skybox, reflection.rgb, blend); - } - reflection.rgb *= intensity; - reflection.a = blend; - reflection.rgb *= blend; - - reflection_accum += reflection; - -#ifndef USE_LIGHTMAP - - vec4 ambient_out; -#ifndef USE_VERTEX_LIGHTING +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) +in vec3 tangent_interp; +in vec3 binormal_interp; +#endif - vec3 amb_normal = (local_matrix * vec4(normal, 0.0)).xyz; +#ifdef NORMAL_USED +in vec3 normal_interp; #endif - ambient_out.rgb = textureCubeLod(reflection_map, amb_normal, RADIANCE_MAX_LOD).rgb; - ambient_out.rgb = mix(ref_ambient.rgb, ambient_out.rgb, ref_ambient.a); - if (exterior) { - ambient_out.rgb = mix(ambient, ambient_out.rgb, blend); - } +in highp vec3 vertex_interp; - ambient_out.a = blend; - ambient_out.rgb *= blend; - ambient_accum += ambient_out; +#ifdef USE_RADIANCE_MAP -#endif -} +#define RADIANCE_MAX_LOD 5.0 -#endif //use refprobe 1 or 2 +uniform samplerCube radiance_map; // texunit:-2 -#ifdef USE_LIGHTMAP -uniform mediump sampler2D lightmap; //texunit:-4 -uniform mediump float lightmap_energy; #endif -#ifdef USE_LIGHTMAP_CAPTURE -uniform mediump vec4[12] lightmap_captures; -uniform bool lightmap_capture_sky; - -#endif +layout(std140) uniform GlobalShaderUniformData { //ubo:1 + vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS]; +}; -#ifdef USE_RADIANCE_MAP + /* Material Uniforms */ -uniform samplerCube radiance_map; // texunit:-2 +#if defined(MATERIAL_UNIFORMS_USED) -uniform mat4 radiance_inverse_xform; +/* clang-format off */ +layout(std140) uniform MaterialUniforms { // ubo:3 -#endif +#MATERIAL_UNIFORMS -uniform vec4 bg_color; -uniform float bg_energy; +}; +/* clang-format on */ -uniform float ambient_sky_contribution; -uniform vec4 ambient_color; -uniform float ambient_energy; +#endif -#ifdef USE_LIGHTING +layout(std140) uniform SceneData { // ubo:2 + highp mat4 projection_matrix; + highp mat4 inv_projection_matrix; + highp mat4 inv_view_matrix; + highp mat4 view_matrix; -uniform highp vec4 shadow_color; + vec2 viewport_size; + vec2 screen_pixel_size; -#ifdef USE_VERTEX_LIGHTING + mediump vec4 ambient_light_color_energy; -//get from vertex -in highp vec3 diffuse_interp; -in highp vec3 specular_interp; + mediump float ambient_color_sky_mix; + bool material_uv2_mode; + float pad2; + bool use_ambient_light; + bool use_ambient_cubemap; + bool use_reflection_cubemap; -uniform highp vec3 light_direction; //may be used by fog, so leave here + float fog_aerial_perspective; + float time; -#else -//done in fragment -// general for all lights -uniform highp vec4 light_color; + mat3 radiance_inverse_xform; -uniform highp float light_specular; + uint directional_light_count; + float z_far; + float z_near; + float pad; -// directional -uniform highp vec3 light_direction; -// omni -uniform highp vec3 light_position; + bool fog_enabled; + float fog_density; + float fog_height; + float fog_height_density; -uniform highp float light_attenuation; + vec3 fog_light_color; + float fog_sun_scatter; +} +scene_data; -// spot -uniform highp float light_spot_attenuation; -uniform highp float light_spot_range; -uniform highp float light_spot_angle; -#endif +/* clang-format off */ -//this is needed outside above if because dual paraboloid wants it -uniform highp float light_range; +#GLOBALS -#ifdef USE_SHADOW +/* clang-format on */ -uniform highp vec2 shadow_pixel_size; +//directional light data -#if defined(LIGHT_MODE_OMNI) || defined(LIGHT_MODE_SPOT) -uniform highp sampler2D light_shadow_atlas; //texunit:-3 -#endif +#ifndef DISABLE_LIGHT_DIRECTIONAL -#ifdef LIGHT_MODE_DIRECTIONAL -uniform highp sampler2D light_directional_shadow; // texunit:-3 -uniform highp vec4 light_split_offsets; -#endif +struct DirectionalLightData { + mediump vec3 direction; + mediump float energy; + mediump vec3 color; + mediump float size; + mediump vec3 pad; + mediump float specular; +}; -in highp vec4 shadow_coord; +layout(std140) uniform DirectionalLights { // ubo:7 + DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +}; -#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) -in highp vec4 shadow_coord2; #endif -#if defined(LIGHT_USE_PSSM4) - -in highp vec4 shadow_coord3; -in highp vec4 shadow_coord4; - -#endif +// omni and spot +#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; -uniform vec4 light_clamp; + mediump vec3 direction; + highp float size; -#endif // light shadow + mediump vec3 color; + mediump float attenuation; -// directional shadow + mediump float cone_attenuation; + mediump float cone_angle; + mediump float specular_amount; + bool shadow_enabled; +}; +#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; #endif -// -// varyings -// - -#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) -in highp vec4 position_interp; -#endif +#ifndef DISABLE_LIGHT_SPOT -in highp vec3 vertex_interp; -in vec3 normal_interp; +layout(std140) uniform SpotLightData { // ubo:6 -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) -in vec3 tangent_interp; -in vec3 binormal_interp; + LightData spot_lights[MAX_LIGHT_DATA_STRUCTS]; +}; +uniform uint spot_light_indices[MAX_FORWARD_LIGHTS]; +uniform int spot_light_count; #endif -#if defined(ENABLE_COLOR_INTERP) -in vec4 color_interp; +#ifdef USE_ADDITIVE_LIGHTING +uniform highp samplerCubeShadow positional_shadow; // texunit:-4 #endif -#if defined(ENABLE_UV_INTERP) -in vec2 uv_interp; -#endif +#endif // !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT) -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -in vec2 uv2_interp; -#endif +uniform highp sampler2D screen_texture; // texunit:-5 +uniform highp sampler2D depth_buffer; // texunit:-6 -in vec3 view_interp; +uniform highp mat4 world_transform; +uniform mediump float opaque_prepass_threshold; layout(location = 0) out vec4 frag_color; @@ -985,95 +537,31 @@ vec3 F0(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, vec3(metallic)); } -/* clang-format off */ - -FRAGMENT_SHADER_GLOBALS - -/* clang-format on */ - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - -in highp float dp_clip; - -#endif - -#ifdef USE_LIGHTING - -// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. -// We're dividing this factor off because the overall term we'll end up looks like -// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): -// -// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) -// -// We're basically regouping this as -// -// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] -// -// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. -// -// The contents of the D and G (G1) functions (GGX) are taken from -// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). -// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). - -/* -float G_GGX_2cos(float cos_theta_m, float alpha) { - // Schlick's approximation - // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) - // Eq. (19), although see Heitz (2014) the about the problems with his derivation. - // It nevertheless approximates GGX well with k = alpha/2. - float k = 0.5 * alpha; - return 0.5 / (cos_theta_m * (1.0 - k) + k); - - // float cos2 = cos_theta_m * cos_theta_m; - // float sin2 = (1.0 - cos2); - // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); -} -*/ - -// This approximates G_GGX_2cos(cos_theta_l, alpha) * G_GGX_2cos(cos_theta_v, alpha) -// See Filament docs, Specular G section. -float V_GGX(float cos_theta_l, float cos_theta_v, float alpha) { - return 0.5 / mix(2.0 * cos_theta_l * cos_theta_v, cos_theta_l + cos_theta_v, alpha); -} - +#if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT) float D_GGX(float cos_theta_m, float alpha) { - float alpha2 = alpha * alpha; - float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; - return alpha2 / (M_PI * d * d); + float a = cos_theta_m * alpha; + float k = alpha / (1.0 - cos_theta_m * cos_theta_m + a * a); + return k * k * (1.0 / M_PI); } -/* -float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float s_x = alpha_x * cos_phi; - float s_y = alpha_y * sin_phi; - return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); -} -*/ - -// This approximates G_GGX_anisotropic_2cos(cos_theta_l, ...) * G_GGX_anisotropic_2cos(cos_theta_v, ...) -// See Filament docs, Anisotropic specular BRDF section. -float V_GGX_anisotropic(float alpha_x, float alpha_y, float TdotV, float TdotL, float BdotV, float BdotL, float NdotV, float NdotL) { - float Lambda_V = NdotL * length(vec3(alpha_x * TdotV, alpha_y * BdotV, NdotV)); - float Lambda_L = NdotV * length(vec3(alpha_x * TdotL, alpha_y * BdotL, NdotL)); - return 0.5 / (Lambda_V + Lambda_L); +// From Earl Hammon, Jr. "PBR Diffuse Lighting for GGX+Smith Microsurfaces" https://www.gdcvault.com/play/1024478/PBR-Diffuse-Lighting-for-GGX +float V_GGX(float NdotL, float NdotV, float alpha) { + return 0.5 / mix(2.0 * NdotL * NdotV, NdotL + NdotV, alpha); } -float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi, float NdotH) { +float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { float alpha2 = alpha_x * alpha_y; - highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * NdotH); + highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * cos_theta_m); highp float v2 = dot(v, v); float w2 = alpha2 / v2; float D = alpha2 * w2 * w2 * (1.0 / M_PI); return D; +} - /* float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float r_x = cos_phi / alpha_x; - float r_y = sin_phi / alpha_y; - float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); - return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); */ +float V_GGX_anisotropic(float alpha_x, float alpha_y, float TdotV, float TdotL, float BdotV, float BdotL, float NdotV, float NdotL) { + float Lambda_V = NdotL * length(vec3(alpha_x * TdotV, alpha_y * BdotV, NdotV)); + float Lambda_L = NdotV * length(vec3(alpha_x * TdotL, alpha_y * BdotL, NdotL)); + return 0.5 / (Lambda_V + Lambda_L); } float SchlickFresnel(float u) { @@ -1082,109 +570,59 @@ float SchlickFresnel(float u) { return m2 * m2 * m; // pow(m,5) } -float GTR1(float NdotH, float a) { - if (a >= 1.0) - return 1.0 / M_PI; - float a2 = a * a; - float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; - return (a2 - 1.0) / (M_PI * log(a2) * t); -} - -void light_compute( - vec3 N, - vec3 L, - vec3 V, - vec3 B, - vec3 T, - vec3 light_color, - vec3 attenuation, - vec3 diffuse_color, - vec3 transmission, - float specular_blob_intensity, - float roughness, - float metallic, - float specular, - float rim, - float rim_tint, - float clearcoat, - float clearcoat_gloss, - float anisotropy, - inout vec3 diffuse_light, - inout vec3 specular_light, - inout float alpha) { -//this makes lights behave closer to linear, but then addition of lights looks bad -//better left disabled - -//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); -/* -#define SRGB_APPROX(m_var) {\ - float S1 = sqrt(m_var);\ - float S2 = sqrt(S1);\ - float S3 = sqrt(S2);\ - m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ - } -*/ -#define SRGB_APPROX(m_var) +void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 f0, float roughness, float metallic, float specular_amount, vec3 albedo, inout float alpha, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_roughness, vec3 vertex_normal, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 B, vec3 T, float anisotropy, +#endif + inout vec3 diffuse_light, inout vec3 specular_light) { #if defined(USE_LIGHT_SHADER_CODE) // light is written by the light shader vec3 normal = N; - vec3 albedo = diffuse_color; vec3 light = L; vec3 view = V; /* clang-format off */ -LIGHT_SHADER_CODE + +#CODE : LIGHT /* clang-format on */ #else - float NdotL = dot(N, L); + float NdotL = min(A + dot(N, L), 1.0); float cNdotL = max(NdotL, 0.0); // clamped NdotL float NdotV = dot(N, V); - float cNdotV = max(abs(NdotV), 1e-6); + float cNdotV = max(NdotV, 1e-4); -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) vec3 H = normalize(V + L); #endif -#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - float cNdotH = max(dot(N, H), 0.0); +#if defined(SPECULAR_SCHLICK_GGX) + float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); #endif -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - float cLdotH = max(dot(L, H), 0.0); +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) + float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); #endif if (metallic < 1.0) { -#if defined(DIFFUSE_OREN_NAYAR) - vec3 diffuse_brdf_NL; -#else float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance -#endif #if defined(DIFFUSE_LAMBERT_WRAP) // energy conserving lambert wrap shader diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); - -#elif defined(DIFFUSE_OREN_NAYAR) - - { - // see http://mimosa-pudica.net/improved-oren-nayar.html - float LdotV = dot(L, V); - - float s = LdotV - NdotL * NdotV; - float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); - - float sigma2 = roughness * roughness; // TODO: this needs checking - vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); - float B = 0.45 * sigma2 / (sigma2 + 0.09); - - diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); - } - #elif defined(DIFFUSE_TOON) diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); @@ -1196,230 +634,250 @@ LIGHT_SHADER_CODE float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; - /* - float energyBias = mix(roughness, 0.0, 0.5); - float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); - float fd90 = energyBias + 2.0 * VoH * VoH * roughness; - float f0 = 1.0; - float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); - float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); - - diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; - */ } #else // lambert diffuse_brdf_NL = cNdotL * (1.0 / M_PI); #endif - SRGB_APPROX(diffuse_brdf_NL) - - diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; + diffuse_light += light_color * diffuse_brdf_NL * attenuation; -#if defined(TRANSMISSION_USED) - diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; +#if defined(LIGHT_BACKLIGHT_USED) + diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; #endif -#if defined(LIGHT_USE_RIM) +#if defined(LIGHT_RIM_USED) float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); - diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; + diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color; #endif } - if (roughness > 0.0) { + if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely -#if defined(SPECULAR_SCHLICK_GGX) - vec3 specular_brdf_NL = vec3(0.0); -#else - float specular_brdf_NL = 0.0; -#endif - -#if defined(SPECULAR_BLINN) - - //normalized blinn - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess) * cNdotL; - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - specular_brdf_NL = blinn; - -#elif defined(SPECULAR_PHONG) - - vec3 R = normalize(-reflect(L, N)); - float cRdotV = max(0.0, dot(R, V)); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float phong = pow(cRdotV, shininess); - phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - specular_brdf_NL = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); + // D -#elif defined(SPECULAR_TOON) +#if defined(SPECULAR_TOON) vec3 R = normalize(-reflect(L, N)); float RdotV = dot(R, V); float mid = 1.0 - roughness; mid *= mid; - specular_brdf_NL = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; + float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; + diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection #elif defined(SPECULAR_DISABLED) // none.. + #elif defined(SPECULAR_SCHLICK_GGX) // shlick+ggx as default - -#if defined(LIGHT_USE_ANISOTROPY) 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; float XdotH = dot(T, H); float YdotH = dot(B, H); - float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH, cNdotH); - //float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); + 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 - float alpha_ggx = roughness * roughness; +#else // LIGHT_ANISOTROPY_USED float D = D_GGX(cNdotH, alpha_ggx); - //float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); float G = V_GGX(cNdotL, cNdotV, alpha_ggx); -#endif - // F - vec3 f0 = F0(metallic, specular, diffuse_color); +#endif // LIGHT_ANISOTROPY_USED + // F float cLdotH5 = SchlickFresnel(cLdotH); vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); - specular_brdf_NL = cNdotL * D * F * G; + vec3 specular_brdf_NL = cNdotL * D * F * G; + specular_light += specular_brdf_NL * light_color * attenuation * specular_amount; #endif - SRGB_APPROX(specular_brdf_NL) - specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; - -#if defined(LIGHT_USE_CLEARCOAT) +#if defined(LIGHT_CLEARCOAT_USED) + // Clearcoat ignores normal_map, use vertex normal instead + float ccNdotL = max(min(A + dot(vertex_normal, L), 1.0), 0.0); + float ccNdotH = clamp(A + dot(vertex_normal, H), 0.0, 1.0); + float ccNdotV = max(dot(vertex_normal, V), 1e-4); #if !defined(SPECULAR_SCHLICK_GGX) float cLdotH5 = SchlickFresnel(cLdotH); #endif - float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Dr = D_GGX(ccNdotH, mix(0.001, 0.1, clearcoat_roughness)); + float Gr = 0.25 / (cLdotH * cLdotH); float Fr = mix(.04, 1.0, cLdotH5); - //float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); - float Gr = V_GGX(cNdotL, cNdotV, 0.25); + float clearcoat_specular_brdf_NL = clearcoat * Gr * Fr * Dr * cNdotL; - float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - - specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; -#endif + specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; + // TODO: Clearcoat adds light to the scene right now (it is non-energy conserving), both diffuse and specular need to be scaled by (1.0 - FR) + // but to do so we need to rearrange this entire function +#endif // LIGHT_CLEARCOAT_USED } #ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); + alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0)); #endif -#endif //defined(USE_LIGHT_SHADER_CODE) +#endif //defined(LIGHT_CODE_USED) } -#endif -// shadows - -#ifdef USE_SHADOW - -#ifdef USE_RGBA_SHADOWS - -#define SHADOW_DEPTH(m_val) dot(m_val, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) - -#else - -#define SHADOW_DEPTH(m_val) (m_val).r +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} +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, #endif - -#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, SHADOW_DEPTH(texture(p_shadow, p_pos))) -#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, SHADOW_DEPTH(textureProj(p_shadow, p_pos))) - -float sample_shadow(highp sampler2D shadow, highp vec4 spos) { -#ifdef SHADOW_MODE_PCF_13 - - spos.xyz /= spos.w; - vec2 pos = spos.xy; - float depth = spos.z; - - float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth); - return avg * (1.0 / 13.0); +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, #endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_roughness, vec3 vertex_normal, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif + 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); + vec3 color = omni_lights[idx].color; + float size_A = 0.0; -#ifdef SHADOW_MODE_PCF_5 - - spos.xyz /= spos.w; - vec2 pos = spos.xy; - float depth = spos.z; + if (omni_lights[idx].size > 0.0) { + float t = omni_lights[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } - float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); - return avg * (1.0 / 5.0); + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_RIM_USED + rim * omni_attenuation, rim_tint, +#endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_roughness, vertex_normal, +#endif +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, +#endif + diffuse_light, + specular_light); +} +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, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, #endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_roughness, vec3 vertex_normal, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif + inout vec3 diffuse_light, + inout vec3 specular_light) { -#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) + 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); + 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)); + spot_attenuation *= 1.0 - pow(spot_rim, spot_lights[idx].cone_attenuation); + vec3 color = spot_lights[idx].color; + + float size_A = 0.0; + + if (spot_lights[idx].size > 0.0) { + float t = spot_lights[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } - return SAMPLE_SHADOW_TEXEL_PROJ(shadow, spos); + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha, +#ifdef LIGHT_BACKLIGHT_USED + backlight, +#endif +#ifdef LIGHT_RIM_USED + rim * spot_attenuation, rim_tint, #endif +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_roughness, vertex_normal, +#endif +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, +#endif + diffuse_light, specular_light); } +#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT) -#endif +#ifndef MODE_RENDER_DEPTH +vec4 fog_process(vec3 vertex) { + vec3 fog_color = scene_data.fog_light_color; -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) +#ifdef USE_RADIANCE_MAP +/* + if (scene_data.fog_aerial_perspective > 0.0) { + vec3 sky_fog_color = vec3(0.0); + vec3 cube_view = scene_data.radiance_inverse_xform * vertex; + // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred + float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)); -#if defined(USE_VERTEX_LIGHTING) + sky_fog_color = textureLod(radiance_map, cube_view, mip_level * RADIANCE_MAX_LOD).rgb; -in vec4 fog_interp; + fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective); + } + */ +#endif + +#ifndef DISABLE_LIGHT_DIRECTIONAL + if (scene_data.fog_sun_scatter > 0.001) { + vec4 sun_scatter = vec4(0.0); + float sun_total = 0.0; + vec3 view = normalize(vertex); + for (uint i = uint(0); i < scene_data.directional_light_count; i++) { + vec3 light_color = directional_lights[i].color * directional_lights[i].energy; + float light_amount = pow(max(dot(view, directional_lights[i].direction), 0.0), 8.0); + fog_color += light_color * light_amount * scene_data.fog_sun_scatter; + } + } +#endif // !DISABLE_LIGHT_DIRECTIONAL -#else -uniform mediump vec4 fog_color_base; -#ifdef LIGHT_MODE_DIRECTIONAL -uniform mediump vec4 fog_sun_color_amount; -#endif + float fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density)); -uniform bool fog_transmit_enabled; -uniform mediump float fog_transmit_curve; + if (abs(scene_data.fog_height_density) >= 0.0001) { + float y = (scene_data.inv_view_matrix * vec4(vertex, 1.0)).y; -#ifdef FOG_DEPTH_ENABLED -uniform highp float fog_depth_begin; -uniform mediump float fog_depth_curve; -uniform mediump float fog_max_distance; -#endif + float y_dist = y - scene_data.fog_height; -#ifdef FOG_HEIGHT_ENABLED -uniform highp float fog_height_min; -uniform highp float fog_height_max; -uniform mediump float fog_height_curve; -#endif + float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data.fog_height_density)); -#endif //vertex lit -#endif //fog + fog_amount = max(vfog_amount, fog_amount); + } -void main() { -#ifdef RENDER_DEPTH_DUAL_PARABOLOID + return vec4(fog_color, fog_amount); +} - if (dp_clip > 0.0) - discard; -#endif - highp vec3 vertex = vertex_interp; +#endif // !MODE_RENDER_DEPTH + +void main() { + //lay out everything, whatever is unused is optimized away anyway + vec3 vertex = vertex_interp; vec3 view = -normalize(vertex_interp); vec3 albedo = vec3(1.0); - vec3 transmission = vec3(0.0); + vec3 backlight = vec3(0.0); + vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0); + float transmittance_depth = 0.0; + float transmittance_boost = 0.0; float metallic = 0.0; float specular = 0.5; vec3 emission = vec3(0.0); @@ -1427,183 +885,211 @@ void main() { float rim = 0.0; float rim_tint = 0.0; float clearcoat = 0.0; - float clearcoat_gloss = 0.0; + float clearcoat_roughness = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); - float sss_strength = 0.0; //unused - // gl_FragDepth is not available in GLES2, so writing to DEPTH is not converted to gl_FragDepth by Godot compiler resulting in a - // compile error because DEPTH is not a variable. - float m_DEPTH = 0.0; - - float alpha = 1.0; - float side = 1.0; - - float specular_blob_intensity = 1.0; -#if defined(SPECULAR_TOON) - specular_blob_intensity *= specular * 2.0; + vec4 fog = vec4(0.0); +#if defined(CUSTOM_RADIANCE_USED) + vec4 custom_radiance = vec4(0.0); +#endif +#if defined(CUSTOM_IRRADIANCE_USED) + vec4 custom_irradiance = vec4(0.0); #endif -#if defined(ENABLE_AO) float ao = 1.0; float ao_light_affect = 0.0; -#endif -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - vec3 binormal = normalize(binormal_interp) * side; - vec3 tangent = normalize(tangent_interp) * side; + float alpha = 1.0; + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec3 binormal = normalize(binormal_interp); + vec3 tangent = normalize(tangent_interp); #else vec3 binormal = vec3(0.0); vec3 tangent = vec3(0.0); #endif - vec3 normal = normalize(normal_interp) * side; -#if defined(ENABLE_NORMALMAP) - vec3 normalmap = vec3(0.5); +#ifdef NORMAL_USED + vec3 normal = normalize(normal_interp); + +#if defined(DO_SIDE_CHECK) + if (!gl_FrontFacing) { + normal = -normal; + } #endif - float normaldepth = 1.0; -#if defined(ALPHA_SCISSOR_USED) - float alpha_scissor = 0.5; +#endif //NORMAL_USED + +#ifdef UV_USED + vec2 uv = uv_interp; #endif -#if defined(SCREEN_UV_USED) - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; +#if defined(UV2_USED) || defined(USE_LIGHTMAP) + vec2 uv2 = uv2_interp; #endif - { - /* clang-format off */ +#if defined(COLOR_USED) + vec4 color = color_interp; +#endif -FRAGMENT_SHADER_CODE +#if defined(NORMAL_MAP_USED) - /* clang-format on */ - } + vec3 normal_map = vec3(0.5); +#endif -#if defined(ENABLE_NORMALMAP) - normalmap.xy = normalmap.xy * 2.0 - 1.0; - normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); + float normal_map_depth = 1.0; - normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; - //normal = normalmap; -#endif + vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size; - normal = normalize(normal); + float sss_strength = 0.0; - vec3 N = normal; +#ifdef ALPHA_SCISSOR_USED + float alpha_scissor_threshold = 1.0; +#endif // ALPHA_SCISSOR_USED - vec3 specular_light = vec3(0.0, 0.0, 0.0); - vec3 diffuse_light = vec3(0.0, 0.0, 0.0); - vec3 ambient_light = vec3(0.0, 0.0, 0.0); +#ifdef ALPHA_HASH_USED + float alpha_hash_scale = 1.0; +#endif // ALPHA_HASH_USED - vec3 eye_position = view; +#ifdef ALPHA_ANTIALIASING_EDGE_USED + float alpha_antialiasing_edge = 0.0; + vec2 alpha_texture_coordinate = vec2(0.0, 0.0); +#endif // ALPHA_ANTIALIASING_EDGE_USED + { +#CODE : FRAGMENT + } -#if !defined(USE_SHADOW_TO_OPACITY) +#ifndef USE_SHADOW_TO_OPACITY #if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { + if (alpha < alpha_scissor_threshold) { discard; } #endif // ALPHA_SCISSOR_USED -#ifdef USE_DEPTH_PREPASS - if (alpha < 0.1) { +#ifdef USE_OPAQUE_PREPASS +#if !defined(ALPHA_SCISSOR_USED) + + if (alpha < opaque_prepass_threshold) { discard; } -#endif // USE_DEPTH_PREPASS -#endif // !USE_SHADOW_TO_OPACITY - -#ifdef BASE_PASS +#endif // not ALPHA_SCISSOR_USED +#endif // USE_OPAQUE_PREPASS - // IBL precalculations - float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0); - vec3 f0 = F0(metallic, specular, albedo); - vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0); +#endif // !USE_SHADOW_TO_OPACITY -#ifdef AMBIENT_LIGHT_DISABLED - ambient_light = vec3(0.0, 0.0, 0.0); -#else +#ifdef NORMAL_MAP_USED -#ifdef USE_RADIANCE_MAP + normal_map.xy = normal_map.xy * 2.0 - 1.0; + normal_map.z = sqrt(max(0.0, 1.0 - dot(normal_map.xy, normal_map.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. - vec3 ref_vec = reflect(-eye_position, N); - ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz); + normal = normalize(mix(normal, tangent * normal_map.x + binormal * normal_map.y + normal * normal_map.z, normal_map_depth)); - ref_vec.z *= -1.0; +#endif - specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy; -#ifndef USE_LIGHTMAP - { - vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz); - vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, 4.0).xyz * bg_energy; - env_ambient *= 1.0 - F; +#ifdef LIGHT_ANISOTROPY_USED - ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution); + if (anisotropy > 0.01) { + //rotation matrix + mat3 rot = mat3(tangent, binormal, normal); + //make local to space + tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0)); + binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0)); } + #endif -#else +#ifndef MODE_RENDER_DEPTH - ambient_light = ambient_color.rgb; - specular_light = bg_color.rgb * bg_energy; +#ifndef CUSTOM_FOG_USED +#ifndef DISABLE_FOG + // fog must be processed as early as possible and then packed. + // to maximize VGPR usage -#endif -#endif // AMBIENT_LIGHT_DISABLED - ambient_light *= ambient_energy; + if (scene_data.fog_enabled) { + fog = fog_process(vertex); + } +#endif // !DISABLE_FOG +#endif //!CUSTOM_FOG_USED -#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + uint fog_rg = packHalf2x16(fog.rg); + uint fog_ba = packHalf2x16(fog.ba); - vec4 ambient_accum = vec4(0.0); - vec4 reflection_accum = vec4(0.0); +#endif //!MODE_RENDER_DEPTH -#ifdef USE_REFLECTION_PROBE1 +#ifndef MODE_RENDER_DEPTH - reflection_process(reflection_probe1, -#ifdef USE_VERTEX_LIGHTING - refprobe1_reflection_normal_blend.rgb, -#ifndef USE_LIGHTMAP - refprobe1_ambient_normal, -#endif - refprobe1_reflection_normal_blend.a, -#else - normal_interp, vertex_interp, refprobe1_local_matrix, - refprobe1_use_box_project, refprobe1_box_extents, refprobe1_box_offset, -#endif - refprobe1_exterior, refprobe1_intensity, refprobe1_ambient, roughness, - ambient_light, specular_light, reflection_accum, ambient_accum); + // Convert colors to linear + albedo = srgb_to_linear(albedo); + emission = srgb_to_linear(emission); + // TODO Backlight and transmittance when used +#ifndef MODE_UNSHADED + vec3 f0 = F0(metallic, specular, albedo); + vec3 specular_light = vec3(0.0, 0.0, 0.0); + vec3 diffuse_light = vec3(0.0, 0.0, 0.0); + vec3 ambient_light = vec3(0.0, 0.0, 0.0); -#endif // USE_REFLECTION_PROBE1 +#ifdef BASE_PASS + /////////////////////// LIGHTING ////////////////////////////// -#ifdef USE_REFLECTION_PROBE2 + // IBL precalculations + float ndotv = clamp(dot(normal, view), 0.0, 1.0); + vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0); - reflection_process(reflection_probe2, -#ifdef USE_VERTEX_LIGHTING - refprobe2_reflection_normal_blend.rgb, -#ifndef USE_LIGHTMAP - refprobe2_ambient_normal, -#endif - refprobe2_reflection_normal_blend.a, +#ifdef USE_RADIANCE_MAP + if (scene_data.use_reflection_cubemap) { +#ifdef LIGHT_ANISOTROPY_USED + // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy + vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; + vec3 anisotropic_tangent = cross(anisotropic_direction, view); + vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction); + vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); + vec3 ref_vec = reflect(-view, bent_normal); #else - normal_interp, vertex_interp, refprobe2_local_matrix, - refprobe2_use_box_project, refprobe2_box_extents, refprobe2_box_offset, + vec3 ref_vec = reflect(-view, normal); +#endif + 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 = srgb_to_linear(specular_light); + specular_light *= horizon * horizon; + specular_light *= scene_data.ambient_light_color_energy.a; + } #endif - refprobe2_exterior, refprobe2_intensity, refprobe2_ambient, roughness, - ambient_light, specular_light, reflection_accum, ambient_accum); -#endif // USE_REFLECTION_PROBE2 + // Calculate Reflection probes + // Calculate Lightmaps - if (reflection_accum.a > 0.0) { - specular_light = reflection_accum.rgb / reflection_accum.a; - } +#if defined(CUSTOM_RADIANCE_USED) + specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a); +#endif // CUSTOM_RADIANCE_USED #ifndef USE_LIGHTMAP - if (ambient_accum.a > 0.0) { - ambient_light = ambient_accum.rgb / ambient_accum.a; - } + //lightmap overrides everything + if (scene_data.use_ambient_light) { + ambient_light = scene_data.ambient_light_color_energy.rgb; +#ifdef USE_RADIANCE_MAP + if (scene_data.use_ambient_cubemap) { + vec3 ambient_dir = scene_data.radiance_inverse_xform * normal; + vec3 cubemap_ambient = textureLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).rgb; + cubemap_ambient = srgb_to_linear(cubemap_ambient); + ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix); + } #endif + } +#endif // USE_LIGHTMAP + +#if defined(CUSTOM_IRRADIANCE_USED) + ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a); +#endif // CUSTOM_IRRADIANCE_USED + ambient_light *= albedo.rgb; -#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + ambient_light *= ao; + + // convert ao to direct light ao + ao = mix(1.0, ao, ao_light_affect); - // environment BRDF approximation { #if defined(DIFFUSE_TOON) //simplify for toon, as @@ -1611,436 +1097,95 @@ FRAGMENT_SHADER_CODE #else // scales the specular reflections, needs to be be computed before lighting happens, - // but after environment and reflection probes are added - //TODO: this curve is not really designed for gammaspace, should be adjusted + // but after environment, GI, and reflection probes are added + // Environment brdf approximation (Lazarov 2013) + // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); vec4 r = roughness * c0 + c1; + float ndotv = clamp(dot(normal, view), 0.0, 1.0); + 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 * F + env.y; - -#endif - } - -#ifdef USE_LIGHTMAP - //ambient light will come entirely from lightmap is lightmap is used - ambient_light = texture(lightmap, uv2_interp).rgb * lightmap_energy; -#endif - -#ifdef USE_LIGHTMAP_CAPTURE - { - vec3 cone_dirs[12]; - cone_dirs[0] = vec3(0.0, 0.0, 1.0); - cone_dirs[1] = vec3(0.866025, 0.0, 0.5); - cone_dirs[2] = vec3(0.267617, 0.823639, 0.5); - cone_dirs[3] = vec3(-0.700629, 0.509037, 0.5); - cone_dirs[4] = vec3(-0.700629, -0.509037, 0.5); - cone_dirs[5] = vec3(0.267617, -0.823639, 0.5); - cone_dirs[6] = vec3(0.0, 0.0, -1.0); - cone_dirs[7] = vec3(0.866025, 0.0, -0.5); - cone_dirs[8] = vec3(0.267617, 0.823639, -0.5); - cone_dirs[9] = vec3(-0.700629, 0.509037, -0.5); - cone_dirs[10] = vec3(-0.700629, -0.509037, -0.5); - cone_dirs[11] = vec3(0.267617, -0.823639, -0.5); - - vec3 local_normal = normalize(camera_matrix * vec4(normal, 0.0)).xyz; - vec4 captured = vec4(0.0); - float sum = 0.0; - for (int i = 0; i < 12; i++) { - float amount = max(0.0, dot(local_normal, cone_dirs[i])); //not correct, but creates a nice wrap around effect - captured += lightmap_captures[i] * amount; - sum += amount; - } - - captured /= sum; - - if (lightmap_capture_sky) { - ambient_light = mix(ambient_light, captured.rgb, captured.a); - } else { - ambient_light = captured.rgb; - } - } -#endif - -#endif //BASE PASS - -// -// Lighting -// -#ifdef USE_LIGHTING - -#ifndef USE_VERTEX_LIGHTING - vec3 L; + specular_light *= env.x * f0 + env.y; #endif - vec3 light_att = vec3(1.0); - -#ifdef LIGHT_MODE_OMNI - -#ifndef USE_VERTEX_LIGHTING - vec3 light_vec = light_position - vertex; - float light_length = length(light_vec); - - float normalized_distance = light_length / light_range; - if (normalized_distance < 1.0) { - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); - - light_att = vec3(omni_attenuation); - } else { - light_att = vec3(0.0); - } - L = normalize(light_vec); - -#endif - -#if !defined(SHADOWS_DISABLED) - -#ifdef USE_SHADOW - { - highp vec4 splane = shadow_coord; - float shadow_len = length(splane.xyz); - - splane.xyz = normalize(splane.xyz); - - vec4 clamp_rect = light_clamp; - - if (splane.z >= 0.0) { - splane.z += 1.0; - - clamp_rect.y += clamp_rect.w; - } else { - splane.z = 1.0 - splane.z; - } - - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len / light_range; - - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; - - float shadow = sample_shadow(light_shadow_atlas, splane); - - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); } -#endif - -#endif //SHADOWS_DISABLED - -#endif //type omni - -#ifdef LIGHT_MODE_DIRECTIONAL - -#ifndef USE_VERTEX_LIGHTING - vec3 light_vec = -light_direction; - L = normalize(light_vec); -#endif - float depth_z = -vertex.z; -#if !defined(SHADOWS_DISABLED) - -#ifdef USE_SHADOW - -#ifdef USE_VERTEX_LIGHTING - //compute shadows in a mobile friendly way - -#ifdef LIGHT_USE_PSSM4 - //take advantage of prefetch - float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); - float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); - float shadow3 = sample_shadow(light_directional_shadow, shadow_coord3); - float shadow4 = sample_shadow(light_directional_shadow, shadow_coord4); - - if (depth_z < light_split_offsets.w) { - float pssm_fade = 0.0; - float shadow_att = 1.0; -#ifdef LIGHT_USE_PSSM_BLEND - float shadow_att2 = 1.0; - float pssm_blend = 0.0; - bool use_blend = true; -#endif - if (depth_z < light_split_offsets.y) { - if (depth_z < light_split_offsets.x) { - shadow_att = shadow1; - -#ifdef LIGHT_USE_PSSM_BLEND - shadow_att2 = shadow2; - - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - shadow_att = shadow2; - -#ifdef LIGHT_USE_PSSM_BLEND - shadow_att2 = shadow3; +#endif // BASE_PASS - pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#ifndef DISABLE_LIGHT_DIRECTIONAL + //diffuse_light = normal; // + for (uint i = uint(0); i < scene_data.directional_light_count; i++) { + light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, 1.0, f0, roughness, metallic, 1.0, albedo, alpha, +#ifdef LIGHT_BACKLIGHT_USED + backlight, #endif - } - } else { - if (depth_z < light_split_offsets.z) { - shadow_att = shadow3; - -#if defined(LIGHT_USE_PSSM_BLEND) - shadow_att2 = shadow4; - pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); +#ifdef LIGHT_RIM_USED + rim, rim_tint, #endif - - } else { - shadow_att = shadow4; - pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); - -#if defined(LIGHT_USE_PSSM_BLEND) - use_blend = false; +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif - } - } -#if defined(LIGHT_USE_PSSM_BLEND) - if (use_blend) { - shadow_att = mix(shadow_att, shadow_att2, pssm_blend); - } +#ifdef LIGHT_ANISOTROPY_USED + binormal, + tangent, anisotropy, #endif - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att); + diffuse_light, + specular_light); } +#endif //!DISABLE_LIGHT_DIRECTIONAL -#endif //LIGHT_USE_PSSM4 - -#ifdef LIGHT_USE_PSSM2 - - //take advantage of prefetch - float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); - float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); - - if (depth_z < light_split_offsets.y) { - float shadow_att = 1.0; - float pssm_fade = 0.0; - -#ifdef LIGHT_USE_PSSM_BLEND - float shadow_att2 = 1.0; - float pssm_blend = 0.0; - bool use_blend = true; -#endif - if (depth_z < light_split_offsets.x) { - float pssm_fade = 0.0; - shadow_att = shadow1; - -#ifdef LIGHT_USE_PSSM_BLEND - shadow_att2 = shadow2; - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - shadow_att = shadow2; - pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); -#ifdef LIGHT_USE_PSSM_BLEND - use_blend = false; -#endif - } -#ifdef LIGHT_USE_PSSM_BLEND - if (use_blend) { - shadow_att = mix(shadow_att, shadow_att2, pssm_blend); +#ifndef DISABLE_LIGHT_OMNI + for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) { + if (i >= omni_light_count) { + break; } + light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 0.0, albedo, alpha, +#ifdef LIGHT_BACKLIGHT_USED + backlight, #endif - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att); - } - -#endif //LIGHT_USE_PSSM2 - -#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) - - light_att *= mix(shadow_color.rgb, vec3(1.0), sample_shadow(light_directional_shadow, shadow_coord)); -#endif //orthogonal - -#else //fragment version of pssm - - { -#ifdef LIGHT_USE_PSSM4 - if (depth_z < light_split_offsets.w) { -#elif defined(LIGHT_USE_PSSM2) - if (depth_z < light_split_offsets.y) { -#else - if (depth_z < light_split_offsets.x) { -#endif //pssm2 - - highp vec4 pssm_coord; - float pssm_fade = 0.0; - -#ifdef LIGHT_USE_PSSM_BLEND - float pssm_blend; - highp vec4 pssm_coord2; - bool use_blend = true; -#endif - -#ifdef LIGHT_USE_PSSM4 - - if (depth_z < light_split_offsets.y) { - if (depth_z < light_split_offsets.x) { - pssm_coord = shadow_coord; - -#ifdef LIGHT_USE_PSSM_BLEND - pssm_coord2 = shadow_coord2; - - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - pssm_coord = shadow_coord2; - -#ifdef LIGHT_USE_PSSM_BLEND - pssm_coord2 = shadow_coord3; - - pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#ifdef LIGHT_RIM_USED + rim, + rim_tint, #endif - } - } else { - if (depth_z < light_split_offsets.z) { - pssm_coord = shadow_coord3; - -#if defined(LIGHT_USE_PSSM_BLEND) - pssm_coord2 = shadow_coord4; - pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif - - } else { - pssm_coord = shadow_coord4; - pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); - -#if defined(LIGHT_USE_PSSM_BLEND) - use_blend = false; +#ifdef LIGHT_ANISOTROPY_USED + binormal, tangent, anisotropy, #endif - } - } - -#endif // LIGHT_USE_PSSM4 - -#ifdef LIGHT_USE_PSSM2 - if (depth_z < light_split_offsets.x) { - pssm_coord = shadow_coord; - -#ifdef LIGHT_USE_PSSM_BLEND - pssm_coord2 = shadow_coord2; - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - pssm_coord = shadow_coord2; - pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); -#ifdef LIGHT_USE_PSSM_BLEND - use_blend = false; -#endif - } - -#endif // LIGHT_USE_PSSM2 + diffuse_light, specular_light); + } +#endif // !DISABLE_LIGHT_OMNI -#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) - { - pssm_coord = shadow_coord; - } +#ifndef DISABLE_LIGHT_SPOT + for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) { + if (i >= spot_light_count) { + break; + } + light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 0.0, albedo, alpha, +#ifdef LIGHT_BACKLIGHT_USED + backlight, #endif - - float shadow = sample_shadow(light_directional_shadow, pssm_coord); - -#ifdef LIGHT_USE_PSSM_BLEND - if (use_blend) { - shadow = mix(shadow, sample_shadow(light_directional_shadow, pssm_coord2), pssm_blend); - } +#ifdef LIGHT_RIM_USED + rim, + rim_tint, #endif - - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); - } - } -#endif //use vertex lighting - -#endif //use shadow - -#endif // SHADOWS_DISABLED - +#ifdef LIGHT_CLEARCOAT_USED + clearcoat, clearcoat_roughness, normalize(normal_interp), #endif - -#ifdef LIGHT_MODE_SPOT - - light_att = vec3(1.0); - -#ifndef USE_VERTEX_LIGHTING - - vec3 light_rel_vec = light_position - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length / light_range; - - if (normalized_distance < 1.0) { - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); - vec3 spot_dir = light_direction; - - float spot_cutoff = light_spot_angle; - float angle = dot(-normalize(light_rel_vec), spot_dir); - - if (angle > spot_cutoff) { - float scos = max(angle, spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - - light_att = vec3(spot_attenuation); - } else { - light_att = vec3(0.0); - } - } else { - light_att = vec3(0.0); - } - - L = normalize(light_rel_vec); - +#ifdef LIGHT_ANISOTROPY_USED + tangent, + binormal, anisotropy, #endif - -#if !defined(SHADOWS_DISABLED) - -#ifdef USE_SHADOW - { - highp vec4 splane = shadow_coord; - - float shadow = sample_shadow(light_shadow_atlas, splane); - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); + diffuse_light, specular_light); } -#endif - -#endif // SHADOWS_DISABLED - -#endif // LIGHT_MODE_SPOT -#ifdef USE_VERTEX_LIGHTING - //vertex lighting - - specular_light += specular_interp * specular_blob_intensity * light_att; - diffuse_light += diffuse_interp * albedo * light_att; - -#else - //fragment lighting - light_compute( - normal, - L, - eye_position, - binormal, - tangent, - light_color.xyz, - light_att, - albedo, - transmission, - specular_blob_intensity * light_specular, - roughness, - metallic, - specular, - rim, - rim_tint, - clearcoat, - clearcoat_gloss, - anisotropy, - diffuse_light, - specular_light, - alpha); - -#endif //vertex lighting - -#endif //USE_LIGHTING - //compute and merge - -#ifdef USE_SHADOW_TO_OPACITY +#endif // !DISABLE_LIGHT_SPOT +#endif // !MODE_UNSHADED +#endif // !MODE_RENDER_DEPTH +#if defined(USE_SHADOW_TO_OPACITY) alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); #if defined(ALPHA_SCISSOR_USED) @@ -2049,105 +1194,60 @@ FRAGMENT_SHADER_CODE } #endif // ALPHA_SCISSOR_USED -#ifdef USE_DEPTH_PREPASS - if (alpha < 0.1) { +#ifdef USE_OPAQUE_PREPASS +#if !defined(ALPHA_SCISSOR_USED) + + if (alpha < opaque_prepass_threshold) { discard; } -#endif // USE_DEPTH_PREPASS -#endif // !USE_SHADOW_TO_OPACITY +#endif // not ALPHA_SCISSOR_USED +#endif // USE_OPAQUE_PREPASS -#ifndef RENDER_DEPTH +#endif // USE_SHADOW_TO_OPACITY -#ifdef SHADELESS +#ifdef MODE_RENDER_DEPTH +//nothing happens, so a tree-ssa optimizer will result in no fragment shader :) +#else // !MODE_RENDER_DEPTH +#ifdef MODE_UNSHADED frag_color = vec4(albedo, alpha); #else - ambient_light *= albedo; - -#if defined(ENABLE_AO) - ambient_light *= ao; - ao_light_affect = mix(1.0, ao, ao_light_affect); - specular_light *= ao_light_affect; - diffuse_light *= ao_light_affect; -#endif + diffuse_light *= albedo; diffuse_light *= 1.0 - metallic; ambient_light *= 1.0 - metallic; - frag_color = vec4(ambient_light + diffuse_light + specular_light, alpha); - - //add emission if in base pass + frag_color = vec4(diffuse_light + specular_light, alpha); #ifdef BASE_PASS - frag_color.rgb += emission; + frag_color.rgb += emission + ambient_light; #endif - // frag_color = vec4(normal, 1.0); - -//apply fog -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - -#if defined(USE_VERTEX_LIGHTING) +#endif //MODE_UNSHADED + fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba)); -#if defined(BASE_PASS) - frag_color.rgb = mix(frag_color.rgb, fog_interp.rgb, fog_interp.a); +#ifndef DISABLE_FOG + if (scene_data.fog_enabled) { +#ifdef BASE_PASS + frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); #else - frag_color.rgb *= (1.0 - fog_interp.a); + frag_color.rgb *= (1.0 - fog.a); #endif // BASE_PASS - -#else //pixel based fog - float fog_amount = 0.0; - -#ifdef LIGHT_MODE_DIRECTIONAL - - vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(eye_position, light_direction), 0.0), 8.0)); -#else - vec3 fog_color = fog_color_base.rgb; + } #endif -#ifdef FOG_DEPTH_ENABLED - - { - float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); + // Tonemap before writing as we are writing to an sRGB framebuffer + frag_color.rgb *= exposure; + frag_color.rgb = apply_tonemapping(frag_color.rgb, white); + frag_color.rgb = linear_to_srgb(frag_color.rgb); - fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; - - if (fog_transmit_enabled) { - vec3 total_light = frag_color.rgb; - float transmit = pow(fog_z, fog_transmit_curve); - fog_color = mix(max(total_light, fog_color), fog_color, transmit); - } - } +#ifdef USE_BCS + frag_color.rgb = apply_bcs(frag_color.rgb, bcs); #endif -#ifdef FOG_HEIGHT_ENABLED - { - float y = (camera_matrix * vec4(vertex, 1.0)).y; - fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); - } +#ifdef USE_COLOR_CORRECTION + frag_color.rgb = apply_color_correction(frag_color.rgb, color_correction); #endif -#if defined(BASE_PASS) - frag_color.rgb = mix(frag_color.rgb, fog_color, fog_amount); -#else - frag_color.rgb *= (1.0 - fog_amount); -#endif // BASE_PASS - -#endif //use vertex lit - -#endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - -#endif //unshaded - -#else // not RENDER_DEPTH -//depth render -#ifdef USE_RGBA_SHADOWS - - highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias - highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); - comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); - frag_color = comp; - -#endif -#endif +#endif //!MODE_RENDER_DEPTH } diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl new file mode 100644 index 0000000000..eb1befe38e --- /dev/null +++ b/drivers/gles3/shaders/sky.glsl @@ -0,0 +1,168 @@ +/* clang-format off */ +#[modes] + +mode_background = +mode_half_res = #define USE_HALF_RES_PASS +mode_quarter_res = #define USE_QUARTER_RES_PASS +mode_cubemap = #define USE_CUBEMAP_PASS +mode_cubemap_half_res = #define USE_CUBEMAP_PASS \n#define USE_HALF_RES_PASS +mode_cubemap_quarter_res = #define USE_CUBEMAP_PASS \n#define USE_QUARTER_RES_PASS + +#[specializations] + +#[vertex] + +layout(location = 0) in vec2 vertex_attrib; + +out vec2 uv_interp; +/* clang-format on */ + +void main() { + uv_interp = vertex_attrib; + gl_Position = vec4(uv_interp, 1.0, 1.0); +} + +/* clang-format off */ +#[fragment] + +#define M_PI 3.14159265359 + +#include "tonemap_inc.glsl" + +in vec2 uv_interp; + +/* clang-format on */ + +uniform samplerCube radiance; //texunit:-1 +#ifdef USE_CUBEMAP_PASS +uniform samplerCube half_res; //texunit:-2 +uniform samplerCube quarter_res; //texunit:-3 +#else +uniform sampler2D half_res; //texunit:-2 +uniform sampler2D quarter_res; //texunit:-3 +#endif + +layout(std140) uniform GlobalShaderUniformData { //ubo:1 + vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS]; +}; + +struct DirectionalLightData { + vec4 direction_energy; + vec4 color_size; + bool enabled; +}; + +layout(std140) uniform DirectionalLights { //ubo:4 + DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +} +directional_lights; + +/* clang-format off */ + +#ifdef MATERIAL_UNIFORMS_USED +layout(std140) uniform MaterialUniforms{ //ubo:3 + +#MATERIAL_UNIFORMS + +}; +#endif +/* clang-format on */ +#GLOBALS + +#ifdef USE_CUBEMAP_PASS +#define AT_CUBEMAP_PASS true +#else +#define AT_CUBEMAP_PASS false +#endif + +#ifdef USE_HALF_RES_PASS +#define AT_HALF_RES_PASS true +#else +#define AT_HALF_RES_PASS false +#endif + +#ifdef USE_QUARTER_RES_PASS +#define AT_QUARTER_RES_PASS true +#else +#define AT_QUARTER_RES_PASS false +#endif + +// mat4 is a waste of space, but we don't have an easy way to set a mat3 uniform for now +uniform mat4 orientation; +uniform vec4 projection; +uniform vec3 position; +uniform float time; + +uniform float fog_aerial_perspective; +uniform vec3 fog_light_color; +uniform float fog_sun_scatter; +uniform bool fog_enabled; +uniform float fog_density; +uniform float z_far; +uniform uint directional_light_count; + +layout(location = 0) out vec4 frag_color; + +void main() { + vec3 cube_normal; + 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; + cube_normal = mat3(orientation) * cube_normal; + cube_normal = normalize(cube_normal); + + vec2 uv = gl_FragCoord.xy; // uv_interp * 0.5 + 0.5; + + vec2 panorama_coords = vec2(atan(cube_normal.x, -cube_normal.z), acos(cube_normal.y)); + + if (panorama_coords.x < 0.0) { + panorama_coords.x += M_PI * 2.0; + } + + panorama_coords /= vec2(M_PI * 2.0, M_PI); + + vec3 color = vec3(0.0, 0.0, 0.0); + float alpha = 1.0; // Only available to subpasses + vec4 half_res_color = vec4(1.0); + vec4 quarter_res_color = vec4(1.0); + vec4 custom_fog = vec4(0.0); + +#ifdef USE_CUBEMAP_PASS +#ifdef USES_HALF_RES_COLOR + half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal); +#endif +#ifdef USES_QUARTER_RES_COLOR + quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal); +#endif +#else +#ifdef USES_HALF_RES_COLOR + half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0); +#endif +#ifdef USES_QUARTER_RES_COLOR + quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0); +#endif +#endif + + { + +#CODE : SKY + + } + + // Convert to Linear for tonemapping so color matches scene shader better + color = srgb_to_linear(color); + color *= exposure; + color = apply_tonemapping(color, white); + color = linear_to_srgb(color); + +#ifdef USE_BCS + color = apply_bcs(color, bcs); +#endif + +#ifdef USE_COLOR_CORRECTION + color = apply_color_correction(color, color_correction); +#endif + + frag_color.rgb = color; + frag_color.a = alpha; +} diff --git a/drivers/gles3/shaders/stdlib_inc.glsl b/drivers/gles3/shaders/stdlib_inc.glsl new file mode 100644 index 0000000000..d5051760d7 --- /dev/null +++ b/drivers/gles3/shaders/stdlib_inc.glsl @@ -0,0 +1,60 @@ + +#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 half2float(uint h) { + return ((h & uint(0x8000)) << uint(16)) | (((h & uint(0x7c00)) + uint(0x1c000)) << uint(13)) | ((h & uint(0x03ff)) << uint(13)); +} + +uint packHalf2x16(vec2 v) { + return float2half(floatBitsToUint(v.x)) | float2half(floatBitsToUint(v.y)) << uint(16); +} + +vec2 unpackHalf2x16(uint v) { + return vec2(uintBitsToFloat(half2float(v & uint(0xffff))), + uintBitsToFloat(half2float(v >> uint(16)))); +} + +uint packUnorm2x16(vec2 v) { + uvec2 uv = uvec2(round(clamp(v, vec2(0.0), vec2(1.0)) * 65535.0)); + return uv.x | uv.y << uint(16); +} + +vec2 unpackUnorm2x16(uint p) { + return vec2(float(p & uint(0xffff)), float(p >> uint(16))) * 0.000015259021; // 1.0 / 65535.0 optimization +} + +uint packSnorm2x16(vec2 v) { + uvec2 uv = uvec2(round(clamp(v, vec2(-1.0), vec2(1.0)) * 32767.0) + 32767.0); + return uv.x | uv.y << uint(16); +} + +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) { + 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) { + 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) { + 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 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)); +} diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index 8b3aa4d309..a478cf9170 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -10,9 +10,9 @@ precision highp float; precision highp int; #endif -layout(location = 0) vec2 vertex_attrib; +layout(location = 0) in vec2 vertex_attrib; /* clang-format on */ -layout(location = 4) vec2 uv_in; +layout(location = 4) in vec2 uv_in; out vec2 uv_interp; @@ -231,10 +231,10 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) { } void main() { - vec3 color = textureLod(source, uv_interp, 0.0).rgb; + vec4 color = textureLod(source, uv_interp, 0.0); #ifdef USE_FXAA - color = apply_fxaa(color, uv_interp, pixel_size); + color.rgb = apply_fxaa(color.rgb, uv_interp, pixel_size); #endif // Glow @@ -296,18 +296,18 @@ void main() { #endif //USE_MULTI_TEXTURE_GLOW glow *= glow_intensity; - color = apply_glow(color, glow); + color.rgb = apply_glow(color.rgb, glow); #endif // Additional effects #ifdef USE_BCS - color = apply_bcs(color, bcs); + color.rgb = apply_bcs(color.rgb, bcs); #endif #ifdef USE_COLOR_CORRECTION - color = apply_color_correction(color, color_correction); + color.rgb = apply_color_correction(color.rgb, color_correction); #endif - frag_color = vec4(color, 1.0); + frag_color = color; } diff --git a/drivers/gles3/shaders/tonemap_inc.glsl b/drivers/gles3/shaders/tonemap_inc.glsl new file mode 100644 index 0000000000..f8f12760ec --- /dev/null +++ b/drivers/gles3/shaders/tonemap_inc.glsl @@ -0,0 +1,127 @@ +#ifdef USE_BCS +uniform vec3 bcs; +#endif + +#ifdef USE_COLOR_CORRECTION +#ifdef USE_1D_LUT +uniform sampler2D source_color_correction; //texunit:-1 +#else +uniform sampler3D source_color_correction; //texunit:-1 +#endif +#endif + +layout(std140) uniform TonemapData { //ubo:0 + float exposure; + float white; + int tonemapper; + int pad; +}; + +vec3 apply_bcs(vec3 color, vec3 bcs) { + color = mix(vec3(0.0), color, bcs.x); + color = mix(vec3(0.5), color, bcs.y); + color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, bcs.z); + + return color; +} +#ifdef USE_COLOR_CORRECTION +#ifdef USE_1D_LUT +vec3 apply_color_correction(vec3 color) { + color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r; + color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g; + color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b; + return color; +} +#else +vec3 apply_color_correction(vec3 color) { + return textureLod(source_color_correction, color, 0.0).rgb; +} +#endif +#endif + +vec3 tonemap_filmic(vec3 color, float p_white) { + // exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers + // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values) + // has no effect on the curve's general shape or visual properties + const float exposure_bias = 2.0f; + const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance + const float B = 0.30f * exposure_bias; + const float C = 0.10f; + const float D = 0.20f; + const float E = 0.01f; + const float F = 0.30f; + + vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F; + float p_white_tonemapped = ((p_white * (A * p_white + C * B) + D * E) / (p_white * (A * p_white + B) + D * F)) - E / F; + + return color_tonemapped / p_white_tonemapped; +} + +// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl +// (MIT License). +vec3 tonemap_aces(vec3 color, float p_white) { + const float exposure_bias = 1.8f; + const float A = 0.0245786f; + const float B = 0.000090537f; + const float C = 0.983729f; + const float D = 0.432951f; + const float E = 0.238081f; + + // Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias` + const mat3 rgb_to_rrt = mat3( + vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias), + vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias), + vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias)); + + const mat3 odt_to_rgb = mat3( + vec3(1.60475f, -0.53108f, -0.07367f), + vec3(-0.10208f, 1.10813f, -0.00605f), + vec3(-0.00327f, -0.07276f, 1.07602f)); + + color *= rgb_to_rrt; + vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E); + color_tonemapped *= odt_to_rgb; + + p_white *= exposure_bias; + float p_white_tonemapped = (p_white * (p_white + A) - B) / (p_white * (C * p_white + D) + E); + + return color_tonemapped / p_white_tonemapped; +} + +vec3 tonemap_reinhard(vec3 color, float p_white) { + return (p_white * color + color) / (color * p_white + p_white); +} + +// This expects 0-1 range input. +vec3 linear_to_srgb(vec3 color) { + //color = clamp(color, vec3(0.0), vec3(1.0)); + //const vec3 a = vec3(0.055f); + //return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f))); + // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html + return max(vec3(1.055) * pow(color, vec3(0.416666667)) - vec3(0.055), vec3(0.0)); +} + +// This expects 0-1 range input, outside that range it behaves poorly. +vec3 srgb_to_linear(vec3 color) { + // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html + return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878); +} + +#define TONEMAPPER_LINEAR 0 +#define TONEMAPPER_REINHARD 1 +#define TONEMAPPER_FILMIC 2 +#define TONEMAPPER_ACES 3 + +vec3 apply_tonemapping(vec3 color, float p_white) { // inputs are LINEAR, always outputs clamped [0;1] color + // Ensure color values passed to tonemappers are positive. + // They can be negative in the case of negative lights, which leads to undesired behavior. + if (tonemapper == TONEMAPPER_LINEAR) { + return color; + } else if (tonemapper == TONEMAPPER_REINHARD) { + return tonemap_reinhard(max(vec3(0.0f), color), p_white); + } else if (tonemapper == TONEMAPPER_FILMIC) { + return tonemap_filmic(max(vec3(0.0f), color), p_white); + } else { // TONEMAPPER_ACES + return tonemap_aces(max(vec3(0.0f), color), p_white); + } +} |