You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-09 12:50:35 +00:00
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.
This commit is contained in:
@@ -142,11 +142,15 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
|
||||
Rect2 clip_rect(0, 0, p_viewport->size.x, p_viewport->size.y);
|
||||
RasterizerCanvas::Light *lights = nullptr;
|
||||
RasterizerCanvas::Light *lights_with_shadow = nullptr;
|
||||
RasterizerCanvas::Light *lights_with_mask = nullptr;
|
||||
|
||||
RasterizerCanvas::Light *directional_lights = nullptr;
|
||||
RasterizerCanvas::Light *directional_lights_with_shadow = nullptr;
|
||||
|
||||
Rect2 shadow_rect;
|
||||
|
||||
int light_count = 0;
|
||||
int shadow_count = 0;
|
||||
int directional_light_count = 0;
|
||||
|
||||
RENDER_TIMESTAMP("Cull Canvas Lights");
|
||||
for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
|
||||
@@ -186,10 +190,6 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
|
||||
lights_with_shadow = cl;
|
||||
cl->radius_cache = cl->rect_cache.size.length();
|
||||
}
|
||||
if (cl->mode == RS::CANVAS_LIGHT_MODE_MASK) {
|
||||
cl->mask_next_ptr = lights_with_mask;
|
||||
lights_with_mask = cl;
|
||||
}
|
||||
|
||||
light_count++;
|
||||
}
|
||||
@@ -199,6 +199,26 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
|
||||
}
|
||||
}
|
||||
|
||||
for (Set<RasterizerCanvas::Light *>::Element *F = canvas->directional_lights.front(); F; F = F->next()) {
|
||||
RasterizerCanvas::Light *cl = F->get();
|
||||
if (cl->enabled) {
|
||||
cl->filter_next_ptr = directional_lights;
|
||||
directional_lights = cl;
|
||||
cl->xform_cache = xf * cl->xform;
|
||||
cl->xform_cache.elements[2] = Vector2(); //translation is pointless
|
||||
if (cl->use_shadow) {
|
||||
cl->shadows_next_ptr = directional_lights_with_shadow;
|
||||
directional_lights_with_shadow = cl;
|
||||
}
|
||||
|
||||
directional_light_count++;
|
||||
|
||||
if (directional_light_count == RS::MAX_2D_DIRECTIONAL_LIGHTS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canvas_map[Viewport::CanvasKey(E->key(), E->get().layer, E->get().sublayer)] = &E->get();
|
||||
}
|
||||
|
||||
@@ -240,6 +260,90 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
|
||||
RENDER_TIMESTAMP("<End rendering 2D Shadows");
|
||||
}
|
||||
|
||||
if (directional_lights_with_shadow) {
|
||||
//update shadows if any
|
||||
RasterizerCanvas::Light *light = directional_lights_with_shadow;
|
||||
while (light) {
|
||||
Vector2 light_dir = -light->xform_cache.elements[1].normalized(); // Y is light direction
|
||||
float cull_distance = light->directional_distance;
|
||||
|
||||
Vector2 light_dir_sign;
|
||||
light_dir_sign.x = (ABS(light_dir.x) < CMP_EPSILON) ? 0.0 : ((light_dir.x > 0.0) ? 1.0 : -1.0);
|
||||
light_dir_sign.y = (ABS(light_dir.y) < CMP_EPSILON) ? 0.0 : ((light_dir.y > 0.0) ? 1.0 : -1.0);
|
||||
|
||||
Vector2 points[6];
|
||||
int point_count = 0;
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
static const Vector2 signs[4] = { Vector2(1, 1), Vector2(1, 0), Vector2(0, 0), Vector2(0, 1) };
|
||||
Vector2 sign_cmp = signs[j] * 2.0 - Vector2(1.0, 1.0);
|
||||
Vector2 point = clip_rect.position + clip_rect.size * signs[j];
|
||||
|
||||
if (sign_cmp == light_dir_sign) {
|
||||
//both point in same direction, plot offseted
|
||||
points[point_count++] = point + light_dir * cull_distance;
|
||||
} else if (sign_cmp.x == light_dir_sign.x || sign_cmp.y == light_dir_sign.y) {
|
||||
int next_j = (j + 1) % 4;
|
||||
Vector2 next_sign_cmp = signs[next_j] * 2.0 - Vector2(1.0, 1.0);
|
||||
|
||||
//one point in the same direction, plot segment
|
||||
|
||||
if (next_sign_cmp.x == light_dir_sign.x || next_sign_cmp.y == light_dir_sign.y) {
|
||||
if (light_dir_sign.x != 0.0 || light_dir_sign.y != 0.0) {
|
||||
points[point_count++] = point;
|
||||
}
|
||||
points[point_count++] = point + light_dir * cull_distance;
|
||||
} else {
|
||||
points[point_count++] = point + light_dir * cull_distance;
|
||||
if (light_dir_sign.x != 0.0 || light_dir_sign.y != 0.0) {
|
||||
points[point_count++] = point;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//plot normally
|
||||
points[point_count++] = point;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 xf_points[6];
|
||||
|
||||
RasterizerCanvas::LightOccluderInstance *occluders = nullptr;
|
||||
|
||||
RENDER_TIMESTAMP(">Render Directional 2D Shadows");
|
||||
|
||||
//make list of occluders
|
||||
int occ_cullded = 0;
|
||||
for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
|
||||
RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get().canvas);
|
||||
Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
|
||||
|
||||
for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) {
|
||||
if (!F->get()->enabled) {
|
||||
continue;
|
||||
}
|
||||
F->get()->xform_cache = xf * F->get()->xform;
|
||||
Transform2D localizer = F->get()->xform_cache.affine_inverse();
|
||||
|
||||
for (int j = 0; j < point_count; j++) {
|
||||
xf_points[j] = localizer.xform(points[j]);
|
||||
}
|
||||
if (F->get()->aabb_cache.intersects_filled_polygon(xf_points, point_count)) {
|
||||
F->get()->next = occluders;
|
||||
occluders = F->get();
|
||||
occ_cullded++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RSG::canvas_render->light_update_directional_shadow(light->light_internal, shadow_count++, light->xform_cache, light->item_shadow_mask, cull_distance, clip_rect, occluders);
|
||||
|
||||
light = light->shadows_next_ptr;
|
||||
}
|
||||
|
||||
//RSG::canvas_render->reset_canvas();
|
||||
RENDER_TIMESTAMP("<Render Directional 2D Shadows");
|
||||
}
|
||||
|
||||
if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().get_layer() > scenario_canvas_max_layer) {
|
||||
if (!can_draw_3d) {
|
||||
RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
|
||||
@@ -255,6 +359,7 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
|
||||
Transform2D xform = _canvas_get_transform(p_viewport, canvas, E->get(), clip_rect.size);
|
||||
|
||||
RasterizerCanvas::Light *canvas_lights = nullptr;
|
||||
RasterizerCanvas::Light *canvas_directional_lights = nullptr;
|
||||
|
||||
RasterizerCanvas::Light *ptr = lights;
|
||||
while (ptr) {
|
||||
@@ -265,7 +370,16 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::
|
||||
ptr = ptr->filter_next_ptr;
|
||||
}
|
||||
|
||||
RSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, lights_with_mask, clip_rect, p_viewport->texture_filter, p_viewport->texture_repeat, p_viewport->snap_2d_transforms_to_pixel, p_viewport->snap_2d_vertices_to_pixel);
|
||||
ptr = directional_lights;
|
||||
while (ptr) {
|
||||
if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) {
|
||||
ptr->next_ptr = canvas_directional_lights;
|
||||
canvas_directional_lights = ptr;
|
||||
}
|
||||
ptr = ptr->filter_next_ptr;
|
||||
}
|
||||
|
||||
RSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, canvas_directional_lights, clip_rect, p_viewport->texture_filter, p_viewport->texture_repeat, p_viewport->snap_2d_transforms_to_pixel, p_viewport->snap_2d_vertices_to_pixel);
|
||||
i++;
|
||||
|
||||
if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) {
|
||||
|
||||
Reference in New Issue
Block a user