summaryrefslogtreecommitdiff
path: root/drivers/gles3/shaders
diff options
context:
space:
mode:
authorclayjohn <claynjohn@gmail.com>2022-10-12 17:55:01 -0700
committerclayjohn <claynjohn@gmail.com>2022-10-12 17:55:01 -0700
commite600fb93a5e5cb6bdbc496393f9d96dd9a664292 (patch)
treeda2ec2d73610664662697fa1a354227e186bebf6 /drivers/gles3/shaders
parent1baefceababe8a0d63434a231c3799555a45d8e3 (diff)
Add 2D lights to OpenGL3 canvas renderer
This is an initial implementation using the same single-pass approach as the RenderingDevice.
Diffstat (limited to 'drivers/gles3/shaders')
-rw-r--r--drivers/gles3/shaders/canvas.glsl170
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl21
-rw-r--r--drivers/gles3/shaders/copy.glsl5
3 files changed, 191 insertions, 5 deletions
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index a177112476..22a11cdc29 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -211,7 +211,7 @@ void main() {
#include "canvas_uniforms_inc.glsl"
#include "stdlib_inc.glsl"
-//uniform sampler2D atlas_texture; //texunit:-2
+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
@@ -243,6 +243,77 @@ layout(std140) uniform MaterialUniforms{
#endif
#GLOBALS
+#ifndef DISABLE_LIGHTING
+#ifdef LIGHT_CODE_USED
+
+vec4 light_compute(
+ vec3 light_vertex,
+ vec3 light_position,
+ vec3 normal,
+ vec4 light_color,
+ float light_energy,
+ vec4 specular_shininess,
+ inout vec4 shadow_modulate,
+ vec2 screen_uv,
+ vec2 uv,
+ vec4 color, bool is_directional) {
+ vec4 light = vec4(0.0);
+ vec3 light_direction = vec3(0.0);
+
+ if (is_directional) {
+ light_direction = normalize(mix(vec3(light_position.xy, 0.0), vec3(0, 0, 1), light_position.z));
+ light_position = vec3(0.0);
+ } else {
+ light_direction = normalize(light_position - light_vertex);
+ }
+
+#CODE : LIGHT
+
+ return light;
+}
+
+#endif
+
+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));
+
+ if (specular_shininess_used) {
+ //blinn
+ vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough
+ vec3 half_vec = normalize(view + light_vec);
+
+ float cNdotV = max(dot(normal, view), 0.0);
+ float cNdotH = max(dot(normal, half_vec), 0.0);
+ float cVdotH = max(dot(view, half_vec), 0.0);
+ float cLdotH = max(dot(light_vec, half_vec), 0.0);
+ float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25;
+ float blinn = pow(cNdotH, shininess);
+ blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
+ float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
+
+ return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL;
+ } else {
+ return light_color * base_color * cNdotL;
+ }
+}
+
+void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
+ uint blend_mode = light_array[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
#ifdef USE_NINEPATCH
@@ -353,7 +424,8 @@ void main() {
color *= texture(color_texture, uv);
}
- bool using_light = false;
+ uint light_count = (draw_data[draw_data_instance].flags >> uint(FLAGS_LIGHT_COUNT_SHIFT)) & uint(0xF); //max 16 lights
+ bool using_light = light_count > 0u || directional_light_count > 0u;
vec3 normal;
@@ -414,11 +486,105 @@ void main() {
#endif
}
+ 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);
+ }
+
+ vec4 base_color = color;
+
#ifdef MODE_LIGHT_ONLY
color = vec4(0.0);
#else
color *= canvas_modulation;
#endif
+#if !defined(DISABLE_LIGHTING) && !defined(MODE_UNSHADED)
+
+ // Directional Lights
+
+ for (uint i = 0u; i < directional_light_count; i++) {
+ uint light_base = i;
+
+ vec2 direction = light_array[light_base].position;
+ vec4 light_color = light_array[light_base].color;
+
+#ifdef LIGHT_CODE_USED
+
+ vec4 shadow_modulate = vec4(1.0);
+ light_color = light_compute(light_vertex, vec3(direction, light_array[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, true);
+#else
+
+ if (normal_used) {
+ vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array[light_base].height));
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
+ } else {
+ light_color.rgb *= base_color.rgb;
+ }
+#endif
+
+ light_blend_compute(light_base, light_color, color.rgb);
+ }
+
+ // Positional Lights
+
+ for (uint i = 0u; i < MAX_LIGHTS_PER_ITEM; i++) {
+ if (i >= light_count) {
+ break;
+ }
+ uint light_base;
+ if (i < 8u) {
+ if (i < 4u) {
+ light_base = draw_data[draw_data_instance].lights[0];
+ } else {
+ light_base = draw_data[draw_data_instance].lights[1];
+ }
+ } else {
+ if (i < 12u) {
+ light_base = draw_data[draw_data_instance].lights[2];
+ } else {
+ light_base = draw_data[draw_data_instance].lights[3];
+ }
+ }
+ light_base >>= (i & 3u) * 8u;
+ light_base &= uint(0xFF);
+
+ vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_array[light_base].texture_matrix[0], light_array[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_array[light_base].atlas_rect.zw + light_array[light_base].atlas_rect.xy;
+ vec4 light_color = textureLod(atlas_texture, tex_uv_atlas, 0.0);
+ vec4 light_base_color = light_array[light_base].color;
+
+#ifdef LIGHT_CODE_USED
+
+ vec4 shadow_modulate = vec4(1.0);
+ vec3 light_position = vec3(light_array[light_base].position, light_array[light_base].height);
+
+ light_color.rgb *= light_base_color.rgb;
+ light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, false);
+#else
+
+ light_color.rgb *= light_base_color.rgb * light_base_color.a;
+
+ if (normal_used) {
+ vec3 light_pos = vec3(light_array[light_base].position, light_array[light_base].height);
+ vec3 pos = light_vertex;
+ vec3 light_vec = normalize(light_pos - pos);
+
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
+ } else {
+ light_color.rgb *= base_color.rgb;
+ }
+#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;
+ }
+
+ light_blend_compute(light_base, light_color, color.rgb);
+ }
+#endif
+
frag_color = color;
}
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index 6b65e09cbf..43d275205f 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -94,6 +94,27 @@ layout(std140) uniform CanvasData { //ubo:0
#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_array[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 ca2fc7e36d..796ba79c2e 100644
--- a/drivers/gles3/shaders/copy.glsl
+++ b/drivers/gles3/shaders/copy.glsl
@@ -2,7 +2,7 @@
#[modes]
mode_default = #define MODE_SIMPLE_COPY
-mode_copy_section = #define USE_COPY_SECTION
+mode_copy_section = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY
mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
mode_mipmap = #define MODE_MIPMAP
mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
@@ -25,8 +25,7 @@ void main() {
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 + uv_interp.xy * copy_section.zw) * 2.0 - 1.0;
#endif
}