summaryrefslogtreecommitdiff
path: root/servers/rendering/rasterizer_rd
diff options
context:
space:
mode:
authorreduz <reduzio@gmail.com>2020-11-03 16:51:53 -0300
committerreduz <reduzio@gmail.com>2020-11-04 10:03:01 -0300
commitf123981a96c8ab7d7cb3e77ecbcf0048cb3b79e6 (patch)
tree9759e240a4043c1e5878a0a431ab6ae366792340 /servers/rendering/rasterizer_rd
parent3ec10bb07cb4a1ce1170c1d189475c8147576b7e (diff)
Implement DirectionalLight2D
Also separated Light2D in PointLight2D and DirectionalLight2D. Used PointLight2D because its more of a point, and it does not work the same as OmniLight (as shape depends on texture). Added a few utility methods to Rect2D I needed.
Diffstat (limited to 'servers/rendering/rasterizer_rd')
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp224
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h14
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas.glsl224
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl5
4 files changed, 344 insertions, 123 deletions
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
index da30291353..b33940b22c 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
@@ -416,10 +416,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
light_count++;
- if (light->mode == RS::CANVAS_LIGHT_MODE_MASK) {
- base_flags |= FLAGS_USING_LIGHT_MASK;
- }
-
if (light_count == MAX_LIGHTS_PER_ITEM) {
break;
}
@@ -430,7 +426,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
}
- light_mode = light_count > 0 ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED;
+ light_mode = (light_count > 0 || using_directional_lights) ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED;
PipelineVariants *pipeline_variants = p_pipeline_variants;
@@ -1194,51 +1190,83 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,
RD::get_singleton()->draw_list_end();
}
-void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) {
+void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) {
int item_count = 0;
//setup canvas state uniforms if needed
Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse();
+ //setup directional lights if exist
+
+ uint32_t light_count = 0;
+ uint32_t directional_light_count = 0;
{
- //update canvas state uniform buffer
- State::Buffer state_buffer;
+ Light *l = p_directional_light_list;
+ uint32_t index = 0;
- Size2i ssize = storage->render_target_get_size(p_to_render_target);
+ while (l) {
+ if (index == state.max_lights_per_render) {
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ continue;
+ }
- Transform screen_transform;
- screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f);
- screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f));
- _update_transform_to_mat4(screen_transform, state_buffer.screen_transform);
- _update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform);
+ CanvasLight *clight = canvas_light_owner.getornull(l->light_internal);
+ if (!clight) { //unused or invalid texture
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ ERR_CONTINUE(!clight);
+ }
- Transform2D normal_transform = p_canvas_transform;
- normal_transform.elements[0].normalize();
- normal_transform.elements[1].normalize();
- normal_transform.elements[2] = Vector2();
- _update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform);
+ Vector2 canvas_light_dir = l->xform_cache.elements[1].normalized();
- state_buffer.canvas_modulate[0] = p_modulate.r;
- state_buffer.canvas_modulate[1] = p_modulate.g;
- state_buffer.canvas_modulate[2] = p_modulate.b;
- state_buffer.canvas_modulate[3] = p_modulate.a;
+ state.light_uniforms[index].position[0] = -canvas_light_dir.x;
+ state.light_uniforms[index].position[1] = -canvas_light_dir.y;
- Size2 render_target_size = storage->render_target_get_size(p_to_render_target);
- state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
- state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y;
+ _update_transform_2d_to_mat2x4(clight->shadow.directional_xform, state.light_uniforms[index].shadow_matrix);
- state_buffer.time = state.time;
- state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel;
+ state.light_uniforms[index].height = l->height; //0..1 here
- RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true);
+ for (int i = 0; i < 4; i++) {
+ state.light_uniforms[index].shadow_color[i] = uint8_t(CLAMP(int32_t(l->shadow_color[i] * 255.0), 0, 255));
+ state.light_uniforms[index].color[i] = l->color[i];
+ }
+
+ state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate
+
+ if (state.shadow_fb.is_valid()) {
+ state.light_uniforms[index].shadow_pixel_size = (1.0 / state.shadow_texture_size) * (1.0 + l->shadow_smooth);
+ state.light_uniforms[index].shadow_z_far_inv = 1.0 / clight->shadow.z_far;
+ state.light_uniforms[index].shadow_y_ofs = clight->shadow.y_offset;
+ } else {
+ state.light_uniforms[index].shadow_pixel_size = 1.0;
+ state.light_uniforms[index].shadow_z_far_inv = 1.0;
+ state.light_uniforms[index].shadow_y_ofs = 0;
+ }
+
+ state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT;
+ state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT;
+ if (clight->shadow.enabled) {
+ state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW;
+ }
+
+ l->render_index_cache = index;
+
+ index++;
+ l = l->next_ptr;
+ }
+
+ light_count = index;
+ directional_light_count = light_count;
+ using_directional_lights = directional_light_count > 0;
}
//setup lights if exist
{
Light *l = p_light_list;
- uint32_t index = 0;
+ uint32_t index = light_count;
while (l) {
if (index == state.max_lights_per_render) {
@@ -1280,7 +1308,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
state.light_uniforms[index].shadow_y_ofs = 0;
}
- state.light_uniforms[index].flags |= l->mode << LIGHT_FLAGS_BLEND_SHIFT;
+ state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT;
state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT;
if (clight->shadow.enabled) {
state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW;
@@ -1306,9 +1334,46 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
l = l->next_ptr;
}
- if (index > 0) {
- RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * index, &state.light_uniforms[0], true);
- }
+ light_count = index;
+ }
+
+ if (light_count > 0) {
+ RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * light_count, &state.light_uniforms[0], true);
+ }
+
+ {
+ //update canvas state uniform buffer
+ State::Buffer state_buffer;
+
+ Size2i ssize = storage->render_target_get_size(p_to_render_target);
+
+ Transform screen_transform;
+ screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f);
+ screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f));
+ _update_transform_to_mat4(screen_transform, state_buffer.screen_transform);
+ _update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform);
+
+ Transform2D normal_transform = p_canvas_transform;
+ normal_transform.elements[0].normalize();
+ normal_transform.elements[1].normalize();
+ normal_transform.elements[2] = Vector2();
+ _update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform);
+
+ state_buffer.canvas_modulate[0] = p_modulate.r;
+ state_buffer.canvas_modulate[1] = p_modulate.g;
+ state_buffer.canvas_modulate[2] = p_modulate.b;
+ state_buffer.canvas_modulate[3] = p_modulate.a;
+
+ Size2 render_target_size = storage->render_target_get_size(p_to_render_target);
+ state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
+ state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y;
+
+ state_buffer.time = state.time;
+ state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel;
+
+ state_buffer.directional_light_count = directional_light_count;
+
+ RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true);
}
{ //default filter/repeat
@@ -1439,10 +1504,7 @@ void RasterizerCanvasRD::light_set_use_shadow(RID p_rid, bool p_enable) {
cl->shadow.enabled = p_enable;
}
-void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) {
- CanvasLight *cl = canvas_light_owner.getornull(p_rid);
- ERR_FAIL_COND(!cl->shadow.enabled);
-
+void RasterizerCanvasRD::_update_shadow_atlas() {
if (state.shadow_fb == RID()) {
//ah, we lack the shadow texture..
RD::get_singleton()->free(state.shadow_texture); //erase placeholder
@@ -1474,6 +1536,12 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, cons
state.shadow_fb = RD::get_singleton()->framebuffer_create(fb_textures);
}
+}
+void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) {
+ CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ ERR_FAIL_COND(!cl->shadow.enabled);
+
+ _update_shadow_atlas();
cl->shadow.z_far = p_far;
cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(state.max_lights_per_render * 2);
@@ -1547,6 +1615,86 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, cons
}
}
+void RasterizerCanvasRD::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) {
+ CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ ERR_FAIL_COND(!cl->shadow.enabled);
+
+ _update_shadow_atlas();
+
+ Vector2 light_dir = p_light_xform.elements[1].normalized();
+
+ Vector2 center = p_clip_rect.position + p_clip_rect.size * 0.5;
+
+ float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center));
+
+ Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance);
+ float distance = to_edge_distance * 2.0 + p_cull_distance;
+ float half_size = p_clip_rect.size.length() * 0.5; //shadow length, must keep this no matter the angle
+
+ cl->shadow.z_far = distance;
+ cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(state.max_lights_per_render * 2);
+
+ Transform2D to_light_xform;
+
+ to_light_xform[2] = from_pos;
+ to_light_xform[1] = light_dir;
+ to_light_xform[0] = -light_dir.tangent();
+
+ to_light_xform.invert();
+
+ Vector<Color> cc;
+ cc.push_back(Color(1, 1, 1, 1));
+
+ Rect2i rect(0, p_shadow_index * 2, state.shadow_texture_size, 2);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect);
+
+ CameraMatrix projection;
+ projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance);
+ projection = projection * CameraMatrix(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse());
+
+ ShadowRenderPushConstant push_constant;
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 4; x++) {
+ push_constant.projection[y * 4 + x] = projection.matrix[y][x];
+ }
+ }
+
+ push_constant.direction[0] = 0.0;
+ push_constant.direction[1] = 1.0;
+ push_constant.z_far = distance;
+ push_constant.pad = 0;
+
+ LightOccluderInstance *instance = p_occluders;
+
+ while (instance) {
+ OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder);
+
+ if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) {
+ instance = instance->next;
+ continue;
+ }
+
+ _update_transform_2d_to_mat2x4(to_light_xform * instance->xform_cache, push_constant.modelview);
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.render_pipelines[co->cull_mode]);
+ RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->vertex_array);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, co->index_array);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+
+ instance = instance->next;
+ }
+
+ RD::get_singleton()->draw_list_end();
+
+ Transform2D to_shadow;
+ to_shadow.elements[0].x = 1.0 / -(half_size * 2.0);
+ to_shadow.elements[2].x = 0.5;
+
+ cl->shadow.directional_xform = to_shadow * to_light_xform;
+}
+
RID RasterizerCanvasRD::occluder_polygon_create() {
OccluderPolygon occluder;
occluder.point_count = 0;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
index 3412435367..b516f63cbf 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
@@ -75,7 +75,6 @@ class RasterizerCanvasRD : public RasterizerCanvas {
FLAGS_CLIP_RECT_UV = (1 << 9),
FLAGS_TRANSPOSE_RECT = (1 << 10),
- FLAGS_USING_LIGHT_MASK = (1 << 11),
FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),
FLAGS_USING_PARTICLES = (1 << 13),
@@ -269,6 +268,7 @@ class RasterizerCanvasRD : public RasterizerCanvas {
bool enabled = false;
float z_far;
float y_offset;
+ Transform2D directional_xform;
} shadow;
};
@@ -331,12 +331,13 @@ class RasterizerCanvasRD : public RasterizerCanvas {
float screen_transform[16];
float canvas_normal_transform[16];
float canvas_modulate[4];
+
float screen_pixel_size[2];
float time;
uint32_t use_pixel_snap;
- //uint32_t light_count;
- //uint32_t pad[3];
+ uint32_t directional_light_count;
+ uint32_t pad[3];
};
LightUniform *light_uniforms;
@@ -355,6 +356,7 @@ class RasterizerCanvasRD : public RasterizerCanvas {
uint32_t max_lights_per_item;
double time;
+
} state;
struct PushConstant {
@@ -388,6 +390,7 @@ class RasterizerCanvasRD : public RasterizerCanvas {
Item *items[MAX_RENDER_ITEMS];
+ bool using_directional_lights = false;
RID default_canvas_texture;
RID default_canvas_group_shader;
@@ -408,6 +411,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
_FORCE_INLINE_ void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4);
_FORCE_INLINE_ void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4);
+ void _update_shadow_atlas();
+
public:
PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>());
void free_polygon(PolygonID p_polygon);
@@ -416,12 +421,13 @@ public:
void light_set_texture(RID p_rid, RID p_texture);
void light_set_use_shadow(RID p_rid, bool p_enable);
void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders);
+ void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders);
RID occluder_polygon_create();
void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines);
void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode);
- void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
+ void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {}
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/rasterizer_rd/shaders/canvas.glsl
index b382c0d85f..2a0f94e733 100644
--- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas.glsl
@@ -249,7 +249,7 @@ vec4 light_compute(
inout vec4 shadow_modulate,
vec2 screen_uv,
vec2 uv,
- vec4 color) {
+ vec4 color, bool is_directional) {
vec4 light = vec4(0.0);
/* clang-format off */
LIGHT_SHADER_CODE
@@ -302,6 +302,99 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
#endif
+#ifdef USE_LIGHTING
+
+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;
+ }
+}
+
+//float distance = length(shadow_pos);
+vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
+#ifdef LIGHT_SHADER_CODE_USED
+ ,
+ vec3 shadow_modulate
+#endif
+) {
+ float shadow;
+ uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
+
+ if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
+ shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
+ } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
+ vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
+ shadow = 0.0;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
+ shadow /= 5.0;
+ } else { //PCF13
+ vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
+ shadow = 0.0;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x;
+ shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x;
+ shadow /= 13.0;
+ }
+
+ vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color);
+#ifdef LIGHT_SHADER_CODE_USED
+ shadow_color *= shadow_modulate;
+#endif
+
+ shadow_color.a *= light_color.a; //respect light alpha
+
+ return mix(light_color, shadow_color, shadow);
+}
+
+void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
+ uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
+
+ switch (blend_mode) {
+ case LIGHT_FLAGS_BLEND_MODE_ADD: {
+ color.rgb += light_color.rgb * light_color.a;
+ } break;
+ case LIGHT_FLAGS_BLEND_MODE_SUB: {
+ color.rgb -= light_color.rgb * light_color.a;
+ } break;
+ case LIGHT_FLAGS_BLEND_MODE_MIX: {
+ color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
+ } break;
+ }
+}
+
+#endif
+
void main() {
vec4 color = color_interp;
vec2 uv = uv_interp;
@@ -332,6 +425,7 @@ void main() {
color *= texture(sampler2D(color_texture, texture_sampler), uv);
uint light_count = (draw_data.flags >> FLAGS_LIGHT_COUNT_SHIFT) & 0xF; //max 16 lights
+ bool using_light = light_count > 0 || canvas_data.directional_light_count > 0;
vec3 normal;
@@ -341,7 +435,7 @@ void main() {
bool normal_used = false;
#endif
- if (normal_used || (light_count > 0 && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
+ if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
normal_used = true;
@@ -358,7 +452,7 @@ void main() {
bool specular_shininess_used = false;
#endif
- if (specular_shininess_used || (light_count > 0 && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
+ if (specular_shininess_used || (using_light && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(sampler2D(specular_texture, texture_sampler), uv);
specular_shininess *= unpackUnorm4x8(draw_data.specular_shininess);
specular_shininess_used = true;
@@ -401,13 +495,52 @@ FRAGMENT_SHADER_CODE
normal = normalize((canvas_data.canvas_normal_transform * vec4(normal, 0.0)).xyz);
}
- vec4 base_color = color;
+ vec3 base_color = color.rgb;
if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) {
color = vec4(0.0); //invisible by default due to using light mask
}
color *= canvas_data.canvas_modulation;
#ifdef USE_LIGHTING
+
+ // Directional Lights
+
+ for (uint i = 0; i < canvas_data.directional_light_count; i++) {
+ uint light_base = i;
+
+ vec2 direction = light_array.data[light_base].position;
+ vec4 light_color = light_array.data[light_base].color;
+
+#ifdef LIGHT_SHADER_CODE_USED
+
+ vec4 shadow_modulate = vec4(1.0);
+ light_color = light_compute(light_vertex, direction, normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, true);
+#else
+
+ if (normal_used) {
+ vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array.data[light_base].height));
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
+ }
+#endif
+
+ if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+
+ vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0);
+
+ light_color = light_shadow_compute(light_base, light_color, shadow_uv
+#ifdef LIGHT_SHADER_CODE_USED
+ ,
+ shadow_modulate
+#endif
+ );
+ }
+
+ light_blend_compute(light_base, light_color, color.rgb);
+ }
+
+ // Positional Lights
+
for (uint i = 0; i < MAX_LIGHTS_PER_ITEM; i++) {
if (i >= light_count) {
break;
@@ -440,7 +573,7 @@ FRAGMENT_SHADER_CODE
vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
light_color.rgb *= light_base_color.rgb;
- light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv);
+ light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv, false);
#else
light_color.rgb *= light_base_color.rgb * light_base_color.a;
@@ -451,24 +584,7 @@ FRAGMENT_SHADER_CODE
vec3 light_vec = normalize(light_pos - pos);
float cNdotL = max(0.0, dot(normal, light_vec));
- if (specular_shininess_used) {
- //blinn
- vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough
- vec3 half_vec = normalize(view + light_vec);
-
- float cNdotV = max(dot(normal, view), 0.0);
- float cNdotH = max(dot(normal, half_vec), 0.0);
- float cVdotH = max(dot(view, half_vec), 0.0);
- float cLdotH = max(dot(light_vec, half_vec), 0.0);
- float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25;
- float blinn = pow(cNdotH, shininess);
- blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
-
- light_color.rgb = specular_shininess.rgb * light_base_color.rgb * s + light_color.rgb * cNdotL;
- } else {
- light_color.rgb *= cNdotL;
- }
+ 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)))) {
@@ -506,69 +622,17 @@ FRAGMENT_SHADER_CODE
distance *= light_array.data[light_base].shadow_zfar_inv;
//float distance = length(shadow_pos);
- float shadow;
- uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
-
vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0);
- if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
- shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
- } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
- vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
- shadow = 0.0;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
- shadow /= 5.0;
- } else { //PCF13
- vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
- shadow = 0.0;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x;
- shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x;
- shadow /= 13.0;
- }
-
- vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color);
+ light_color = light_shadow_compute(light_base, light_color, shadow_uv
#ifdef LIGHT_SHADER_CODE_USED
- shadow_color *= shadow_modulate;
+ ,
+ shadow_modulate
#endif
-
- shadow_color.a *= light_color.a; //respect light alpha
-
- light_color = mix(light_color, shadow_color, shadow);
- //light_color = mix(light_color, shadow_color, shadow);
+ );
}
- uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
-
- switch (blend_mode) {
- case LIGHT_FLAGS_BLEND_MODE_ADD: {
- color.rgb += light_color.rgb * light_color.a;
- } break;
- case LIGHT_FLAGS_BLEND_MODE_SUB: {
- color.rgb -= light_color.rgb * light_color.a;
- } break;
- case LIGHT_FLAGS_BLEND_MODE_MIX: {
- color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
- } break;
- case LIGHT_FLAGS_BLEND_MODE_MASK: {
- light_color.a *= base_color.a;
- color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
- } break;
- }
+ light_blend_compute(light_base, light_color, color.rgb);
}
#endif
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
index 1a226a87d3..bb39584cbb 100644
--- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
@@ -68,7 +68,10 @@ layout(set = 0, binding = 1, std140) uniform CanvasData {
float time;
bool use_pixel_snap;
- //uint light_count;
+ uint directional_light_count;
+ uint pad0;
+ uint pad1;
+ uint pad2;
}
canvas_data;