Normalmapping and Specularmapping working in 2D engine

Added support for Sprite, AnimatedSprite and Polygon2D (should add for tileset eventually).
This commit is contained in:
Juan Linietsky 2019-07-04 22:54:32 -03:00
parent 92b27bccf1
commit a7b2ac7bb1
21 changed files with 1214 additions and 166 deletions

View file

@ -141,6 +141,16 @@ public:
free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk] = idx;
}
_FORCE_INLINE_ uint32_t get_rid_count() const {
return alloc_count;
}
_FORCE_INLINE_ T *get_rid_by_index(uint32_t p_index) {
ERR_FAIL_INDEX_V(p_index, alloc_count, NULL);
uint64_t idx = free_list_chunks[p_index / elements_in_chunk][p_index % elements_in_chunk];
return &chunks[idx / elements_in_chunk][idx % elements_in_chunk];
}
void get_owned_list(List<RID> *p_owned) {
for (size_t i = 0; i < alloc_count; i++) {
uint64_t idx = free_list_chunks[i / elements_in_chunk][i % elements_in_chunk];
@ -250,6 +260,14 @@ public:
alloc.free(p_rid);
}
_FORCE_INLINE_ uint32_t get_rid_count() const {
return alloc.get_rid_count();
}
_FORCE_INLINE_ T *get_rid_by_index(uint32_t p_index) {
return alloc.get_rid_by_index(p_index);
}
_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
return alloc.get_owned_list(p_owned);
}

View file

@ -1613,6 +1613,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
}
if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
printf("vkformat: %x\n", image_create_info.format);
ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment.");
}
@ -1664,7 +1665,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
//set bound and unbound layouts
if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
texture.aspect_mask = TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
texture.aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) {
texture.unbound_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
@ -3168,7 +3169,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
} break;*/
default: {
if (reflection.getType()->getQualifier().hasOffset()) {
if (reflection.getType()->getQualifier().hasOffset() || reflection.name.find(".") != std::string::npos) {
//member of uniform block?
return true;
}
@ -4126,7 +4127,7 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) {
return uniform_set_owner.owns(p_uniform_set);
}
Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, void *p_data, bool p_sync_with_draw) {
Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(draw_list && p_sync_with_draw, ERR_INVALID_PARAMETER,

View file

@ -769,7 +769,7 @@ public:
virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
virtual bool uniform_set_is_valid(RID p_uniform_set);
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, void *p_data, bool p_sync_with_draw = false); //works for any buffer
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw = false); //works for any buffer
/*************************/
/**** RENDER PIPELINE ****/

View file

@ -34,6 +34,7 @@
#include "scene/scene_string_names.h"
#define NORMAL_SUFFIX "_normal"
#define SPECULAR_SUFFIX "_specular"
#ifdef TOOLS_ENABLED
Dictionary AnimatedSprite::_edit_get_state() const {
@ -150,6 +151,7 @@ void SpriteFrames::add_animation(const StringName &p_anim) {
animations[p_anim] = Anim();
animations[p_anim].normal_name = String(p_anim) + NORMAL_SUFFIX;
animations[p_anim].specular_name = String(p_anim) + SPECULAR_SUFFIX;
}
bool SpriteFrames::has_animation(const StringName &p_anim) const {
@ -170,6 +172,7 @@ void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &
animations.erase(p_prev);
animations[p_next] = anim;
animations[p_next].normal_name = String(p_next) + NORMAL_SUFFIX;
animations[p_next].specular_name = String(p_next) + SPECULAR_SUFFIX;
}
Vector<String> SpriteFrames::_get_animation_list() const {
@ -443,6 +446,7 @@ void AnimatedSprite::_notification(int p_what) {
return;
Ref<Texture2D> normal = frames->get_normal_frame(animation, frame);
Ref<Texture2D> specular = frames->get_specular_frame(animation, frame);
RID ci = get_canvas_item();
@ -462,7 +466,7 @@ void AnimatedSprite::_notification(int p_what) {
if (vflip)
dst_rect.size.y = -dst_rect.size.y;
texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal);
texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess));
} break;
}
@ -674,6 +678,24 @@ String AnimatedSprite::get_configuration_warning() const {
return String();
}
void AnimatedSprite::set_specular_color(const Color &p_color) {
specular_color = p_color;
update();
}
Color AnimatedSprite::get_specular_color() const {
return specular_color;
}
void AnimatedSprite::set_shininess(float p_shininess) {
shininess = CLAMP(p_shininess, 0.0, 1.0);
update();
}
float AnimatedSprite::get_shininess() const {
return shininess;
}
void AnimatedSprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sprite_frames", "sprite_frames"), &AnimatedSprite::set_sprite_frames);
@ -707,16 +729,27 @@ void AnimatedSprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite::set_speed_scale);
ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite::get_speed_scale);
ClassDB::bind_method(D_METHOD("set_specular_color", "color"), &AnimatedSprite::set_specular_color);
ClassDB::bind_method(D_METHOD("get_specular_color"), &AnimatedSprite::get_specular_color);
ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &AnimatedSprite::set_shininess);
ClassDB::bind_method(D_METHOD("get_shininess"), &AnimatedSprite::get_shininess);
ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite::_res_changed);
ADD_SIGNAL(MethodInfo("frame_changed"));
ADD_SIGNAL(MethodInfo("animation_finished"));
ADD_GROUP("Animation", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
ADD_GROUP("Lighting", "");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess");
ADD_GROUP("Offset", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
@ -736,4 +769,6 @@ AnimatedSprite::AnimatedSprite() {
animation = "default";
timeout = 0;
is_over = false;
specular_color = Color(1, 1, 1, 1);
shininess = 1.0;
}

View file

@ -50,8 +50,12 @@ class SpriteFrames : public Resource {
}
StringName normal_name;
StringName specular_name;
};
Color specular_color;
float shininess;
Map<StringName, Anim> animations;
Array _get_frames() const;
@ -107,6 +111,20 @@ public:
return EN->get().frames[p_idx];
}
_FORCE_INLINE_ Ref<Texture2D> get_specular_frame(const StringName &p_anim, int p_idx) const {
const Map<StringName, Anim>::Element *E = animations.find(p_anim);
ERR_FAIL_COND_V(!E, Ref<Texture2D>());
ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
const Map<StringName, Anim>::Element *EN = animations.find(E->get().specular_name);
if (!EN || p_idx >= EN->get().frames.size())
return Ref<Texture2D>();
return EN->get().frames[p_idx];
}
void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) {
Map<StringName, Anim>::Element *E = animations.find(p_anim);
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
@ -150,6 +168,9 @@ class AnimatedSprite : public Node2D {
bool _is_playing() const;
Rect2 _get_rect() const;
Color specular_color;
float shininess;
protected:
static void _bind_methods();
void _notification(int p_what);
@ -197,8 +218,11 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
void set_modulate(const Color &p_color);
Color get_modulate() const;
void set_specular_color(const Color &p_color);
Color get_specular_color() const;
void set_shininess(float p_shininess);
float get_shininess() const;
virtual String get_configuration_warning() const;
AnimatedSprite();

View file

@ -307,7 +307,7 @@ void Polygon2D::_notification(int p_what) {
if (invert || polygons.size() == 0) {
Vector<int> indices = Geometry::triangulate_polygon(points);
if (indices.size()) {
VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID());
VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID(), -1, normal_map.is_valid() ? normal_map->get_rid() : RID(), specular_map.is_valid() ? specular_map->get_rid() : RID(), Color(specular_color.r, specular_color.g, specular_color.b, shininess));
}
} else {
//draw individual polygons
@ -430,6 +430,42 @@ Ref<Texture2D> Polygon2D::get_texture() const {
return texture;
}
void Polygon2D::set_normal_map(const Ref<Texture2D> &p_normal_map) {
normal_map = p_normal_map;
update();
}
Ref<Texture2D> Polygon2D::get_normal_map() const {
return normal_map;
}
void Polygon2D::set_specular_map(const Ref<Texture2D> &p_specular_map) {
specular_map = p_specular_map;
update();
}
Ref<Texture2D> Polygon2D::get_specular_map() const {
return specular_map;
}
void Polygon2D::set_specular_color(const Color &p_specular_color) {
specular_color = p_specular_color;
update();
}
Color Polygon2D::get_specular_color() const {
return specular_color;
}
void Polygon2D::set_shininess(float p_shininess) {
shininess = CLAMP(p_shininess, 0.0, 1.0);
update();
}
float Polygon2D::get_shininess() const {
return shininess;
}
void Polygon2D::set_texture_offset(const Vector2 &p_offset) {
tex_ofs = p_offset;
@ -600,6 +636,18 @@ void Polygon2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Polygon2D::set_texture);
ClassDB::bind_method(D_METHOD("get_texture"), &Polygon2D::get_texture);
ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &Polygon2D::set_normal_map);
ClassDB::bind_method(D_METHOD("get_normal_map"), &Polygon2D::get_normal_map);
ClassDB::bind_method(D_METHOD("set_specular_map", "specular_map"), &Polygon2D::set_specular_map);
ClassDB::bind_method(D_METHOD("get_specular_map"), &Polygon2D::get_specular_map);
ClassDB::bind_method(D_METHOD("set_specular_color", "specular_color"), &Polygon2D::set_specular_color);
ClassDB::bind_method(D_METHOD("get_specular_color"), &Polygon2D::get_specular_color);
ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &Polygon2D::set_shininess);
ClassDB::bind_method(D_METHOD("get_shininess"), &Polygon2D::get_shininess);
ClassDB::bind_method(D_METHOD("set_texture_offset", "texture_offset"), &Polygon2D::set_texture_offset);
ClassDB::bind_method(D_METHOD("get_texture_offset"), &Polygon2D::get_texture_offset);
@ -654,6 +702,11 @@ void Polygon2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_texture_rotation_degrees", "get_texture_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation");
ADD_GROUP("Lighting", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_map", "get_specular_map");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess");
ADD_GROUP("Skeleton", "");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton");
@ -682,4 +735,6 @@ Polygon2D::Polygon2D() {
rect_cache_dirty = true;
internal_vertices = 0;
current_skeleton_id = 0;
specular_color = Color(1, 1, 1, 1);
shininess = 1.0;
}

View file

@ -52,6 +52,11 @@ class Polygon2D : public Node2D {
Color color;
Ref<Texture2D> texture;
Ref<Texture2D> normal_map;
Ref<Texture2D> specular_map;
Color specular_color;
float shininess;
Size2 tex_scale;
Vector2 tex_ofs;
bool tex_tile;
@ -111,6 +116,18 @@ public:
void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const;
void set_normal_map(const Ref<Texture2D> &p_normal_map);
Ref<Texture2D> get_normal_map() const;
void set_specular_map(const Ref<Texture2D> &p_specular_map);
Ref<Texture2D> get_specular_map() const;
void set_specular_color(const Color &p_specular_color);
Color get_specular_color() const;
void set_shininess(float p_shininess);
float get_shininess() const;
void set_texture_offset(const Vector2 &p_offset);
Vector2 get_texture_offset() const;

View file

@ -130,7 +130,7 @@ void Sprite::_notification(int p_what) {
Rect2 src_rect, dst_rect;
bool filter_clip;
_get_rects(src_rect, dst_rect, filter_clip);
texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, Ref<Texture2D>(), Color(1, 1, 1, 1), VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, filter_clip);
texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess), VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, filter_clip);
} break;
}
@ -166,6 +166,35 @@ Ref<Texture2D> Sprite::get_normal_map() const {
return normal_map;
}
void Sprite::set_specular_map(const Ref<Texture2D> &p_texture) {
specular = p_texture;
update();
}
Ref<Texture2D> Sprite::get_specular_map() const {
return specular;
}
void Sprite::set_specular_color(const Color &p_color) {
specular_color = p_color;
update();
}
Color Sprite::get_specular_color() const {
return specular_color;
}
void Sprite::set_shininess(float p_shininess) {
shininess = CLAMP(p_shininess, 0.0, 1.0);
update();
}
float Sprite::get_shininess() const {
return shininess;
}
Ref<Texture2D> Sprite::get_texture() const {
return texture;
@ -334,7 +363,7 @@ bool Sprite::is_pixel_opaque(const Point2 &p_point) const {
if (vflip)
q.y = 1.0f - q.y;
q = q * src_rect.size + src_rect.position;
#warning this need to be obtained from CanvasItem repeat mode when I add it
#warning this need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that)
bool is_repeat = false;
bool is_mirrored_repeat = false;
if (is_repeat) {
@ -415,6 +444,15 @@ void Sprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &Sprite::set_normal_map);
ClassDB::bind_method(D_METHOD("get_normal_map"), &Sprite::get_normal_map);
ClassDB::bind_method(D_METHOD("set_specular_map", "specular_map"), &Sprite::set_specular_map);
ClassDB::bind_method(D_METHOD("get_specular_map"), &Sprite::get_specular_map);
ClassDB::bind_method(D_METHOD("set_specular_color", "specular_color"), &Sprite::set_specular_color);
ClassDB::bind_method(D_METHOD("get_specular_color"), &Sprite::get_specular_color);
ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &Sprite::set_shininess);
ClassDB::bind_method(D_METHOD("get_shininess"), &Sprite::get_shininess);
ClassDB::bind_method(D_METHOD("set_centered", "centered"), &Sprite::set_centered);
ClassDB::bind_method(D_METHOD("is_centered"), &Sprite::is_centered);
@ -458,7 +496,11 @@ void Sprite::_bind_methods() {
ADD_SIGNAL(MethodInfo("texture_changed"));
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_GROUP("Lighting", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_map", "get_specular_map");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess");
ADD_GROUP("Offset", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
@ -483,6 +525,8 @@ Sprite::Sprite() {
vflip = false;
region = false;
region_filter_clip = false;
shininess = 1.0;
specular_color = Color(1, 1, 1, 1);
frame = 0;

View file

@ -40,6 +40,9 @@ class Sprite : public Node2D {
Ref<Texture2D> texture;
Ref<Texture2D> normal_map;
Ref<Texture2D> specular;
Color specular_color;
float shininess;
bool centered;
Point2 offset;
@ -88,6 +91,15 @@ public:
void set_normal_map(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_normal_map() const;
void set_specular_map(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_specular_map() const;
void set_specular_color(const Color &p_color);
Color get_specular_color() const;
void set_shininess(float p_shininess);
float get_shininess() const;
void set_centered(bool p_center);
bool is_centered() const;

View file

@ -562,15 +562,6 @@ public:
virtual void render_target_disable_clear_request(RID p_render_target) = 0;
virtual void render_target_do_clear_request(RID p_render_target) = 0;
/* CANVAS SHADOW */
virtual RID canvas_light_shadow_buffer_create(int p_width) = 0;
/* LIGHT SHADOW MAPPING */
virtual RID canvas_light_occluder_create() = 0;
virtual void canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) = 0;
virtual VS::InstanceType get_base_type(RID p_rid) const = 0;
virtual bool free(RID p_rid) = 0;
@ -625,21 +616,21 @@ public:
RID texture;
Vector2 texture_offset;
RID canvas;
RID shadow_buffer;
bool use_shadow;
int shadow_buffer_size;
float shadow_gradient_length;
VS::CanvasLightShadowFilter shadow_filter;
Color shadow_color;
float shadow_smooth;
void *texture_cache; // implementation dependent
//void *texture_cache; // implementation dependent
Rect2 rect_cache;
Transform2D xform_cache;
float radius_cache; //used for shadow far plane
CameraMatrix shadow_matrix_cache;
//CameraMatrix shadow_matrix_cache;
Transform2D light_shader_xform;
Vector2 light_shader_pos;
//Vector2 light_shader_pos;
Light *shadows_next_ptr;
Light *filter_next_ptr;
@ -648,6 +639,8 @@ public:
RID light_internal;
int32_t render_index_cache;
Light() {
enabled = true;
color = Color(1, 1, 1);
@ -662,21 +655,19 @@ public:
energy = 1.0;
item_shadow_mask = -1;
mode = VS::CANVAS_LIGHT_MODE_ADD;
texture_cache = NULL;
// texture_cache = NULL;
next_ptr = NULL;
mask_next_ptr = NULL;
filter_next_ptr = NULL;
use_shadow = false;
shadow_buffer_size = 2048;
shadow_gradient_length = 0;
shadow_filter = VS::CANVAS_LIGHT_FILTER_NONE;
shadow_smooth = 0.0;
render_index_cache = -1;
}
};
virtual RID light_internal_create() = 0;
virtual void light_internal_update(RID p_rid, Light *p_light) = 0;
virtual void light_internal_free(RID p_rid) = 0;
typedef uint64_t TextureBindingID;
virtual TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) = 0;
@ -957,7 +948,7 @@ public:
case Item::Command::TYPE_PRIMITIVE: {
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
for (int j = 0; j < primitive->point_count; j++) {
for (uint32_t j = 0; j < primitive->point_count; j++) {
if (j == 0) {
r.position = primitive->points[0];
} else {
@ -1085,7 +1076,7 @@ public:
c = n;
}
{
uint32_t cbc = MIN((current_block + 1), blocks.size());
uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size());
CommandBlock *blockptr = blocks.ptrw();
for (uint32_t i = 0; i < cbc; i++) {
blockptr[i].usage = 0;
@ -1139,7 +1130,7 @@ public:
bool enabled;
RID canvas;
RID polygon;
RID polygon_buffer;
RID occluder;
Rect2 aabb_cache;
Transform2D xform;
Transform2D xform_cache;
@ -1156,12 +1147,18 @@ public:
}
};
virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) = 0;
virtual RID light_create() = 0;
virtual void light_set_texture(RID p_rid, RID p_texture) = 0;
virtual void light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution) = 0;
virtual void light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0;
virtual void reset_canvas() = 0;
virtual RID occluder_polygon_create() = 0;
virtual void occluder_polygon_set_shape_as_lines(RID p_occluder, const PoolVector<Vector2> &p_lines) = 0;
virtual void occluder_polygon_set_cull_mode(RID p_occluder, VS::CanvasOccluderPolygonCullMode p_mode) = 0;
virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0;
virtual bool free(RID p_rid) = 0;
virtual void update() = 0;
RasterizerCanvas() { singleton = this; }

View file

@ -63,6 +63,14 @@ void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform,
p_mat4[15] = 1;
}
void RasterizerCanvasRD::_update_specular_shininess(const Color &p_transform, uint32_t *r_ss) {
*r_ss = uint32_t(CLAMP(p_transform.a * 255.0, 0, 255)) << 24;
*r_ss |= uint32_t(CLAMP(p_transform.b * 255.0, 0, 255)) << 16;
*r_ss |= uint32_t(CLAMP(p_transform.g * 255.0, 0, 255)) << 8;
*r_ss |= uint32_t(CLAMP(p_transform.r * 255.0, 0, 255));
}
RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) {
Vector<RD::Uniform> uniform_set;
@ -472,12 +480,19 @@ void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) {
polygon_buffers.polygons.erase(p_polygon);
}
Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD::DrawListID p_draw_list) {
Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD::DrawListID p_draw_list, uint32_t &flags) {
TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(p_binding);
ERR_FAIL_COND_V(!texture_binding_ptr, Size2i());
TextureBinding *texture_binding = *texture_binding_ptr;
if (texture_binding->key.normalmap.is_valid()) {
flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
}
if (texture_binding->key.specular.is_valid()) {
flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
if (!RD::get_singleton()->uniform_set_is_valid(texture_binding->uniform_set)) {
//texture may have changed (erased or replaced, see if we can fix)
texture_binding->uniform_set = _create_texture_binding(texture_binding->key.texture, texture_binding->key.normalmap, texture_binding->key.specular, texture_binding->key.texture_filter, texture_binding->key.texture_repeat, texture_binding->key.multimesh);
@ -493,12 +508,15 @@ Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD:
}
////////////////////
void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RD::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse, Item *&current_clip) {
void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RD::TextureSamples p_samples, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights) {
//create an empty push constant
PushConstant push_constant;
Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
_update_transform_2d_to_mat2x3(base_transform, push_constant.world);
Color base_color = p_item->final_modulate;
for (int i = 0; i < 4; i++) {
push_constant.modulation[i] = 0;
push_constant.ninepatch_margins[i] = 0;
@ -506,7 +524,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
push_constant.dst_rect[i] = 0;
}
push_constant.flags = 0;
push_constant.specular_shininess = 0xFFFFFFFF;
push_constant.color_texture_pixel_size[0] = 0;
push_constant.color_texture_pixel_size[1] = 0;
@ -514,6 +531,37 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
push_constant.pad[2] = 0;
push_constant.pad[3] = 0;
push_constant.lights[0] = 0;
push_constant.lights[1] = 0;
push_constant.lights[2] = 0;
push_constant.lights[3] = 0;
uint32_t base_flags = 0;
{
Light *light = p_lights;
uint16_t light_count = 0;
while (light) {
if (light->render_index_cache >= 0 && p_item->light_mask & light->item_mask && p_item->z_final >= light->z_min && p_item->z_final <= light->z_max && p_item->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) {
uint32_t light_index = light->render_index_cache;
push_constant.lights[light_count >> 2] |= light_index << ((light_count & 3) * 8);
light_count++;
if (light->mode == VS::CANVAS_LIGHT_MODE_MASK) {
base_flags |= FLAGS_USING_LIGHT_MASK;
}
if (light_count == MAX_LIGHTS_PER_ITEM) {
break;
}
}
light = light->next_ptr;
}
base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
}
PipelineVariants *pipeline_variants = &shader.pipeline_variants;
bool reclip = false;
@ -521,7 +569,8 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
const Item::Command *c = p_item->commands;
while (c) {
push_constant.flags = 0; //reset on each command for sanity
push_constant.flags = base_flags; //reset on each command for sanity
push_constant.specular_shininess = 0xFFFFFFFF;
switch (c->type) {
case Item::Command::TYPE_RECT: {
@ -538,11 +587,17 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
Size2 texpixel_size;
{
texpixel_size = _bind_texture_binding(rect->texture_binding.binding_id, p_draw_list);
texpixel_size = _bind_texture_binding(rect->texture_binding.binding_id, p_draw_list, push_constant.flags);
texpixel_size.x = 1.0 / texpixel_size.x;
texpixel_size.y = 1.0 / texpixel_size.y;
}
if (rect->specular_shininess.a < 0.999) {
push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
_update_specular_shininess(rect->specular_shininess, &push_constant.specular_shininess);
Rect2 src_rect;
Rect2 dst_rect;
@ -594,10 +649,10 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
texpixel_size = Vector2(1, 1);
}
push_constant.modulation[0] = rect->modulate.r * p_modulate.r;
push_constant.modulation[1] = rect->modulate.g * p_modulate.g;
push_constant.modulation[2] = rect->modulate.b * p_modulate.b;
push_constant.modulation[3] = rect->modulate.a;
push_constant.modulation[0] = rect->modulate.r * base_color.r;
push_constant.modulation[1] = rect->modulate.g * base_color.g;
push_constant.modulation[2] = rect->modulate.b * base_color.b;
push_constant.modulation[3] = rect->modulate.a * base_color.a;
push_constant.src_rect[0] = src_rect.position.x;
push_constant.src_rect[1] = src_rect.position.y;
@ -632,11 +687,17 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
Size2 texpixel_size;
{
texpixel_size = _bind_texture_binding(np->texture_binding.binding_id, p_draw_list);
texpixel_size = _bind_texture_binding(np->texture_binding.binding_id, p_draw_list, push_constant.flags);
texpixel_size.x = 1.0 / texpixel_size.x;
texpixel_size.y = 1.0 / texpixel_size.y;
}
if (np->specular_shininess.a < 0.999) {
push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
_update_specular_shininess(np->specular_shininess, &push_constant.specular_shininess);
Rect2 src_rect;
Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y);
@ -655,10 +716,10 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
}
}
push_constant.modulation[0] = np->color.r * p_modulate.r;
push_constant.modulation[1] = np->color.g * p_modulate.g;
push_constant.modulation[2] = np->color.b * p_modulate.b;
push_constant.modulation[3] = np->color.a * p_modulate.a;
push_constant.modulation[0] = np->color.r * base_color.r;
push_constant.modulation[1] = np->color.g * base_color.g;
push_constant.modulation[2] = np->color.b * base_color.b;
push_constant.modulation[3] = np->color.a * base_color.a;
push_constant.src_rect[0] = src_rect.position.x;
push_constant.src_rect[1] = src_rect.position.y;
@ -713,15 +774,21 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
Size2 texpixel_size;
{
texpixel_size = _bind_texture_binding(polygon->texture_binding.binding_id, p_draw_list);
texpixel_size = _bind_texture_binding(polygon->texture_binding.binding_id, p_draw_list, push_constant.flags);
texpixel_size.x = 1.0 / texpixel_size.x;
texpixel_size.y = 1.0 / texpixel_size.y;
}
push_constant.modulation[0] = p_modulate.r;
push_constant.modulation[1] = p_modulate.g;
push_constant.modulation[2] = p_modulate.b;
push_constant.modulation[3] = p_modulate.a;
if (polygon->specular_shininess.a < 0.999) {
push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
_update_specular_shininess(polygon->specular_shininess, &push_constant.specular_shininess);
push_constant.modulation[0] = base_color.r;
push_constant.modulation[1] = base_color.g;
push_constant.modulation[2] = base_color.b;
push_constant.modulation[3] = base_color.a;
for (int j = 0; j < 4; j++) {
push_constant.src_rect[j] = 0;
@ -755,9 +822,15 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
//bind textures
{
_bind_texture_binding(primitive->texture_binding.binding_id, p_draw_list);
_bind_texture_binding(primitive->texture_binding.binding_id, p_draw_list, push_constant.flags);
}
if (primitive->specular_shininess.a < 0.999) {
push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
_update_specular_shininess(primitive->specular_shininess, &push_constant.specular_shininess);
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3, primitive->point_count) - 1]);
for (uint32_t j = 0; j < MIN(3, primitive->point_count); j++) {
@ -765,7 +838,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
push_constant.points[j * 2 + 1] = primitive->points[j].y;
push_constant.uvs[j * 2 + 0] = primitive->uvs[j].x;
push_constant.uvs[j * 2 + 1] = primitive->uvs[j].y;
Color col = primitive->colors[j] * p_modulate;
Color col = primitive->colors[j] * base_color;
push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
}
@ -779,7 +852,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
push_constant.points[j * 2 + 1] = primitive->points[j + 1].y;
push_constant.uvs[j * 2 + 0] = primitive->uvs[j + 1].x;
push_constant.uvs[j * 2 + 1] = primitive->uvs[j + 1].y;
Color col = primitive->colors[j + 1] * p_modulate;
Color col = primitive->colors[j + 1] * base_color;
push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
}
@ -1107,12 +1180,12 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
}
}
void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Color &p_modulate, const Transform2D &p_transform) {
void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights) {
Item *current_clip = NULL;
RenderTargetFormat render_target_format = RENDER_TARGET_FORMAT_8_BIT_INT;
Transform2D canvas_transform_inverse = p_transform.affine_inverse();
Transform2D canvas_transform_inverse = p_canvas_transform_inverse;
RID framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target);
@ -1153,7 +1226,7 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count,
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, shader.default_skeleton_uniform_set, 1);
}
_render_item(draw_list, ci, render_target_format, texture_samples, p_modulate, canvas_transform_inverse, current_clip);
_render_item(draw_list, ci, render_target_format, texture_samples, canvas_transform_inverse, current_clip, p_lights);
}
RD::get_singleton()->draw_list_end();
@ -1167,11 +1240,67 @@ void RasterizerCanvasRD::_update_canvas_state_uniform_set() {
Vector<RD::Uniform> uniforms;
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 0;
u.ids.push_back(state.canvas_state_buffer);
uniforms.push_back(u);
{
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 0;
u.ids.push_back(state.canvas_state_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 1;
u.ids.push_back(state.lights_uniform_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u_lights;
u_lights.type = RD::UNIFORM_TYPE_TEXTURE;
u_lights.binding = 2;
RD::Uniform u_shadows;
u_shadows.type = RD::UNIFORM_TYPE_TEXTURE;
u_shadows.binding = 3;
//lights
for (uint32_t i = 0; i < MAX_LIGHT_TEXTURES; i++) {
if (i < canvas_light_owner.get_rid_count()) {
CanvasLight *cl = canvas_light_owner.get_rid_by_index(i);
cl->texture_index = i;
RID rd_texture;
if (cl->texture.is_valid()) {
rd_texture = storage->texture_get_rd_texture(cl->texture);
}
if (rd_texture.is_valid()) {
u_lights.ids.push_back(rd_texture);
} else {
u_lights.ids.push_back(default_textures.white_texture);
}
if (cl->shadow.texture.is_valid()) {
u_shadows.ids.push_back(cl->shadow.texture);
} else {
u_shadows.ids.push_back(default_textures.black_texture);
}
} else {
u_lights.ids.push_back(default_textures.white_texture);
u_shadows.ids.push_back(default_textures.black_texture);
}
}
//in case there are more
for (uint32_t i = MAX_LIGHT_TEXTURES; i < canvas_light_owner.get_rid_count(); i++) {
CanvasLight *cl = canvas_light_owner.get_rid_by_index(i);
cl->texture_index = -1; //make invalid (no texture)
}
uniforms.push_back(u_lights);
uniforms.push_back(u_shadows);
}
state.canvas_state_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 3); // uses index 3
}
@ -1182,6 +1311,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
//setup canvas state uniforms if needed
_update_canvas_state_uniform_set();
Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse();
{
//update canvas state uniform buffer
@ -1194,9 +1324,77 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
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;
RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true);
}
//setup lights if exist
{
Light *l = p_light_list;
uint32_t index = 0;
while (l) {
if (index == MAX_RENDER_LIGHTS) {
l->render_index_cache = -1;
l = l->next_ptr;
continue;
}
CanvasLight *clight = canvas_light_owner.getornull(l->light_internal);
if (!clight || clight->texture_index < 0) { //unused or invalid texture
l->render_index_cache = -1;
l = l->next_ptr;
ERR_CONTINUE(!clight);
}
Transform2D to_light_xform = (p_canvas_transform * l->light_shader_xform).affine_inverse();
Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
state.light_uniforms[index].position[0] = canvas_light_pos.x;
state.light_uniforms[index].position[1] = canvas_light_pos.y;
_update_transform_2d_to_mat2x4(to_light_xform, state.light_uniforms[index].matrix);
state.light_uniforms[index].height = l->height * (p_canvas_transform.elements[0].length() + p_canvas_transform.elements[1].length()) * 0.5; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss
for (int i = 0; i < 4; i++) {
state.light_uniforms[index].shadow_color[i] = l->shadow_color[i];
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 (clight->shadow.texture.is_valid()) {
state.light_uniforms[index].shadow_pixel_size = 1.0 / clight->shadow.size;
} else {
state.light_uniforms[index].shadow_pixel_size = 1.0;
}
state.light_uniforms[index].flags = clight->texture_index;
state.light_uniforms[index].flags |= l->mode << LIGHT_FLAGS_BLEND_SHIFT;
l->render_index_cache = index;
index++;
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);
}
}
//fill the list until rendering is possible.
Item *ci = p_item_list;
while (ci) {
@ -1205,7 +1403,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
bool backbuffer_copy = ci->copy_back_buffer; // || shader uses SCREEN_TEXTURE
if (!ci->next || backbuffer_copy || item_count == MAX_RENDER_ITEMS - 1) {
_render_items(p_to_render_target, item_count, p_modulate, p_canvas_transform);
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
//then reset
item_count = 0;
}
@ -1224,6 +1422,292 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite
}
}
RID RasterizerCanvasRD::light_create() {
CanvasLight canvas_light;
canvas_light.shadow.size = 0;
canvas_light.texture_index = -1;
return canvas_light_owner.make_rid(canvas_light);
}
void RasterizerCanvasRD::light_set_texture(RID p_rid, RID p_texture) {
CanvasLight *cl = canvas_light_owner.getornull(p_rid);
ERR_FAIL_COND(!cl);
if (cl->texture == p_texture) {
return;
}
cl->texture = p_texture;
//canvas state uniform set needs updating
if (state.canvas_state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state.canvas_state_uniform_set)) {
RD::get_singleton()->free(state.canvas_state_uniform_set);
}
}
void RasterizerCanvasRD::light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution) {
CanvasLight *cl = canvas_light_owner.getornull(p_rid);
ERR_FAIL_COND(!cl);
ERR_FAIL_COND(p_resolution < 64);
if (cl->shadow.texture.is_valid() == p_enable && p_resolution == cl->shadow.size) {
return;
}
if (cl->shadow.texture.is_valid()) {
RD::get_singleton()->free(cl->shadow.uniform_set);
cl->shadow.uniform_set = RID();
for (int i = 0; i < 4; i++) {
RD::get_singleton()->free(cl->shadow.render_fb[i]);
RD::get_singleton()->free(cl->shadow.render_textures[i]);
cl->shadow.render_fb[i] = RID();
cl->shadow.render_textures[i] = RID();
}
RD::get_singleton()->free(cl->shadow.fix_fb);
RD::get_singleton()->free(cl->shadow.texture);
cl->shadow.fix_fb = RID();
cl->shadow.texture = RID();
}
if (p_enable) {
{ //texture
RD::TextureFormat tf;
tf.type = RD::TEXTURE_TYPE_2D;
tf.width = p_resolution;
tf.height = 1;
tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
cl->shadow.texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
Vector<RID> fb_textures;
fb_textures.push_back(cl->shadow.texture);
cl->shadow.fix_fb = RD::get_singleton()->framebuffer_create(fb_textures);
}
{
RD::TextureFormat tf;
tf.type = RD::TEXTURE_TYPE_2D;
tf.width = p_resolution / 2;
tf.height = 1;
tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_X8_D24_UNORM_PACK32, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_X8_D24_UNORM_PACK32 : RD::DATA_FORMAT_D32_SFLOAT;
//chunks to write
cl->shadow.render_depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::Uniform tex_uniforms;
tex_uniforms.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
tex_uniforms.binding = 0;
for (int i = 0; i < 4; i++) {
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
cl->shadow.render_textures[i] = RD::get_singleton()->texture_create(tf, RD::TextureView());
Vector<RID> textures;
textures.push_back(cl->shadow.render_textures[i]);
textures.push_back(cl->shadow.render_depth);
cl->shadow.render_fb[i] = RD::get_singleton()->framebuffer_create(textures);
tex_uniforms.ids.push_back(default_samplers.samplers[VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST][VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED]);
tex_uniforms.ids.push_back(cl->shadow.render_textures[i]);
}
Vector<RD::Uniform> tex_uniforms_set;
tex_uniforms_set.push_back(tex_uniforms);
cl->shadow.uniform_set = RD::get_singleton()->uniform_set_create(tex_uniforms_set, shadow_render.shader_fix.version_get_shader(shadow_render.shader_fix_version, 0), 0);
}
}
//canvas state uniform set needs updating
if (state.canvas_state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state.canvas_state_uniform_set)) {
RD::get_singleton()->free(state.canvas_state_uniform_set);
}
}
void RasterizerCanvasRD::light_update_shadow(RID p_rid, 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.texture.is_null());
for (int i = 0; i < 4; i++) {
//make sure it remains orthogonal, makes easy to read angle later
//light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1));
Vector<Color> cc;
cc.push_back(Color(p_far, p_far, p_far, 1.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.render_fb[i], RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, cc);
CameraMatrix projection;
{
real_t fov = 90;
real_t nearp = p_near;
real_t farp = p_far;
real_t aspect = 1.0;
real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5));
real_t ymin = -ymax;
real_t xmin = ymin * aspect;
real_t xmax = ymax * aspect;
projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp);
}
Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * (i / 4.0))).xform(Vector3(0, 1, 0));
projection = projection * CameraMatrix(Transform().looking_at(cam_target, 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];
}
}
/*if (i == 0)
*p_xform_cache = projection;*/
LightOccluderInstance *instance = p_occluders;
while (instance) {
OccluderPolygon *co = occluder_polygon_owner.getornull(instance->polygon);
if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) {
instance = instance->next;
continue;
}
_update_transform_2d_to_mat4(p_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();
}
Vector<Color> cc;
cc.push_back(Color(p_far, p_far, p_far, 1.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.fix_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, cc);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.shader_fix_pipeline);
RD::get_singleton()->draw_list_bind_index_array(draw_list, primitive_arrays.index_array[3]);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, cl->shadow.uniform_set, 0);
RD::get_singleton()->draw_list_draw(draw_list, true);
RD::get_singleton()->draw_list_end();
}
RID RasterizerCanvasRD::occluder_polygon_create() {
OccluderPolygon occluder;
occluder.point_count = 0;
occluder.cull_mode = VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
return occluder_polygon_owner.make_rid(occluder);
}
void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, const PoolVector<Vector2> &p_lines) {
OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder);
ERR_FAIL_COND(!oc);
if (oc->point_count != p_lines.size() && oc->vertex_array.is_valid()) {
RD::get_singleton()->free(oc->vertex_array);
RD::get_singleton()->free(oc->vertex_buffer);
RD::get_singleton()->free(oc->index_array);
RD::get_singleton()->free(oc->index_buffer);
oc->vertex_array = RID();
oc->vertex_buffer = RID();
oc->index_array = RID();
oc->index_buffer = RID();
}
if (p_lines.size()) {
PoolVector<uint8_t> geometry;
PoolVector<uint8_t> indices;
int lc = p_lines.size();
geometry.resize(lc * 6 * sizeof(float));
indices.resize(lc * 3 * sizeof(uint16_t));
{
PoolVector<uint8_t>::Write vw = geometry.write();
float *vwptr = (float *)vw.ptr();
PoolVector<uint8_t>::Write iw = indices.write();
uint16_t *iwptr = (uint16_t *)iw.ptr();
PoolVector<Vector2>::Read lr = p_lines.read();
const int POLY_HEIGHT = 16384;
for (int i = 0; i < lc / 2; i++) {
vwptr[i * 12 + 0] = lr[i * 2 + 0].x;
vwptr[i * 12 + 1] = lr[i * 2 + 0].y;
vwptr[i * 12 + 2] = POLY_HEIGHT;
vwptr[i * 12 + 3] = lr[i * 2 + 1].x;
vwptr[i * 12 + 4] = lr[i * 2 + 1].y;
vwptr[i * 12 + 5] = POLY_HEIGHT;
vwptr[i * 12 + 6] = lr[i * 2 + 1].x;
vwptr[i * 12 + 7] = lr[i * 2 + 1].y;
vwptr[i * 12 + 8] = -POLY_HEIGHT;
vwptr[i * 12 + 9] = lr[i * 2 + 0].x;
vwptr[i * 12 + 10] = lr[i * 2 + 0].y;
vwptr[i * 12 + 11] = -POLY_HEIGHT;
iwptr[i * 6 + 0] = i * 4 + 0;
iwptr[i * 6 + 1] = i * 4 + 1;
iwptr[i * 6 + 2] = i * 4 + 2;
iwptr[i * 6 + 3] = i * 4 + 2;
iwptr[i * 6 + 4] = i * 4 + 3;
iwptr[i * 6 + 5] = i * 4 + 0;
}
}
//if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
if (oc->vertex_array.is_null()) {
//create from scratch
//vertices
oc->vertex_buffer = RD::get_singleton()->vertex_buffer_create(lc * 6 * sizeof(real_t), geometry);
Vector<RID> buffer;
buffer.push_back(oc->vertex_buffer);
oc->vertex_array = RD::get_singleton()->vertex_array_create(4 * lc / 2, shadow_render.vertex_format, buffer);
//indices
oc->index_buffer = RD::get_singleton()->index_buffer_create(3 * lc, RD::INDEX_BUFFER_FORMAT_UINT16, indices);
oc->index_array = RD::get_singleton()->index_array_create(oc->index_buffer, 0, 3 * lc);
} else {
//update existing
PoolVector<uint8_t>::Read vr = geometry.read();
RD::get_singleton()->buffer_update(oc->vertex_buffer, 0, geometry.size(), vr.ptr());
PoolVector<uint8_t>::Read ir = indices.read();
RD::get_singleton()->buffer_update(oc->index_buffer, 0, indices.size(), ir.ptr());
}
}
}
void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, VS::CanvasOccluderPolygonCullMode p_mode) {
OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder);
ERR_FAIL_COND(!oc);
oc->cull_mode = p_mode;
}
void RasterizerCanvasRD::update() {
_dispose_bindings();
}
@ -1422,6 +1906,59 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
shader.default_version_rd_shader = shader.canvas_shader.version_get_shader(shader.default_version, 0);
}
{ //shadow rendering
Vector<String> versions;
versions.push_back(String()); //no versions
shadow_render.shader.initialize(versions);
{
Vector<RD::AttachmentFormat> attachments;
RD::AttachmentFormat af_color;
af_color.format = RD::DATA_FORMAT_R32_SFLOAT;
af_color.usage_flags = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
attachments.push_back(af_color);
shadow_render.framebuffer_fix_format = RD::get_singleton()->framebuffer_format_create(attachments);
RD::AttachmentFormat af_depth;
af_depth.format = RD::DATA_FORMAT_D24_UNORM_S8_UINT;
af_depth.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_X8_D24_UNORM_PACK32, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_X8_D24_UNORM_PACK32 : RD::DATA_FORMAT_D32_SFLOAT;
af_depth.usage_flags = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
attachments.push_back(af_depth);
shadow_render.framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments);
}
//pipelines
Vector<RD::VertexDescription> vf;
RD::VertexDescription vd;
vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
vd.location = 0;
vd.offset = 0;
vd.stride = sizeof(float) * 3;
vf.push_back(vd);
shadow_render.vertex_format = RD::get_singleton()->vertex_format_create(vf);
shadow_render.shader_version = shadow_render.shader.version_create();
for (int i = 0; i < 3; i++) {
RD::PipelineRasterizationState rs;
rs.cull_mode = i == 0 ? RD::POLYGON_CULL_DISABLED : (i == 1 ? RD::POLYGON_CULL_FRONT : RD::POLYGON_CULL_BACK);
RD::PipelineDepthStencilState ds;
ds.enable_depth_write = true;
ds.enable_depth_test = true;
ds.depth_compare_operator = RD::COMPARE_OP_LESS;
shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, 0), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
}
shadow_render.shader_fix.initialize(versions);
shadow_render.shader_fix_version = shadow_render.shader_fix.version_create();
shadow_render.shader_fix_pipeline = RD::get_singleton()->render_pipeline_create(shadow_render.shader_fix.version_get_shader(shadow_render.shader_fix_version, 0), shadow_render.framebuffer_fix_format, RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
}
{ //bindings
bindings.id_generator = 0;
//generate for 0
@ -1429,6 +1966,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
{ //state allocate
state.canvas_state_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(State::Buffer));
state.lights_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(LightUniform) * MAX_RENDER_LIGHTS);
}
}
@ -1491,6 +2029,27 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
ERR_FAIL_COND(sizeof(PushConstant) != 128);
}
bool RasterizerCanvasRD::free(RID p_rid) {
if (canvas_light_owner.owns(p_rid)) {
CanvasLight *cl = canvas_light_owner.getornull(p_rid);
ERR_FAIL_COND_V(!cl, false);
light_set_use_shadow(p_rid, false, 64);
canvas_light_owner.free(p_rid);
//canvas state uniform set needs updating
if (state.canvas_state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state.canvas_state_uniform_set)) {
RD::get_singleton()->free(state.canvas_state_uniform_set);
}
} else if (occluder_polygon_owner.owns(p_rid)) {
occluder_polygon_set_shape_as_lines(p_rid, PoolVector<Vector2>());
occluder_polygon_owner.free(p_rid);
} else {
return false;
}
return true;
}
RasterizerCanvasRD::~RasterizerCanvasRD() {
//canvas state

View file

@ -5,6 +5,8 @@
#include "servers/visual/rasterizer/rasterizer_storage_rd.h"
#include "servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.h"
#include "servers/visual/rasterizer/shaders/canvas.glsl.gen.h"
#include "servers/visual/rasterizer/shaders/canvas_occlusion.glsl.gen.h"
#include "servers/visual/rasterizer/shaders/canvas_occlusion_fix.glsl.gen.h"
#include "servers/visual/rendering_device.h"
class RasterizerCanvasRD : public RasterizerCanvas {
@ -37,13 +39,37 @@ 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),
FLAGS_USE_PIXEL_SNAP = (1 << 14),
FLAGS_USE_SKELETON = (1 << 15),
FLAGS_NINEPATCH_H_MODE_SHIFT = 16,
FLAGS_NINEPATCH_V_MODE_SHIFT = 18
FLAGS_NINEPATCH_V_MODE_SHIFT = 18,
FLAGS_LIGHT_COUNT_SHIFT = 20,
FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 26),
FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27)
};
enum {
LIGHT_FLAGS_TEXTURE_MASK = 0xFFFF,
LIGHT_FLAGS_BLEND_SHIFT = 16,
LIGHT_FLAGS_BLEND_MASK = (3 << 16),
LIGHT_FLAGS_BLEND_MODE_ADD = (0 << 16),
LIGHT_FLAGS_BLEND_MODE_SUB = (1 << 16),
LIGHT_FLAGS_BLEND_MODE_MIX = (2 << 16),
LIGHT_FLAGS_BLEND_MODE_MASK = (3 << 16)
};
enum {
MAX_RENDER_ITEMS = 256 * 1024,
MAX_LIGHT_TEXTURES = 1024,
MAX_LIGHTS_PER_ITEM = 16,
MAX_RENDER_LIGHTS = 256
};
/****************/
@ -183,18 +209,66 @@ class RasterizerCanvasRD : public RasterizerCanvas {
/**** LIGHTING ****/
/******************/
enum {
LIGHT_GRID_WIDTH = 16,
LIGHT_GRID_HEIGHT = 16,
MAX_LIGHTS = 128
struct CanvasLight {
int32_t texture_index;
RID texture;
struct {
int size;
RID texture;
RID render_depth;
RID render_fb[4];
RID render_textures[4];
RID fix_fb;
RID uniform_set;
} shadow;
};
RID_Owner<CanvasLight> canvas_light_owner;
struct ShadowRenderPushConstant {
float projection[16];
float modelview[16];
};
struct OccluderPolygon {
VS::CanvasOccluderPolygonCullMode cull_mode;
int point_count;
RID vertex_buffer;
RID vertex_array;
RID index_buffer;
RID index_array;
};
struct LightUniform {
float matrix[8]; //light to texture coordinate matrix
float color[4];
float shadow_color[4];
float position[2];
uint32_t flags; //index to light texture
float height;
float shadow_softness;
float shadow_pixel_size;
float pad[2];
};
RID_Owner<OccluderPolygon> occluder_polygon_owner;
struct {
RID grid_texture;
RID grid_buffer;
PoolVector<uint8_t> grid_texture_data;
PoolVector<uint8_t> grid_buffer_data;
} lighting;
CanvasOcclusionShaderRD shader;
RID shader_version;
RID render_pipelines[3];
RD::VertexFormatID vertex_format;
RD::FramebufferFormatID framebuffer_format;
CanvasOcclusionFixShaderRD shader_fix;
RD::FramebufferFormatID framebuffer_fix_format;
RID shader_fix_version;
RID shader_fix_pipeline;
} shadow_render;
/***************/
/**** STATE ****/
@ -208,12 +282,16 @@ class RasterizerCanvasRD : public RasterizerCanvas {
struct Buffer {
float canvas_transform[16];
float screen_transform[16];
float canvas_normal_transform[16];
float canvas_modulate[4];
//uint32_t light_count;
//uint32_t pad[3];
};
LightUniform light_uniforms[MAX_RENDER_LIGHTS];
RID lights_uniform_buffer;
RID canvas_state_buffer;
//light buffer
RID canvas_state_light_buffer;
//uniform set for all the above
RID canvas_state_uniform_set;
@ -234,8 +312,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
};
//primitive
struct {
float points[6]; // vec2 points[4]
float uvs[6]; // vec2 points[4]
float points[6]; // vec2 points[3]
float uvs[6]; // vec2 points[3]
uint32_t colors[6]; // colors encoded as half
};
};
@ -248,21 +326,19 @@ class RasterizerCanvasRD : public RasterizerCanvas {
float skeleton_inverse[16];
};
enum {
MAX_RENDER_ITEMS = 256 * 1024
};
Item *items[MAX_RENDER_ITEMS];
Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list);
void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RenderingDevice::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse, Item *&current_clip);
void _render_items(RID p_to_render_target, int p_item_count, const Color &p_modulate, const Transform2D &p_transform);
Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list, uint32_t &flags);
void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RenderingDevice::TextureSamples p_samples, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights);
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights);
void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3);
_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
_FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3);
void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4);
void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4);
_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);
_FORCE_INLINE_ void _update_specular_shininess(const Color &p_transform, uint32_t *r_ss);
void _update_canvas_state_uniform_set();
@ -273,21 +349,23 @@ 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);
RID light_internal_create() { return RID(); }
void light_internal_update(RID p_rid, Light *p_light) {}
void light_internal_free(RID p_rid) {}
RID light_create();
void light_set_texture(RID p_rid, RID p_texture);
void light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution);
void light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders);
RID occluder_polygon_create();
void occluder_polygon_set_shape_as_lines(RID p_occluder, const PoolVector<Vector2> &p_lines);
void occluder_polygon_set_cull_mode(RID p_occluder, VS::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);
void canvas_debug_viewport_shadows(Light *p_lights_with_shadow){};
void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) {}
void reset_canvas() {}
void draw_window_margins(int *p_margins, RID *p_margin_textures) {}
void update();
bool free(RID p_rid);
RasterizerCanvasRD(RasterizerStorageRD *p_storage);
~RasterizerCanvasRD();
};

View file

@ -647,15 +647,6 @@ public:
Size2 render_target_get_size(RID p_render_target);
RID render_target_get_rd_framebuffer(RID p_render_target);
/* CANVAS SHADOW */
RID canvas_light_shadow_buffer_create(int p_width) { return RID(); }
/* LIGHT SHADOW MAPPING */
RID canvas_light_occluder_create() { return RID(); }
void canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) {}
VS::InstanceType get_base_type(RID p_rid) const {
if (mesh_owner.owns(p_rid)) {
return VS::INSTANCE_MESH;

View file

@ -4,3 +4,5 @@ Import('env')
if 'RD_GLSL' in env['BUILDERS']:
env.RD_GLSL('canvas.glsl');
env.RD_GLSL('canvas_occlusion.glsl');
env.RD_GLSL('canvas_occlusion_fix.glsl');

View file

@ -23,6 +23,7 @@ layout(location = 7) in vec4 bone_weights_attrib;
layout(location=0) out vec2 uv_interp;
layout(location=1) out vec4 color_interp;
layout(location=2) out vec2 vertex_interp;
#ifdef USE_NINEPATCH
@ -206,12 +207,12 @@ VERTEX_SHADER_CODE
#endif
#endif
vertex = (canvas_data.canvas_transform * vec4(vertex,0.0,1.0)).xy;
vertex_interp = vertex;
uv_interp = uv;
#if !defined(SKIP_TRANSFORM_USED)
gl_Position = (canvas_data.screen_transform * canvas_data.canvas_transform) * vec4(vertex,0.0,1.0);
#else
gl_Position = vec4(vertex,0.0,1.0);
#endif
gl_Position = canvas_data.screen_transform * vec4(vertex,0.0,1.0);
#ifdef USE_POINT_SIZE
gl_PointSize=point_size;
@ -232,6 +233,7 @@ VERSION_DEFINES
layout(location=0) in vec2 uv_interp;
layout(location=1) in vec4 color_interp;
layout(location=2) in vec2 vertex_interp;
#ifdef USE_NINEPATCH
@ -315,6 +317,7 @@ void main() {
vec4 color = color_interp;
vec2 uv = uv_interp;
vec2 vertex = vertex_interp;
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
@ -347,6 +350,8 @@ void main() {
#endif
uint light_count = (draw_data.flags>>FLAGS_LIGHT_COUNT_SHIFT)&0xF; //max 16 lights
vec3 normal;
@ -357,18 +362,33 @@ void main() {
bool normal_used = false;
#endif
#if 0
if (false /*normal_used || canvas_data.light_count > 0*/ ) {
normal.xy = texture(sampler2D(normal_texture,texture_sampler ), uv).xy * 2.0 - 1.0;
if (normal_used || (light_count > 0 && 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;
} else {
#endif
normal = vec3(0.0, 0.0, 1.0);
#if 0
}
vec4 specular_shininess;
#if defined(SPECULAR_SHININESS_USED)
bool specular_shininess_used = true;
#else
bool specular_shininess_used = false;
#endif
if (specular_shininess_used || (light_count > 0 && 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;
} else {
specular_shininess = vec4(1.0);
}
#if defined(SCREEN_UV_USED)
vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
#endif
@ -392,13 +412,104 @@ FRAGMENT_SHADER_CODE
#endif
}
#if 0
if (canvas_data.light_count > 0 ) {
//do lighting
if (normal_used) {
//convert by item transform
normal.xy = mat2(normalize(draw_data.world_x), normalize(draw_data.world_y)) * normal.xy;
//convert by canvas transform
normal = normalize((canvas_data.canvas_normal_transform * vec4(normal,0.0)).xyz);
}
#endif
//color.rgb *= color.a;
vec4 base_color=color;
if (bool(draw_data.flags&FLAGS_USING_LIGHT_MASK)) {
color=vec4(0.0); //inivisible by default due to using light mask
}
color*=canvas_data.canvas_modulation;
for(uint i=0;i<light_count;i++) {
uint light_base;
if (i<8) {
if (i<4) {
light_base=draw_data.lights[0];
} else {
light_base=draw_data.lights[1];
}
} else {
if (i<12) {
light_base=draw_data.lights[2];
} else {
light_base=draw_data.lights[3];
}
}
light_base>>=(i&3)*8;
light_base&=0xFF;
#define LIGHT_FLAGS_BLEND_MASK (3<<16)
#define LIGHT_FLAGS_BLEND_MODE_ADD (0<<16)
#define LIGHT_FLAGS_BLEND_MODE_SUB (1<<16)
#define LIGHT_FLAGS_BLEND_MODE_MIX (2<<16)
#define LIGHT_FLAGS_BLEND_MODE_MASK (3<<16)
vec2 tex_uv = (vec4(vertex,0.0,1.0) * mat4(light_array.data[light_base].matrix[0],light_array.data[light_base].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.
uint texture_idx = light_array.data[light_base].flags&LIGHT_FLAGS_TEXTURE_MASK;
vec4 light_color = texture(sampler2D(light_textures[texture_idx],texture_sampler),tex_uv);
vec4 light_base_color = light_array.data[light_base].color;
light_color.rgb*=light_base_color.rgb*light_base_color.a;
if (normal_used) {
vec3 light_pos = vec3(light_array.data[light_base].position,light_array.data[light_base].height);
vec3 pos = vec3(vertex,0.0);
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;
}
}
if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
//if outside the light texture, light color is zero
light_color.a = 0.0;
}
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;
}
}
frag_color = color;
}

View file

@ -0,0 +1,38 @@
/* clang-format off */
[vertex]
/* clang-format on */
#version 450
layout(location = 0) in highp vec3 vertex;
layout(push_constant, binding = 0, std430) uniform Constants {
mat4 modelview;
mat4 projection;
} constants;
layout(location = 0) out highp float depth;
void main() {
highp vec4 vtx = (constants.modelview * vec4(vertex, 1.0));
depth = length(vtx.xy);
gl_Position = constants.projection * vtx;
}
/* clang-format off */
[fragment]
/* clang-format on */
#version 450
layout(location = 0) in highp float depth;
layout(location = 0) out highp float distance_buf;
void main() {
distance_buf=depth;
}

View file

@ -0,0 +1,56 @@
/* clang-format off */
[vertex]
/* clang-format on */
#version 450
layout(location = 0) out highp float u;
void main() {
if (gl_VertexIndex==0) {
u=0.0;
gl_Position=vec4(-1.0,-1.0,0.0,1.0);
} else if (gl_VertexIndex==1) {
u=0.0;
gl_Position=vec4(-1.0,1.0,0.0,1.0);
} else if (gl_VertexIndex==2) {
u=1.0;
gl_Position=vec4(1.0,1.0,0.0,1.0);
} else {
u=1.0;
gl_Position=vec4(1.0,-1.0,0.0,1.0);
}
}
/* clang-format off */
[fragment]
/* clang-format on */
#version 450
#define PI 3.14159265359
layout(set=0, binding=0) uniform sampler2D textures[4];
layout(location = 0) in highp float u;
layout(location = 0) out highp float distance;
void main() {
//0-1 in the texture we are writing to represents a circle, 0-2PI)
//obtain the quarter circle from the source textures
highp float sub_angle = ((mod(u,0.25)/0.25)*2.0-1.0)*(PI/4.0);
highp float x=tan(sub_angle)*0.5+0.5;
float depth;
if (u<0.25) {
depth=texture(textures[0],vec2(x,0.0)).x;
} else if (u<0.50) {
depth=texture(textures[1],vec2(x,0.0)).x;
} else if (u<0.75) {
depth=texture(textures[2],vec2(x,0.0)).x;
} else {
depth=texture(textures[3],vec2(x,0.0)).x;
}
distance=depth;
}

View file

@ -1,8 +1,10 @@
/* SET0: Per draw primitive settings */
#define M_PI 3.14159265359
#define MAX_LIGHTS 128
#define MAX_LIGHT_TEXTURES 1024
#define MAX_RENDER_LIGHTS 256
#define FLAGS_INSTANCING_STRIDE_MASK 0xF
#define FLAGS_INSTANCING_ENABLED (1<<4)
@ -13,16 +15,19 @@
#define FLAGS_CLIP_RECT_UV (1 << 9)
#define FLAGS_TRANSPOSE_RECT (1 << 10)
#define FLAGS_USING_LIGHT_MASK (1 << 11)
#define FLAGS_NINEPACH_DRAW_CENTER (1 << 12)
#define FLAGS_USING_PARTICLES (1 << 13)
#define FLAGS_USE_PIXEL_SNAP (1 << 14)
#define FLAGS_NINEPATCH_H_MODE_SHIFT 16
#define FLAGS_NINEPATCH_V_MODE_SHIFT 18
#define FLAGS_LIGHT_COUNT_SHIFT 20
#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26)
#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27)
layout(push_constant, binding = 0, std430) uniform DrawData {
vec2 world_x;
vec2 world_y;
@ -77,26 +82,35 @@ layout(set = 2, binding = 1, std140) uniform SkeletonData {
layout(set = 3, binding = 0, std140) uniform CanvasData {
mat4 canvas_transform;
mat4 screen_transform;
mat4 canvas_normal_transform;
vec4 canvas_modulation;
//uint light_count;
} canvas_data;
#define LIGHT_FLAGS_TEXTURE_MASK 0xFFFF
#define LIGHT_FLAGS_BLEND_MASK (3<<16)
#define LIGHT_FLAGS_BLEND_MODE_ADD (0<<16)
#define LIGHT_FLAGS_BLEND_MODE_SUB (1<<16)
#define LIGHT_FLAGS_BLEND_MODE_MIX (2<<16)
#define LIGHT_FLAGS_BLEND_MODE_MASK (3<<16)
struct Light {
// light matrices
mat4 light_matrix;
mat4 light_local_matrix;
mat4 shadow_matrix;
vec4 light_color;
vec4 light_shadow_color;
vec2 light_pos;
float shadowpixel_size;
float shadow_gradient;
float light_height;
float light_outside_alpha;
float shadow_distance_mult;
mat2x4 matrix; //light to texture coordinate matrix
vec4 color;
vec4 shadow_color;
vec2 position;
uint flags; //index to light texture
float height;
float shadow_softness;
float shadow_pixel_size;
float pad0;
float pad1;
};
layout(set = 3, binding = 1, std140) uniform LightData {
Light lights[MAX_LIGHTS];
} light_data;
Light data[MAX_RENDER_LIGHTS];
} light_array;
layout(set = 3, binding = 2) uniform texture2D light_textures[MAX_LIGHTS];
layout(set = 3, binding = 2) uniform texture2D light_textures[MAX_LIGHT_TEXTURES];
layout(set = 3, binding = 3) uniform texture2D shadow_textures[MAX_LIGHT_TEXTURES];

View file

@ -554,7 +554,7 @@ public:
virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0;
virtual bool uniform_set_is_valid(RID p_uniform_set) = 0;
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, void *p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size,const void *p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls
/*************************/
/**** RENDER PIPELINE ****/

View file

@ -502,7 +502,7 @@ void VisualServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from,
line->points[0] = p_from;
line->points[1] = p_to;
}
for (int i = 0; i < line->point_count; i++) {
for (uint32_t i = 0; i < line->point_count; i++) {
line->colors[i] = p_color;
}
line->specular_shininess = Color(1, 1, 1, 1);
@ -1004,7 +1004,7 @@ void VisualServerCanvas::canvas_item_set_use_parent_material(RID p_item, bool p_
RID VisualServerCanvas::canvas_light_create() {
RasterizerCanvas::Light *clight = memnew(RasterizerCanvas::Light);
clight->light_internal = VSG::canvas_render->light_internal_create();
clight->light_internal = VSG::canvas_render->light_create();
return canvas_light_owner.make_rid(clight);
}
void VisualServerCanvas::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) {
@ -1057,6 +1057,7 @@ void VisualServerCanvas::canvas_light_set_texture(RID p_light, RID p_texture) {
ERR_FAIL_COND(!clight);
clight->texture = p_texture;
VSG::canvas_render->light_set_texture(clight->light_internal, p_texture);
}
void VisualServerCanvas::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) {
@ -1129,15 +1130,14 @@ void VisualServerCanvas::canvas_light_set_shadow_enabled(RID p_light, bool p_ena
RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
ERR_FAIL_COND(!clight);
if (clight->shadow_buffer.is_valid() == p_enabled)
if (clight->use_shadow == p_enabled) {
return;
if (p_enabled) {
clight->shadow_buffer = VSG::storage->canvas_light_shadow_buffer_create(clight->shadow_buffer_size);
} else {
VSG::storage->free(clight->shadow_buffer);
clight->shadow_buffer = RID();
}
clight->use_shadow = p_enabled;
VSG::canvas_render->light_set_use_shadow(clight->light_internal, clight->use_shadow, clight->shadow_buffer_size);
}
void VisualServerCanvas::canvas_light_set_shadow_buffer_size(RID p_light, int p_size) {
ERR_FAIL_COND(p_size < 32 || p_size > 16384);
@ -1151,10 +1151,7 @@ void VisualServerCanvas::canvas_light_set_shadow_buffer_size(RID p_light, int p_
clight->shadow_buffer_size = next_power_of_2(p_size);
if (clight->shadow_buffer.is_valid()) {
VSG::storage->free(clight->shadow_buffer);
clight->shadow_buffer = VSG::storage->canvas_light_shadow_buffer_create(clight->shadow_buffer_size);
}
VSG::canvas_render->light_set_use_shadow(clight->light_internal, clight->use_shadow, clight->shadow_buffer_size);
}
void VisualServerCanvas::canvas_light_set_shadow_gradient_length(RID p_light, float p_length) {
@ -1236,7 +1233,7 @@ void VisualServerCanvas::canvas_light_occluder_set_polygon(RID p_occluder, RID p
}
occluder->polygon = p_polygon;
occluder->polygon_buffer = RID();
occluder->occluder = RID();
if (occluder->polygon.is_valid()) {
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_polygon);
@ -1245,7 +1242,7 @@ void VisualServerCanvas::canvas_light_occluder_set_polygon(RID p_occluder, RID p
ERR_FAIL_COND(!occluder_poly);
} else {
occluder_poly->owners.insert(occluder);
occluder->polygon_buffer = occluder_poly->occluder;
occluder->occluder = occluder_poly->occluder;
occluder->aabb_cache = occluder_poly->aabb;
occluder->cull_cache = occluder_poly->cull_mode;
}
@ -1269,7 +1266,7 @@ void VisualServerCanvas::canvas_light_occluder_set_light_mask(RID p_occluder, in
RID VisualServerCanvas::canvas_occluder_polygon_create() {
LightOccluderPolygon *occluder_poly = memnew(LightOccluderPolygon);
occluder_poly->occluder = VSG::storage->canvas_light_occluder_create();
occluder_poly->occluder = VSG::canvas_render->occluder_polygon_create();
return canvas_light_occluder_polygon_owner.make_rid(occluder_poly);
}
void VisualServerCanvas::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const PoolVector<Vector2> &p_shape, bool p_closed) {
@ -1320,7 +1317,7 @@ void VisualServerCanvas::canvas_occluder_polygon_set_shape_as_lines(RID p_occlud
}
}
VSG::storage->canvas_light_occluder_set_polylines(occluder_poly->occluder, p_shape);
VSG::canvas_render->occluder_polygon_set_shape_as_lines(occluder_poly->occluder, p_shape);
for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) {
E->get()->aabb_cache = occluder_poly->aabb;
}
@ -1331,6 +1328,7 @@ void VisualServerCanvas::canvas_occluder_polygon_set_cull_mode(RID p_occluder_po
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon);
ERR_FAIL_COND(!occluder_poly);
occluder_poly->cull_mode = p_mode;
VSG::canvas_render->occluder_polygon_set_cull_mode(occluder_poly->occluder, p_mode);
for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) {
E->get()->cull_cache = p_mode;
}
@ -1422,10 +1420,7 @@ bool VisualServerCanvas::free(RID p_rid) {
canvas->lights.erase(canvas_light);
}
if (canvas_light->shadow_buffer.is_valid())
VSG::storage->free(canvas_light->shadow_buffer);
VSG::canvas_render->light_internal_free(canvas_light->light_internal);
VSG::canvas_render->free(canvas_light->light_internal);
canvas_light_owner.free(p_rid);
memdelete(canvas_light);
@ -1456,7 +1451,7 @@ bool VisualServerCanvas::free(RID p_rid) {
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_rid);
ERR_FAIL_COND_V(!occluder_poly, true);
VSG::storage->free(occluder_poly->occluder);
VSG::canvas_render->free(occluder_poly->occluder);
while (occluder_poly->owners.size()) {

View file

@ -149,13 +149,13 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
cl->filter_next_ptr = lights;
lights = cl;
cl->texture_cache = NULL;
// cl->texture_cache = NULL;
Transform2D scale;
scale.scale(cl->rect_cache.size);
scale.elements[2] = cl->rect_cache.position;
cl->light_shader_xform = (cl->xform_cache * scale).affine_inverse();
cl->light_shader_pos = cl->xform_cache[2];
if (cl->shadow_buffer.is_valid()) {
cl->light_shader_xform = cl->xform * scale;
//cl->light_shader_pos = cl->xform_cache[2];
if (cl->use_shadow) {
cl->shadows_next_ptr = lights_with_shadow;
if (lights_with_shadow == NULL) {
@ -174,7 +174,8 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
light_count++;
}
VSG::canvas_render->light_internal_update(cl->light_internal, cl);
//guess this is not needed, but keeping because it may be
//VSG::canvas_render->light_internal_update(cl->light_internal, cl);
}
}
@ -208,7 +209,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
RasterizerCanvas::Light *light = lights_with_shadow;
while (light) {
VSG::canvas_render->canvas_light_shadow_buffer_update(light->shadow_buffer, light->xform_cache.affine_inverse(), light->item_shadow_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders, &light->shadow_matrix_cache);
VSG::canvas_render->light_update_shadow(light->light_internal, light->xform_cache.affine_inverse(), light->item_shadow_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders);
light = light->shadows_next_ptr;
}