mirror of
https://github.com/godotengine/godot.git
synced 2024-11-25 05:33:11 +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:
parent
3ec10bb07c
commit
f123981a96
@ -244,6 +244,68 @@ struct Rect2 {
|
||||
return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs());
|
||||
}
|
||||
|
||||
Vector2 get_support(const Vector2 &p_normal) const {
|
||||
Vector2 half_extents = size * 0.5;
|
||||
Vector2 ofs = position + half_extents;
|
||||
return Vector2(
|
||||
(p_normal.x > 0) ? -half_extents.x : half_extents.x,
|
||||
(p_normal.y > 0) ? -half_extents.y : half_extents.y) +
|
||||
ofs;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const {
|
||||
Vector2 center = position + size * 0.5;
|
||||
int side_plus = 0;
|
||||
int side_minus = 0;
|
||||
Vector2 end = position + size;
|
||||
|
||||
int i_f = p_point_count - 1;
|
||||
for (int i = 0; i < p_point_count; i++) {
|
||||
const Vector2 &a = p_points[i_f];
|
||||
const Vector2 &b = p_points[i];
|
||||
i_f = i;
|
||||
|
||||
Vector2 r = (b - a);
|
||||
float l = r.length();
|
||||
if (l == 0.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//check inside
|
||||
Vector2 tg = r.tangent();
|
||||
float s = tg.dot(center) - tg.dot(a);
|
||||
if (s < 0.0) {
|
||||
side_plus++;
|
||||
} else {
|
||||
side_minus++;
|
||||
}
|
||||
|
||||
//check ray box
|
||||
r /= l;
|
||||
Vector2 ir(1.0 / r.x, 1.0 / r.y);
|
||||
|
||||
// lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
|
||||
// r.org is origin of ray
|
||||
Vector2 t13 = (position - a) * ir;
|
||||
Vector2 t24 = (end - a) * ir;
|
||||
|
||||
float tmin = MAX(MIN(t13.x, t24.x), MIN(t13.y, t24.y));
|
||||
float tmax = MIN(MAX(t13.x, t24.x), MAX(t13.y, t24.y));
|
||||
|
||||
// if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
|
||||
if (tmax < 0 || tmin > tmax || tmin >= l) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (side_plus * side_minus == 0) {
|
||||
return true; //all inside
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
operator String() const { return String(position) + ", " + String(size); }
|
||||
|
||||
Rect2() {}
|
||||
|
@ -33,54 +33,6 @@
|
||||
#include "core/engine.h"
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
Dictionary Light2D::_edit_get_state() const {
|
||||
Dictionary state = Node2D::_edit_get_state();
|
||||
state["offset"] = get_texture_offset();
|
||||
return state;
|
||||
}
|
||||
|
||||
void Light2D::_edit_set_state(const Dictionary &p_state) {
|
||||
Node2D::_edit_set_state(p_state);
|
||||
set_texture_offset(p_state["offset"]);
|
||||
}
|
||||
|
||||
void Light2D::_edit_set_pivot(const Point2 &p_pivot) {
|
||||
set_position(get_transform().xform(p_pivot));
|
||||
set_texture_offset(get_texture_offset() - p_pivot);
|
||||
}
|
||||
|
||||
Point2 Light2D::_edit_get_pivot() const {
|
||||
return Vector2();
|
||||
}
|
||||
|
||||
bool Light2D::_edit_use_pivot() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
Rect2 Light2D::_edit_get_rect() const {
|
||||
if (texture.is_null()) {
|
||||
return Rect2();
|
||||
}
|
||||
|
||||
Size2 s = texture->get_size() * _scale;
|
||||
return Rect2(texture_offset - s / 2.0, s);
|
||||
}
|
||||
|
||||
bool Light2D::_edit_use_rect() const {
|
||||
return !texture.is_null();
|
||||
}
|
||||
#endif
|
||||
|
||||
Rect2 Light2D::get_anchorable_rect() const {
|
||||
if (texture.is_null()) {
|
||||
return Rect2();
|
||||
}
|
||||
|
||||
Size2 s = texture->get_size() * _scale;
|
||||
return Rect2(texture_offset - s / 2.0, s);
|
||||
}
|
||||
|
||||
void Light2D::_update_light_visibility() {
|
||||
if (!is_inside_tree()) {
|
||||
return;
|
||||
@ -123,32 +75,6 @@ bool Light2D::is_editor_only() const {
|
||||
return editor_only;
|
||||
}
|
||||
|
||||
void Light2D::set_texture(const Ref<Texture2D> &p_texture) {
|
||||
texture = p_texture;
|
||||
if (texture.is_valid()) {
|
||||
RS::get_singleton()->canvas_light_set_texture(canvas_light, texture->get_rid());
|
||||
} else {
|
||||
RS::get_singleton()->canvas_light_set_texture(canvas_light, RID());
|
||||
}
|
||||
|
||||
update_configuration_warning();
|
||||
}
|
||||
|
||||
Ref<Texture2D> Light2D::get_texture() const {
|
||||
return texture;
|
||||
}
|
||||
|
||||
void Light2D::set_texture_offset(const Vector2 &p_offset) {
|
||||
texture_offset = p_offset;
|
||||
RS::get_singleton()->canvas_light_set_texture_offset(canvas_light, texture_offset);
|
||||
item_rect_changed();
|
||||
_change_notify("offset");
|
||||
}
|
||||
|
||||
Vector2 Light2D::get_texture_offset() const {
|
||||
return texture_offset;
|
||||
}
|
||||
|
||||
void Light2D::set_color(const Color &p_color) {
|
||||
color = p_color;
|
||||
RS::get_singleton()->canvas_light_set_color(canvas_light, color);
|
||||
@ -176,20 +102,6 @@ float Light2D::get_energy() const {
|
||||
return energy;
|
||||
}
|
||||
|
||||
void Light2D::set_texture_scale(float p_scale) {
|
||||
_scale = p_scale;
|
||||
// Avoid having 0 scale values, can lead to errors in physics and rendering.
|
||||
if (_scale == 0) {
|
||||
_scale = CMP_EPSILON;
|
||||
}
|
||||
RS::get_singleton()->canvas_light_set_scale(canvas_light, _scale);
|
||||
item_rect_changed();
|
||||
}
|
||||
|
||||
float Light2D::get_texture_scale() const {
|
||||
return _scale;
|
||||
}
|
||||
|
||||
void Light2D::set_z_range_min(int p_min_z) {
|
||||
z_min = p_min_z;
|
||||
RS::get_singleton()->canvas_light_set_z_range(canvas_light, z_min, z_max);
|
||||
@ -244,15 +156,6 @@ int Light2D::get_item_shadow_cull_mask() const {
|
||||
return item_shadow_mask;
|
||||
}
|
||||
|
||||
void Light2D::set_mode(Mode p_mode) {
|
||||
mode = p_mode;
|
||||
RS::get_singleton()->canvas_light_set_mode(canvas_light, RS::CanvasLightMode(p_mode));
|
||||
}
|
||||
|
||||
Light2D::Mode Light2D::get_mode() const {
|
||||
return mode;
|
||||
}
|
||||
|
||||
void Light2D::set_shadow_enabled(bool p_enabled) {
|
||||
shadow = p_enabled;
|
||||
RS::get_singleton()->canvas_light_set_shadow_enabled(canvas_light, shadow);
|
||||
@ -281,6 +184,15 @@ Color Light2D::get_shadow_color() const {
|
||||
return shadow_color;
|
||||
}
|
||||
|
||||
void Light2D::set_blend_mode(BlendMode p_mode) {
|
||||
blend_mode = p_mode;
|
||||
RS::get_singleton()->canvas_light_set_blend_mode(_get_light(), RS::CanvasLightBlendMode(p_mode));
|
||||
}
|
||||
|
||||
Light2D::BlendMode Light2D::get_blend_mode() const {
|
||||
return blend_mode;
|
||||
}
|
||||
|
||||
void Light2D::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_ENTER_TREE) {
|
||||
RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, get_canvas());
|
||||
@ -300,19 +212,6 @@ void Light2D::_notification(int p_what) {
|
||||
}
|
||||
}
|
||||
|
||||
String Light2D::get_configuration_warning() const {
|
||||
String warning = Node2D::get_configuration_warning();
|
||||
|
||||
if (!texture.is_valid()) {
|
||||
if (!warning.empty()) {
|
||||
warning += "\n\n";
|
||||
}
|
||||
warning += TTR("A texture with the shape of the light must be supplied to the \"Texture\" property.");
|
||||
}
|
||||
|
||||
return warning;
|
||||
}
|
||||
|
||||
void Light2D::set_shadow_smooth(float p_amount) {
|
||||
shadow_smooth = p_amount;
|
||||
RS::get_singleton()->canvas_light_set_shadow_smooth(canvas_light, shadow_smooth);
|
||||
@ -329,24 +228,12 @@ void Light2D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_editor_only", "editor_only"), &Light2D::set_editor_only);
|
||||
ClassDB::bind_method(D_METHOD("is_editor_only"), &Light2D::is_editor_only);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Light2D::set_texture);
|
||||
ClassDB::bind_method(D_METHOD("get_texture"), &Light2D::get_texture);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_texture_offset", "texture_offset"), &Light2D::set_texture_offset);
|
||||
ClassDB::bind_method(D_METHOD("get_texture_offset"), &Light2D::get_texture_offset);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_color", "color"), &Light2D::set_color);
|
||||
ClassDB::bind_method(D_METHOD("get_color"), &Light2D::get_color);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_height", "height"), &Light2D::set_height);
|
||||
ClassDB::bind_method(D_METHOD("get_height"), &Light2D::get_height);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_energy", "energy"), &Light2D::set_energy);
|
||||
ClassDB::bind_method(D_METHOD("get_energy"), &Light2D::get_energy);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_texture_scale", "texture_scale"), &Light2D::set_texture_scale);
|
||||
ClassDB::bind_method(D_METHOD("get_texture_scale"), &Light2D::get_texture_scale);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_z_range_min", "z"), &Light2D::set_z_range_min);
|
||||
ClassDB::bind_method(D_METHOD("get_z_range_min"), &Light2D::get_z_range_min);
|
||||
|
||||
@ -365,9 +252,6 @@ void Light2D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_item_shadow_cull_mask", "item_shadow_cull_mask"), &Light2D::set_item_shadow_cull_mask);
|
||||
ClassDB::bind_method(D_METHOD("get_item_shadow_cull_mask"), &Light2D::get_item_shadow_cull_mask);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_mode", "mode"), &Light2D::set_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_mode"), &Light2D::get_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_shadow_enabled", "enabled"), &Light2D::set_shadow_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_shadow_enabled"), &Light2D::is_shadow_enabled);
|
||||
|
||||
@ -380,16 +264,18 @@ void Light2D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_shadow_color", "shadow_color"), &Light2D::set_shadow_color);
|
||||
ClassDB::bind_method(D_METHOD("get_shadow_color"), &Light2D::get_shadow_color);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &Light2D::set_blend_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_mode"), &Light2D::get_blend_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_height", "height"), &Light2D::set_height);
|
||||
ClassDB::bind_method(D_METHOD("get_height"), &Light2D::get_height);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_texture_offset", "get_texture_offset");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_scale", PROPERTY_HINT_RANGE, "0.01,50,0.01"), "set_texture_scale", "get_texture_scale");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Add,Sub,Mix,Mask"), "set_mode", "get_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Add,Sub,Mix"), "set_blend_mode", "get_blend_mode");
|
||||
ADD_GROUP("Range", "range_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "range_height", PROPERTY_HINT_RANGE, "-2048,2048,0.1,or_lesser,or_greater"), "set_height", "get_height");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_min", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_min", "get_z_range_min");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_max", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_max", "get_z_range_max");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_layer_min", PROPERTY_HINT_RANGE, "-512,512,1"), "set_layer_range_min", "get_layer_range_min");
|
||||
@ -403,14 +289,13 @@ void Light2D::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shadow_filter_smooth", PROPERTY_HINT_RANGE, "0,64,0.1"), "set_shadow_smooth", "get_shadow_smooth");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_item_cull_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_item_shadow_cull_mask", "get_item_shadow_cull_mask");
|
||||
|
||||
BIND_ENUM_CONSTANT(MODE_ADD);
|
||||
BIND_ENUM_CONSTANT(MODE_SUB);
|
||||
BIND_ENUM_CONSTANT(MODE_MIX);
|
||||
BIND_ENUM_CONSTANT(MODE_MASK);
|
||||
|
||||
BIND_ENUM_CONSTANT(SHADOW_FILTER_NONE);
|
||||
BIND_ENUM_CONSTANT(SHADOW_FILTER_PCF5);
|
||||
BIND_ENUM_CONSTANT(SHADOW_FILTER_PCF13);
|
||||
|
||||
BIND_ENUM_CONSTANT(BLEND_MODE_ADD);
|
||||
BIND_ENUM_CONSTANT(BLEND_MODE_SUB);
|
||||
BIND_ENUM_CONSTANT(BLEND_MODE_MIX);
|
||||
}
|
||||
|
||||
Light2D::Light2D() {
|
||||
@ -420,22 +305,170 @@ Light2D::Light2D() {
|
||||
shadow = false;
|
||||
color = Color(1, 1, 1);
|
||||
height = 0;
|
||||
_scale = 1.0;
|
||||
z_min = -1024;
|
||||
z_max = 1024;
|
||||
layer_min = 0;
|
||||
layer_max = 0;
|
||||
item_mask = 1;
|
||||
item_shadow_mask = 1;
|
||||
mode = MODE_ADD;
|
||||
energy = 1.0;
|
||||
shadow_color = Color(0, 0, 0, 0);
|
||||
shadow_filter = SHADOW_FILTER_NONE;
|
||||
shadow_smooth = 0;
|
||||
|
||||
blend_mode = BLEND_MODE_ADD;
|
||||
set_notify_transform(true);
|
||||
}
|
||||
|
||||
Light2D::~Light2D() {
|
||||
RenderingServer::get_singleton()->free(canvas_light);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
Dictionary PointLight2D::_edit_get_state() const {
|
||||
Dictionary state = Node2D::_edit_get_state();
|
||||
state["offset"] = get_texture_offset();
|
||||
return state;
|
||||
}
|
||||
|
||||
void PointLight2D::_edit_set_state(const Dictionary &p_state) {
|
||||
Node2D::_edit_set_state(p_state);
|
||||
set_texture_offset(p_state["offset"]);
|
||||
}
|
||||
|
||||
void PointLight2D::_edit_set_pivot(const Point2 &p_pivot) {
|
||||
set_position(get_transform().xform(p_pivot));
|
||||
set_texture_offset(get_texture_offset() - p_pivot);
|
||||
}
|
||||
|
||||
Point2 PointLight2D::_edit_get_pivot() const {
|
||||
return Vector2();
|
||||
}
|
||||
|
||||
bool PointLight2D::_edit_use_pivot() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
Rect2 PointLight2D::_edit_get_rect() const {
|
||||
if (texture.is_null()) {
|
||||
return Rect2();
|
||||
}
|
||||
|
||||
Size2 s = texture->get_size() * _scale;
|
||||
return Rect2(texture_offset - s / 2.0, s);
|
||||
}
|
||||
|
||||
bool PointLight2D::_edit_use_rect() const {
|
||||
return !texture.is_null();
|
||||
}
|
||||
#endif
|
||||
|
||||
Rect2 PointLight2D::get_anchorable_rect() const {
|
||||
if (texture.is_null()) {
|
||||
return Rect2();
|
||||
}
|
||||
|
||||
Size2 s = texture->get_size() * _scale;
|
||||
return Rect2(texture_offset - s / 2.0, s);
|
||||
}
|
||||
|
||||
void PointLight2D::set_texture(const Ref<Texture2D> &p_texture) {
|
||||
texture = p_texture;
|
||||
if (texture.is_valid()) {
|
||||
RS::get_singleton()->canvas_light_set_texture(_get_light(), texture->get_rid());
|
||||
} else {
|
||||
RS::get_singleton()->canvas_light_set_texture(_get_light(), RID());
|
||||
}
|
||||
|
||||
update_configuration_warning();
|
||||
}
|
||||
|
||||
Ref<Texture2D> PointLight2D::get_texture() const {
|
||||
return texture;
|
||||
}
|
||||
|
||||
void PointLight2D::set_texture_offset(const Vector2 &p_offset) {
|
||||
texture_offset = p_offset;
|
||||
RS::get_singleton()->canvas_light_set_texture_offset(_get_light(), texture_offset);
|
||||
item_rect_changed();
|
||||
_change_notify("offset");
|
||||
}
|
||||
|
||||
Vector2 PointLight2D::get_texture_offset() const {
|
||||
return texture_offset;
|
||||
}
|
||||
|
||||
String PointLight2D::get_configuration_warning() const {
|
||||
String warning = Node2D::get_configuration_warning();
|
||||
|
||||
if (!texture.is_valid()) {
|
||||
if (!warning.empty()) {
|
||||
warning += "\n\n";
|
||||
}
|
||||
warning += TTR("A texture with the shape of the light must be supplied to the \"Texture\" property.");
|
||||
}
|
||||
|
||||
return warning;
|
||||
}
|
||||
|
||||
void PointLight2D::set_texture_scale(float p_scale) {
|
||||
_scale = p_scale;
|
||||
// Avoid having 0 scale values, can lead to errors in physics and rendering.
|
||||
if (_scale == 0) {
|
||||
_scale = CMP_EPSILON;
|
||||
}
|
||||
RS::get_singleton()->canvas_light_set_texture_scale(_get_light(), _scale);
|
||||
item_rect_changed();
|
||||
}
|
||||
|
||||
float PointLight2D::get_texture_scale() const {
|
||||
return _scale;
|
||||
}
|
||||
|
||||
void PointLight2D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &PointLight2D::set_texture);
|
||||
ClassDB::bind_method(D_METHOD("get_texture"), &PointLight2D::get_texture);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_texture_offset", "texture_offset"), &PointLight2D::set_texture_offset);
|
||||
ClassDB::bind_method(D_METHOD("get_texture_offset"), &PointLight2D::get_texture_offset);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_texture_scale", "texture_scale"), &PointLight2D::set_texture_scale);
|
||||
ClassDB::bind_method(D_METHOD("get_texture_scale"), &PointLight2D::get_texture_scale);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_texture_offset", "get_texture_offset");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_scale", PROPERTY_HINT_RANGE, "0.01,50,0.01"), "set_texture_scale", "get_texture_scale");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"), "set_height", "get_height");
|
||||
}
|
||||
|
||||
PointLight2D::PointLight2D() {
|
||||
RS::get_singleton()->canvas_light_set_mode(_get_light(), RS::CANVAS_LIGHT_MODE_POINT);
|
||||
_scale = 1.0;
|
||||
}
|
||||
|
||||
PointLight2D::~PointLight2D() {
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
void DirectionalLight2D::set_max_distance(float p_distance) {
|
||||
max_distance = p_distance;
|
||||
RS::get_singleton()->canvas_light_set_directional_distance(_get_light(), max_distance);
|
||||
}
|
||||
float DirectionalLight2D::get_max_distance() const {
|
||||
return max_distance;
|
||||
}
|
||||
|
||||
void DirectionalLight2D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_max_distance", "pixels"), &DirectionalLight2D::set_max_distance);
|
||||
ClassDB::bind_method(D_METHOD("get_max_distance"), &DirectionalLight2D::get_max_distance);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_height", "get_height");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,16384.0,1.0,or_greater"), "set_max_distance", "get_max_distance");
|
||||
}
|
||||
DirectionalLight2D::DirectionalLight2D() {
|
||||
RS::get_singleton()->canvas_light_set_mode(_get_light(), RS::CANVAS_LIGHT_MODE_DIRECTIONAL);
|
||||
set_max_distance(10000.0);
|
||||
}
|
||||
|
@ -37,13 +37,6 @@ class Light2D : public Node2D {
|
||||
GDCLASS(Light2D, Node2D);
|
||||
|
||||
public:
|
||||
enum Mode {
|
||||
MODE_ADD,
|
||||
MODE_SUB,
|
||||
MODE_MIX,
|
||||
MODE_MASK,
|
||||
};
|
||||
|
||||
enum ShadowFilter {
|
||||
SHADOW_FILTER_NONE,
|
||||
SHADOW_FILTER_PCF5,
|
||||
@ -51,6 +44,12 @@ public:
|
||||
SHADOW_FILTER_MAX
|
||||
};
|
||||
|
||||
enum BlendMode {
|
||||
BLEND_MODE_ADD,
|
||||
BLEND_MODE_SUB,
|
||||
BLEND_MODE_MIX,
|
||||
};
|
||||
|
||||
private:
|
||||
RID canvas_light;
|
||||
bool enabled;
|
||||
@ -68,43 +67,25 @@ private:
|
||||
int item_mask;
|
||||
int item_shadow_mask;
|
||||
float shadow_smooth;
|
||||
Mode mode;
|
||||
Ref<Texture2D> texture;
|
||||
Vector2 texture_offset;
|
||||
ShadowFilter shadow_filter;
|
||||
BlendMode blend_mode;
|
||||
|
||||
void _update_light_visibility();
|
||||
|
||||
protected:
|
||||
_FORCE_INLINE_ RID _get_light() const { return canvas_light; }
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual Dictionary _edit_get_state() const override;
|
||||
virtual void _edit_set_state(const Dictionary &p_state) override;
|
||||
|
||||
virtual void _edit_set_pivot(const Point2 &p_pivot) override;
|
||||
virtual Point2 _edit_get_pivot() const override;
|
||||
virtual bool _edit_use_pivot() const override;
|
||||
virtual Rect2 _edit_get_rect() const override;
|
||||
virtual bool _edit_use_rect() const override;
|
||||
#endif
|
||||
|
||||
virtual Rect2 get_anchorable_rect() const override;
|
||||
|
||||
void set_enabled(bool p_enabled);
|
||||
bool is_enabled() const;
|
||||
|
||||
void set_editor_only(bool p_editor_only);
|
||||
bool is_editor_only() const;
|
||||
|
||||
void set_texture(const Ref<Texture2D> &p_texture);
|
||||
Ref<Texture2D> get_texture() const;
|
||||
|
||||
void set_texture_offset(const Vector2 &p_offset);
|
||||
Vector2 get_texture_offset() const;
|
||||
|
||||
void set_color(const Color &p_color);
|
||||
Color get_color() const;
|
||||
|
||||
@ -114,9 +95,6 @@ public:
|
||||
void set_energy(float p_energy);
|
||||
float get_energy() const;
|
||||
|
||||
void set_texture_scale(float p_scale);
|
||||
float get_texture_scale() const;
|
||||
|
||||
void set_z_range_min(int p_min_z);
|
||||
int get_z_range_min() const;
|
||||
|
||||
@ -135,9 +113,6 @@ public:
|
||||
void set_item_shadow_cull_mask(int p_mask);
|
||||
int get_item_shadow_cull_mask() const;
|
||||
|
||||
void set_mode(Mode p_mode);
|
||||
Mode get_mode() const;
|
||||
|
||||
void set_shadow_enabled(bool p_enabled);
|
||||
bool is_shadow_enabled() const;
|
||||
|
||||
@ -150,13 +125,69 @@ public:
|
||||
void set_shadow_smooth(float p_amount);
|
||||
float get_shadow_smooth() const;
|
||||
|
||||
String get_configuration_warning() const override;
|
||||
void set_blend_mode(BlendMode p_mode);
|
||||
BlendMode get_blend_mode() const;
|
||||
|
||||
Light2D();
|
||||
~Light2D();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(Light2D::Mode);
|
||||
VARIANT_ENUM_CAST(Light2D::ShadowFilter);
|
||||
VARIANT_ENUM_CAST(Light2D::BlendMode);
|
||||
|
||||
class PointLight2D : public Light2D {
|
||||
GDCLASS(PointLight2D, Light2D);
|
||||
|
||||
private:
|
||||
float _scale;
|
||||
Ref<Texture2D> texture;
|
||||
Vector2 texture_offset;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual Dictionary _edit_get_state() const override;
|
||||
virtual void _edit_set_state(const Dictionary &p_state) override;
|
||||
|
||||
virtual void _edit_set_pivot(const Point2 &p_pivot) override;
|
||||
virtual Point2 _edit_get_pivot() const override;
|
||||
virtual bool _edit_use_pivot() const override;
|
||||
virtual Rect2 _edit_get_rect() const override;
|
||||
virtual bool _edit_use_rect() const override;
|
||||
#endif
|
||||
|
||||
virtual Rect2 get_anchorable_rect() const override;
|
||||
|
||||
void set_texture(const Ref<Texture2D> &p_texture);
|
||||
Ref<Texture2D> get_texture() const;
|
||||
|
||||
void set_texture_offset(const Vector2 &p_offset);
|
||||
Vector2 get_texture_offset() const;
|
||||
|
||||
void set_texture_scale(float p_scale);
|
||||
float get_texture_scale() const;
|
||||
|
||||
String get_configuration_warning() const override;
|
||||
|
||||
PointLight2D();
|
||||
~PointLight2D();
|
||||
};
|
||||
|
||||
class DirectionalLight2D : public Light2D {
|
||||
GDCLASS(DirectionalLight2D, Light2D);
|
||||
|
||||
float max_distance = 10000.0;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_max_distance(float p_distance);
|
||||
float get_max_distance() const;
|
||||
|
||||
DirectionalLight2D();
|
||||
};
|
||||
|
||||
#endif // LIGHT_2D_H
|
||||
|
@ -628,7 +628,9 @@ void register_scene_types() {
|
||||
ClassDB::register_class<Polygon2D>();
|
||||
ClassDB::register_class<Skeleton2D>();
|
||||
ClassDB::register_class<Bone2D>();
|
||||
ClassDB::register_class<Light2D>();
|
||||
ClassDB::register_virtual_class<Light2D>();
|
||||
ClassDB::register_class<PointLight2D>();
|
||||
ClassDB::register_class<DirectionalLight2D>();
|
||||
ClassDB::register_class<LightOccluder2D>();
|
||||
ClassDB::register_class<OccluderPolygon2D>();
|
||||
ClassDB::register_class<YSort>();
|
||||
@ -917,6 +919,7 @@ void register_scene_types() {
|
||||
ClassDB::add_compatibility_class("VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform");
|
||||
ClassDB::add_compatibility_class("World", "World3D");
|
||||
ClassDB::add_compatibility_class("StreamTexture", "StreamTexture2D");
|
||||
ClassDB::add_compatibility_class("Light2D", "PointLight2D");
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -832,7 +832,9 @@ public:
|
||||
int layer_max;
|
||||
int item_mask;
|
||||
int item_shadow_mask;
|
||||
float directional_distance;
|
||||
RS::CanvasLightMode mode;
|
||||
RS::CanvasLightBlendMode blend_mode;
|
||||
RID texture;
|
||||
Vector2 texture_offset;
|
||||
RID canvas;
|
||||
@ -854,7 +856,7 @@ public:
|
||||
Light *shadows_next_ptr;
|
||||
Light *filter_next_ptr;
|
||||
Light *next_ptr;
|
||||
Light *mask_next_ptr;
|
||||
Light *directional_next_ptr;
|
||||
|
||||
RID light_internal;
|
||||
uint64_t version;
|
||||
@ -875,16 +877,18 @@ public:
|
||||
scale = 1.0;
|
||||
energy = 1.0;
|
||||
item_shadow_mask = 1;
|
||||
mode = RS::CANVAS_LIGHT_MODE_ADD;
|
||||
mode = RS::CANVAS_LIGHT_MODE_POINT;
|
||||
blend_mode = RS::CANVAS_LIGHT_BLEND_MODE_ADD;
|
||||
// texture_cache = nullptr;
|
||||
next_ptr = nullptr;
|
||||
mask_next_ptr = nullptr;
|
||||
directional_next_ptr = nullptr;
|
||||
filter_next_ptr = nullptr;
|
||||
use_shadow = false;
|
||||
shadow_buffer_size = 2048;
|
||||
shadow_filter = RS::CANVAS_LIGHT_FILTER_NONE;
|
||||
shadow_smooth = 0.0;
|
||||
render_index_cache = -1;
|
||||
directional_distance = 10000.0;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1322,7 +1326,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
virtual 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) = 0;
|
||||
virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) = 0;
|
||||
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0;
|
||||
|
||||
struct LightOccluderInstance {
|
||||
@ -1350,6 +1354,7 @@ public:
|
||||
virtual void light_set_texture(RID p_rid, RID p_texture) = 0;
|
||||
virtual void light_set_use_shadow(RID p_rid, bool p_enable) = 0;
|
||||
virtual 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) = 0;
|
||||
virtual 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) = 0;
|
||||
|
||||
virtual RID occluder_polygon_create() = 0;
|
||||
virtual void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) = 0;
|
||||
|
@ -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;
|
||||
|
@ -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) {}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
static const int z_range = RS::CANVAS_ITEM_Z_MAX - RS::CANVAS_ITEM_Z_MIN + 1;
|
||||
|
||||
void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) {
|
||||
void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) {
|
||||
RENDER_TIMESTAMP("Cull CanvasItem Tree");
|
||||
|
||||
memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *));
|
||||
@ -68,7 +68,7 @@ void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Can
|
||||
|
||||
RENDER_TIMESTAMP("Render Canvas Items");
|
||||
|
||||
RSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_transform, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
RSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_directional_lights, p_transform, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
}
|
||||
|
||||
void _collect_ysort_children(RenderingServerCanvas::Item *p_canvas_item, Transform2D p_transform, RenderingServerCanvas::Item *p_material_owner, RenderingServerCanvas::Item **r_items, int &r_index) {
|
||||
@ -298,28 +298,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights) {
|
||||
if (!p_masked_lights) {
|
||||
return;
|
||||
}
|
||||
|
||||
RasterizerCanvas::Item *ci = p_canvas_item;
|
||||
|
||||
while (ci) {
|
||||
RasterizerCanvas::Light *light = p_masked_lights;
|
||||
while (light) {
|
||||
if (ci->light_mask & light->item_mask && p_z >= light->z_min && p_z <= light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) {
|
||||
ci->light_masked = true;
|
||||
}
|
||||
|
||||
light = light->mask_next_ptr;
|
||||
}
|
||||
|
||||
ci = ci->next;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel) {
|
||||
void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_directional_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel) {
|
||||
RENDER_TIMESTAMP(">Render Canvas");
|
||||
|
||||
snapping_2d_transforms_to_pixel = p_snap_2d_transforms_to_pixel;
|
||||
@ -341,26 +320,26 @@ void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas,
|
||||
}
|
||||
|
||||
if (!has_mirror) {
|
||||
_render_canvas_item_tree(p_render_target, ci, l, nullptr, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
_render_canvas_item_tree(p_render_target, ci, l, nullptr, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
|
||||
} else {
|
||||
//used for parallaxlayer mirroring
|
||||
for (int i = 0; i < l; i++) {
|
||||
const Canvas::ChildItem &ci2 = p_canvas->child_items[i];
|
||||
_render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
_render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
|
||||
//mirroring (useful for scrolling backgrounds)
|
||||
if (ci2.mirror.x != 0) {
|
||||
Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0));
|
||||
_render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
_render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
}
|
||||
if (ci2.mirror.y != 0) {
|
||||
Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y));
|
||||
_render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
_render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
}
|
||||
if (ci2.mirror.y != 0 && ci2.mirror.x != 0) {
|
||||
Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror);
|
||||
_render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
_render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1040,13 +1019,38 @@ RID RenderingServerCanvas::canvas_light_create() {
|
||||
return canvas_light_owner.make_rid(clight);
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) {
|
||||
RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
|
||||
ERR_FAIL_COND(!clight);
|
||||
|
||||
if (clight->mode == p_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
RID canvas = clight->canvas;
|
||||
|
||||
if (canvas.is_valid()) {
|
||||
canvas_light_attach_to_canvas(p_light, RID());
|
||||
}
|
||||
|
||||
clight->mode = p_mode;
|
||||
|
||||
if (canvas.is_valid()) {
|
||||
canvas_light_attach_to_canvas(p_light, canvas);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) {
|
||||
RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
|
||||
ERR_FAIL_COND(!clight);
|
||||
|
||||
if (clight->canvas.is_valid()) {
|
||||
Canvas *canvas = canvas_owner.getornull(clight->canvas);
|
||||
canvas->lights.erase(clight);
|
||||
if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) {
|
||||
canvas->lights.erase(clight);
|
||||
} else {
|
||||
canvas->directional_lights.erase(clight);
|
||||
}
|
||||
}
|
||||
|
||||
if (!canvas_owner.owns(p_canvas)) {
|
||||
@ -1057,7 +1061,11 @@ void RenderingServerCanvas::canvas_light_attach_to_canvas(RID p_light, RID p_can
|
||||
|
||||
if (clight->canvas.is_valid()) {
|
||||
Canvas *canvas = canvas_owner.getornull(clight->canvas);
|
||||
canvas->lights.insert(clight);
|
||||
if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) {
|
||||
canvas->lights.insert(clight);
|
||||
} else {
|
||||
canvas->directional_lights.insert(clight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1068,7 +1076,7 @@ void RenderingServerCanvas::canvas_light_set_enabled(RID p_light, bool p_enabled
|
||||
clight->enabled = p_enabled;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_set_scale(RID p_light, float p_scale) {
|
||||
void RenderingServerCanvas::canvas_light_set_texture_scale(RID p_light, float p_scale) {
|
||||
RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
|
||||
ERR_FAIL_COND(!clight);
|
||||
|
||||
@ -1152,11 +1160,18 @@ void RenderingServerCanvas::canvas_light_set_item_shadow_cull_mask(RID p_light,
|
||||
clight->item_shadow_mask = p_mask;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) {
|
||||
void RenderingServerCanvas::canvas_light_set_directional_distance(RID p_light, float p_distance) {
|
||||
RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
|
||||
ERR_FAIL_COND(!clight);
|
||||
|
||||
clight->mode = p_mode;
|
||||
clight->directional_distance = p_distance;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode) {
|
||||
RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
|
||||
ERR_FAIL_COND(!clight);
|
||||
|
||||
clight->blend_mode = p_mode;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) {
|
||||
|
@ -116,6 +116,7 @@ public:
|
||||
};
|
||||
|
||||
Set<RasterizerCanvas::Light *> lights;
|
||||
Set<RasterizerCanvas::Light *> directional_lights;
|
||||
|
||||
Set<RasterizerCanvas::LightOccluderInstance *> occluders;
|
||||
|
||||
@ -155,15 +156,14 @@ public:
|
||||
bool snapping_2d_transforms_to_pixel = false;
|
||||
|
||||
private:
|
||||
void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
|
||||
void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
|
||||
void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner);
|
||||
void _light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights);
|
||||
|
||||
RasterizerCanvas::Item **z_list;
|
||||
RasterizerCanvas::Item **z_last_list;
|
||||
|
||||
public:
|
||||
void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel);
|
||||
void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_directional_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel);
|
||||
|
||||
RID canvas_create();
|
||||
void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring);
|
||||
@ -220,9 +220,10 @@ public:
|
||||
void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false);
|
||||
|
||||
RID canvas_light_create();
|
||||
void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode);
|
||||
void canvas_light_attach_to_canvas(RID p_light, RID p_canvas);
|
||||
void canvas_light_set_enabled(RID p_light, bool p_enabled);
|
||||
void canvas_light_set_scale(RID p_light, float p_scale);
|
||||
void canvas_light_set_texture_scale(RID p_light, float p_scale);
|
||||
void canvas_light_set_transform(RID p_light, const Transform2D &p_transform);
|
||||
void canvas_light_set_texture(RID p_light, RID p_texture);
|
||||
void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset);
|
||||
@ -233,8 +234,9 @@ public:
|
||||
void canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer);
|
||||
void canvas_light_set_item_cull_mask(RID p_light, int p_mask);
|
||||
void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask);
|
||||
void canvas_light_set_directional_distance(RID p_light, float p_distance);
|
||||
|
||||
void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode);
|
||||
void canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode);
|
||||
|
||||
void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled);
|
||||
void canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter);
|
||||
|
@ -748,9 +748,12 @@ public:
|
||||
BIND6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
|
||||
|
||||
BIND0R(RID, canvas_light_create)
|
||||
|
||||
BIND2(canvas_light_set_mode, RID, CanvasLightMode)
|
||||
|
||||
BIND2(canvas_light_attach_to_canvas, RID, RID)
|
||||
BIND2(canvas_light_set_enabled, RID, bool)
|
||||
BIND2(canvas_light_set_scale, RID, float)
|
||||
BIND2(canvas_light_set_texture_scale, RID, float)
|
||||
BIND2(canvas_light_set_transform, RID, const Transform2D &)
|
||||
BIND2(canvas_light_set_texture, RID, RID)
|
||||
BIND2(canvas_light_set_texture_offset, RID, const Vector2 &)
|
||||
@ -761,8 +764,9 @@ public:
|
||||
BIND3(canvas_light_set_layer_range, RID, int, int)
|
||||
BIND2(canvas_light_set_item_cull_mask, RID, int)
|
||||
BIND2(canvas_light_set_item_shadow_cull_mask, RID, int)
|
||||
BIND2(canvas_light_set_directional_distance, RID, float)
|
||||
|
||||
BIND2(canvas_light_set_mode, RID, CanvasLightMode)
|
||||
BIND2(canvas_light_set_blend_mode, RID, CanvasLightBlendMode)
|
||||
|
||||
BIND2(canvas_light_set_shadow_enabled, RID, bool)
|
||||
BIND2(canvas_light_set_shadow_filter, RID, CanvasLightShadowFilter)
|
||||
|
@ -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) {
|
||||
|
@ -647,9 +647,12 @@ public:
|
||||
FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
|
||||
|
||||
FUNC0R(RID, canvas_light_create)
|
||||
|
||||
FUNC2(canvas_light_set_mode, RID, CanvasLightMode)
|
||||
|
||||
FUNC2(canvas_light_attach_to_canvas, RID, RID)
|
||||
FUNC2(canvas_light_set_enabled, RID, bool)
|
||||
FUNC2(canvas_light_set_scale, RID, float)
|
||||
FUNC2(canvas_light_set_texture_scale, RID, float)
|
||||
FUNC2(canvas_light_set_transform, RID, const Transform2D &)
|
||||
FUNC2(canvas_light_set_texture, RID, RID)
|
||||
FUNC2(canvas_light_set_texture_offset, RID, const Vector2 &)
|
||||
@ -660,8 +663,9 @@ public:
|
||||
FUNC3(canvas_light_set_layer_range, RID, int, int)
|
||||
FUNC2(canvas_light_set_item_cull_mask, RID, int)
|
||||
FUNC2(canvas_light_set_item_shadow_cull_mask, RID, int)
|
||||
FUNC2(canvas_light_set_directional_distance, RID, float)
|
||||
|
||||
FUNC2(canvas_light_set_mode, RID, CanvasLightMode)
|
||||
FUNC2(canvas_light_set_blend_mode, RID, CanvasLightBlendMode)
|
||||
|
||||
FUNC2(canvas_light_set_shadow_enabled, RID, bool)
|
||||
FUNC2(canvas_light_set_shadow_filter, RID, CanvasLightShadowFilter)
|
||||
|
@ -1833,7 +1833,7 @@ void RenderingServer::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_create"), &RenderingServer::canvas_light_create);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_attach_to_canvas", "light", "canvas"), &RenderingServer::canvas_light_attach_to_canvas);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_set_enabled", "light", "enabled"), &RenderingServer::canvas_light_set_enabled);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_set_scale", "light", "scale"), &RenderingServer::canvas_light_set_scale);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_set_texture_scale", "light", "scale"), &RenderingServer::canvas_light_set_texture_scale);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_set_transform", "light", "transform"), &RenderingServer::canvas_light_set_transform);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_set_texture", "light", "texture"), &RenderingServer::canvas_light_set_texture);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_set_texture_offset", "light", "offset"), &RenderingServer::canvas_light_set_texture_offset);
|
||||
@ -2190,10 +2190,9 @@ void RenderingServer::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
|
||||
BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_MAX);
|
||||
|
||||
BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_ADD);
|
||||
BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_SUB);
|
||||
BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_MIX);
|
||||
BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_MASK);
|
||||
BIND_ENUM_CONSTANT(CANVAS_LIGHT_BLEND_MODE_ADD);
|
||||
BIND_ENUM_CONSTANT(CANVAS_LIGHT_BLEND_MODE_SUB);
|
||||
BIND_ENUM_CONSTANT(CANVAS_LIGHT_BLEND_MODE_MIX);
|
||||
|
||||
BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_NONE);
|
||||
BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_PCF5);
|
||||
|
@ -77,6 +77,7 @@ public:
|
||||
CANVAS_ITEM_Z_MAX = 4096,
|
||||
MAX_GLOW_LEVELS = 7,
|
||||
MAX_CURSORS = 8,
|
||||
MAX_2D_DIRECTIONAL_LIGHTS = 8
|
||||
};
|
||||
|
||||
/* TEXTURE API */
|
||||
@ -1195,12 +1196,17 @@ public:
|
||||
virtual void canvas_item_set_canvas_group_mode(RID p_item, CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false) = 0;
|
||||
|
||||
virtual RID canvas_light_create() = 0;
|
||||
|
||||
enum CanvasLightMode {
|
||||
CANVAS_LIGHT_MODE_POINT,
|
||||
CANVAS_LIGHT_MODE_DIRECTIONAL,
|
||||
};
|
||||
|
||||
virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode) = 0;
|
||||
|
||||
virtual void canvas_light_attach_to_canvas(RID p_light, RID p_canvas) = 0;
|
||||
virtual void canvas_light_set_enabled(RID p_light, bool p_enabled) = 0;
|
||||
virtual void canvas_light_set_scale(RID p_light, float p_scale) = 0;
|
||||
virtual void canvas_light_set_transform(RID p_light, const Transform2D &p_transform) = 0;
|
||||
virtual void canvas_light_set_texture(RID p_light, RID p_texture) = 0;
|
||||
virtual void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) = 0;
|
||||
virtual void canvas_light_set_color(RID p_light, const Color &p_color) = 0;
|
||||
virtual void canvas_light_set_height(RID p_light, float p_height) = 0;
|
||||
virtual void canvas_light_set_energy(RID p_light, float p_energy) = 0;
|
||||
@ -1209,14 +1215,19 @@ public:
|
||||
virtual void canvas_light_set_item_cull_mask(RID p_light, int p_mask) = 0;
|
||||
virtual void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) = 0;
|
||||
|
||||
enum CanvasLightMode {
|
||||
CANVAS_LIGHT_MODE_ADD,
|
||||
CANVAS_LIGHT_MODE_SUB,
|
||||
CANVAS_LIGHT_MODE_MIX,
|
||||
CANVAS_LIGHT_MODE_MASK,
|
||||
virtual void canvas_light_set_directional_distance(RID p_light, float p_distance) = 0;
|
||||
|
||||
virtual void canvas_light_set_texture_scale(RID p_light, float p_scale) = 0;
|
||||
virtual void canvas_light_set_texture(RID p_light, RID p_texture) = 0;
|
||||
virtual void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) = 0;
|
||||
|
||||
enum CanvasLightBlendMode {
|
||||
CANVAS_LIGHT_BLEND_MODE_ADD,
|
||||
CANVAS_LIGHT_BLEND_MODE_SUB,
|
||||
CANVAS_LIGHT_BLEND_MODE_MIX,
|
||||
};
|
||||
|
||||
virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode) = 0;
|
||||
virtual void canvas_light_set_blend_mode(RID p_light, CanvasLightBlendMode p_mode) = 0;
|
||||
|
||||
enum CanvasLightShadowFilter {
|
||||
CANVAS_LIGHT_FILTER_NONE,
|
||||
@ -1435,6 +1446,7 @@ VARIANT_ENUM_CAST(RenderingServer::NinePatchAxisMode);
|
||||
VARIANT_ENUM_CAST(RenderingServer::CanvasItemTextureFilter);
|
||||
VARIANT_ENUM_CAST(RenderingServer::CanvasItemTextureRepeat);
|
||||
VARIANT_ENUM_CAST(RenderingServer::CanvasLightMode);
|
||||
VARIANT_ENUM_CAST(RenderingServer::CanvasLightBlendMode);
|
||||
VARIANT_ENUM_CAST(RenderingServer::CanvasLightShadowFilter);
|
||||
VARIANT_ENUM_CAST(RenderingServer::CanvasOccluderPolygonCullMode);
|
||||
VARIANT_ENUM_CAST(RenderingServer::GlobalVariableType);
|
||||
|
Loading…
Reference in New Issue
Block a user