summaryrefslogtreecommitdiff
path: root/servers/rendering/rasterizer_rd
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/rasterizer_rd')
-rw-r--r--servers/rendering/rasterizer_rd/light_cluster_builder.cpp1
-rw-r--r--servers/rendering/rasterizer_rd/light_cluster_builder.h30
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp50
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h2
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp34
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.h16
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp299
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h30
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp102
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.h34
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp1239
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.h268
-rw-r--r--servers/rendering/rasterizer_rd/shader_compiler_rd.cpp149
-rw-r--r--servers/rendering/rasterizer_rd/shader_compiler_rd.h6
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl5
-rw-r--r--servers/rendering/rasterizer_rd/shaders/copy.glsl2
-rw-r--r--servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl44
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl206
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl48
-rw-r--r--servers/rendering/rasterizer_rd/shaders/sky.glsl10
20 files changed, 2423 insertions, 152 deletions
diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.cpp b/servers/rendering/rasterizer_rd/light_cluster_builder.cpp
index 943ef1c7fa..f75308a975 100644
--- a/servers/rendering/rasterizer_rd/light_cluster_builder.cpp
+++ b/servers/rendering/rasterizer_rd/light_cluster_builder.cpp
@@ -39,6 +39,7 @@ void LightClusterBuilder::begin(const Transform &p_view_transform, const CameraM
//reset counts
light_count = 0;
refprobe_count = 0;
+ decal_count = 0;
item_count = 0;
sort_id_count = 0;
}
diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.h b/servers/rendering/rasterizer_rd/light_cluster_builder.h
index 50a68e03cb..78288dc620 100644
--- a/servers/rendering/rasterizer_rd/light_cluster_builder.h
+++ b/servers/rendering/rasterizer_rd/light_cluster_builder.h
@@ -193,23 +193,25 @@ public:
refprobes = (OrientedBoxData *)memrealloc(refprobes, sizeof(OrientedBoxData) * refprobe_max);
}
+ Transform xform = view_xform * p_transform;
+
OrientedBoxData &rp = refprobes[refprobe_count];
- Vector3 origin = p_transform.origin;
+ Vector3 origin = xform.origin;
rp.position[0] = origin.x;
rp.position[1] = origin.y;
rp.position[2] = origin.z;
- Vector3 x_axis = p_transform.basis.get_axis(0) * p_half_extents.x;
+ Vector3 x_axis = xform.basis.get_axis(0) * p_half_extents.x;
rp.x_axis[0] = x_axis.x;
rp.x_axis[1] = x_axis.y;
rp.x_axis[2] = x_axis.z;
- Vector3 y_axis = p_transform.basis.get_axis(1) * p_half_extents.y;
+ Vector3 y_axis = xform.basis.get_axis(1) * p_half_extents.y;
rp.y_axis[0] = y_axis.x;
rp.y_axis[1] = y_axis.y;
rp.y_axis[2] = y_axis.z;
- Vector3 z_axis = p_transform.basis.get_axis(2) * p_half_extents.z;
+ Vector3 z_axis = xform.basis.get_axis(2) * p_half_extents.z;
rp.z_axis[0] = z_axis.x;
rp.z_axis[1] = z_axis.y;
rp.z_axis[2] = z_axis.z;
@@ -230,35 +232,37 @@ public:
refprobe_count++;
}
- _FORCE_INLINE_ void add_decal(const Transform &p_transform, const Vector2 &p_half_extents, float p_depth) {
+ _FORCE_INLINE_ void add_decal(const Transform &p_transform, const Vector3 &p_half_extents) {
if (unlikely(decal_count == decal_max)) {
decal_max = nearest_power_of_2_templated(decal_max + 1);
decals = (OrientedBoxData *)memrealloc(decals, sizeof(OrientedBoxData) * decal_max);
}
- OrientedBoxData &dc = decals[decal_count];
+ Transform xform = view_xform * p_transform;
- Vector3 z_axis = -p_transform.basis.get_axis(2) * p_depth * 0.5;
- dc.z_axis[0] = z_axis.x;
- dc.z_axis[1] = z_axis.y;
- dc.z_axis[2] = z_axis.z;
+ OrientedBoxData &dc = decals[decal_count];
- Vector3 origin = p_transform.origin - z_axis;
+ Vector3 origin = xform.origin;
dc.position[0] = origin.x;
dc.position[1] = origin.y;
dc.position[2] = origin.z;
- Vector3 x_axis = p_transform.basis.get_axis(0) * p_half_extents.x;
+ Vector3 x_axis = xform.basis.get_axis(0) * p_half_extents.x;
dc.x_axis[0] = x_axis.x;
dc.x_axis[1] = x_axis.y;
dc.x_axis[2] = x_axis.z;
- Vector3 y_axis = p_transform.basis.get_axis(1) * p_half_extents.y;
+ Vector3 y_axis = xform.basis.get_axis(1) * p_half_extents.y;
dc.y_axis[0] = y_axis.x;
dc.y_axis[1] = y_axis.y;
dc.y_axis[2] = y_axis.z;
+ Vector3 z_axis = xform.basis.get_axis(2) * p_half_extents.z;
+ dc.z_axis[0] = z_axis.x;
+ dc.z_axis[1] = z_axis.y;
+ dc.z_axis[2] = z_axis.z;
+
AABB aabb;
aabb.position = origin + x_axis + y_axis + z_axis;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
index ba4f4c4acb..956bf54d01 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
@@ -273,7 +273,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
Vector<uint8_t> polygon_buffer;
polygon_buffer.resize(buffer_size * sizeof(float));
- Vector<RD::VertexDescription> descriptions;
+ Vector<RD::VertexAttribute> descriptions;
descriptions.resize(4);
Vector<RID> buffers;
buffers.resize(4);
@@ -284,7 +284,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
uint32_t *uptr = (uint32_t *)r;
uint32_t base_offset = 0;
{ //vertices
- RD::VertexDescription vd;
+ RD::VertexAttribute vd;
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
vd.offset = base_offset * sizeof(float);
vd.location = RS::ARRAY_VERTEX;
@@ -304,7 +304,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
//colors
if ((uint32_t)p_colors.size() == vertex_count || p_colors.size() == 1) {
- RD::VertexDescription vd;
+ RD::VertexAttribute vd;
vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
vd.offset = base_offset * sizeof(float);
vd.location = RS::ARRAY_COLOR;
@@ -332,7 +332,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
}
base_offset += 4;
} else {
- RD::VertexDescription vd;
+ RD::VertexAttribute vd;
vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
vd.offset = 0;
vd.location = RS::ARRAY_COLOR;
@@ -344,7 +344,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
//uvs
if ((uint32_t)p_uvs.size() == vertex_count) {
- RD::VertexDescription vd;
+ RD::VertexAttribute vd;
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
vd.offset = base_offset * sizeof(float);
vd.location = RS::ARRAY_TEX_UV;
@@ -360,7 +360,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
}
base_offset += 2;
} else {
- RD::VertexDescription vd;
+ RD::VertexAttribute vd;
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
vd.offset = 0;
vd.location = RS::ARRAY_TEX_UV;
@@ -372,7 +372,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
//bones
if ((uint32_t)p_indices.size() == vertex_count * 4 && (uint32_t)p_weights.size() == vertex_count * 4) {
- RD::VertexDescription vd;
+ RD::VertexAttribute vd;
vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
vd.offset = base_offset * sizeof(float);
vd.location = RS::ARRAY_BONES;
@@ -401,7 +401,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int
base_offset += 4;
} else {
- RD::VertexDescription vd;
+ RD::VertexAttribute vd;
vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
vd.offset = 0;
vd.location = RS::ARRAY_BONES;
@@ -618,6 +618,14 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_
}
}
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 7;
+ u.ids.push_back(storage->global_variables_get_storage_buffer());
+ uniforms.push_back(u);
+ }
+
//validate and update lighs if they are being used
if (light_count > 0) {
@@ -2012,6 +2020,9 @@ void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
if (E->get().texture_order >= 0) {
order[E->get().texture_order + 100000] = E->key();
} else {
@@ -2027,6 +2038,23 @@ void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_
}
}
+void RasterizerCanvasRD::ShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const {
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RasterizerStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E->get());
+ p.info.name = E->key(); //supply name
+ p.index = E->get().instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p_param_list->push_back(p);
+ }
+}
+
bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
@@ -2366,6 +2394,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
actions.default_repeat = ShaderLanguage::REPEAT_DISABLE;
actions.base_varying_index = 4;
+ actions.global_buffer_array_variable = "global_variables.data";
+
shader.compiler.initialize(actions);
}
@@ -2393,8 +2423,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
}
//pipelines
- Vector<RD::VertexDescription> vf;
- RD::VertexDescription vd;
+ Vector<RD::VertexAttribute> vf;
+ RD::VertexAttribute vd;
vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
vd.location = 0;
vd.offset = 0;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
index 83b431eaf6..4d47b3e13b 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
@@ -185,6 +185,8 @@ class RasterizerCanvasRD : public RasterizerCanvas {
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const;
+
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
index 3da16ccb79..d469dd97ca 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
@@ -204,7 +204,29 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1
return uniform_set;
}
-void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance) {
+void RasterizerEffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) {
+
+ zeromem(&copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
+
+ copy_to_fb.push_constant.use_section = true;
+ copy_to_fb.push_constant.section[0] = p_uv_rect.position.x;
+ copy_to_fb.push_constant.section[1] = p_uv_rect.position.y;
+ copy_to_fb.push_constant.section[2] = p_uv_rect.size.x;
+ copy_to_fb.push_constant.section[3] = p_uv_rect.size.y;
+
+ if (p_flip_y) {
+ copy_to_fb.push_constant.flip_y = true;
+ }
+
+ RD::DrawListID draw_list = p_draw_list;
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[p_panorama ? COPY_TO_FB_COPY_PANORAMA_TO_DP : COPY_TO_FB_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+}
+
+void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero) {
zeromem(&copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
if (p_flip_y) {
@@ -213,9 +235,12 @@ void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_fr
if (p_force_luminance) {
copy_to_fb.push_constant.force_luminance = true;
}
+ if (p_alpha_to_zero) {
+ copy_to_fb.push_constant.alpha_to_zero = true;
+ }
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[COPY_TO_FB_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
RD::get_singleton()->draw_list_set_push_constant(draw_list, &copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
@@ -1213,6 +1238,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
{
Vector<String> copy_modes;
copy_modes.push_back("\n");
+ copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n");
copy_to_fb.shader.initialize(copy_modes);
@@ -1220,7 +1246,9 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
//use additive
- copy_to_fb.pipeline.setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ for (int i = 0; i < COPY_TO_FB_MAX; i++) {
+ copy_to_fb.pipelines[i].setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ }
}
{
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
index aec381d193..531591442b 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
@@ -111,21 +111,30 @@ class RasterizerEffectsRD {
} copy;
+ enum CopyToFBMode {
+ COPY_TO_FB_COPY,
+ COPY_TO_FB_COPY_PANORAMA_TO_DP,
+ COPY_TO_FB_MAX,
+
+ };
+
struct CopyToFbPushConstant {
float section[4];
float pixel_size[2];
uint32_t flip_y;
uint32_t use_section;
+
uint32_t force_luminance;
- uint32_t pad[3];
+ uint32_t alpha_to_zero;
+ uint32_t pad[2];
};
struct CopyToFb {
CopyToFbPushConstant push_constant;
CopyToFbShaderRD shader;
RID shader_version;
- RenderPipelineVertexFormatCacheRD pipeline;
+ RenderPipelineVertexFormatCacheRD pipelines[COPY_TO_FB_MAX];
} copy_to_fb;
@@ -553,10 +562,11 @@ class RasterizerEffectsRD {
RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2);
public:
- void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false);
+ void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false);
void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false);
void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);
void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far);
+ void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false);
void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false);
void gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
index 8ed58c0ef5..b3cf40f166 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
@@ -52,6 +52,21 @@ static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_arra
p_array[15] = 1;
}
+static _FORCE_INLINE_ void store_basis_3x4(const Basis &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.elements[0][0];
+ p_array[1] = p_mtx.elements[1][0];
+ p_array[2] = p_mtx.elements[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.elements[0][1];
+ p_array[5] = p_mtx.elements[1][1];
+ p_array[6] = p_mtx.elements[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.elements[0][2];
+ p_array[9] = p_mtx.elements[1][2];
+ p_array[10] = p_mtx.elements[2][2];
+ p_array[11] = 0;
+}
+
static _FORCE_INLINE_ void store_transform_3x3(const Transform &p_mtx, float *p_array) {
p_array[0] = p_mtx.basis.elements[0][0];
p_array[1] = p_mtx.basis.elements[1][0];
@@ -363,6 +378,10 @@ void RasterizerSceneHighEndRD::ShaderData::get_param_list(List<PropertyInfo> *p_
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+
if (E->get().texture_order >= 0) {
order[E->get().texture_order + 100000] = E->key();
} else {
@@ -378,6 +397,23 @@ void RasterizerSceneHighEndRD::ShaderData::get_param_list(List<PropertyInfo> *p_
}
}
+void RasterizerSceneHighEndRD::ShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const {
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RasterizerStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E->get());
+ p.info.name = E->key(); //supply name
+ p.index = E->get().instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p_param_list->push_back(p);
+ }
+}
+
bool RasterizerSceneHighEndRD::ShaderData::is_param_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
@@ -813,6 +849,7 @@ void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements,
store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform);
id.flags = 0;
id.mask = e->instance->layer_mask;
+ id.instance_uniforms_ofs = e->instance->instance_allocated_shader_parameters_offset >= 0 ? e->instance->instance_allocated_shader_parameters_offset : 0;
if (e->instance->base_type == RS::INSTANCE_MULTIMESH) {
id.flags |= INSTANCE_DATA_FLAG_MULTIMESH;
@@ -1149,7 +1186,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const Camer
} else if (is_environment(p_environment)) {
RS::EnvironmentBG env_bg = environment_get_background(p_environment);
- RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_light_ambient_source(p_environment);
+ RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_environment);
float bg_energy = environment_get_bg_energy(p_environment);
scene_state.ubo.ambient_light_color_energy[3] = bg_energy;
@@ -1169,7 +1206,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const Camer
scene_state.ubo.use_ambient_cubemap = false;
} else {
- float energy = environment_get_ambient_light_ambient_energy(p_environment);
+ float energy = environment_get_ambient_light_energy(p_environment);
Color color = environment_get_ambient_light_color(p_environment);
color = color.to_linear();
scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
@@ -1511,7 +1548,7 @@ void RasterizerSceneHighEndRD::_setup_reflections(RID *p_reflection_probe_cull_r
Color ambient_linear = storage->reflection_probe_get_interior_ambient(base_probe).to_linear();
if (is_environment(p_environment)) {
Color env_ambient_color = environment_get_ambient_light_color(p_environment).to_linear();
- float env_ambient_energy = environment_get_ambient_light_ambient_energy(p_environment);
+ float env_ambient_energy = environment_get_ambient_light_energy(p_environment);
ambient_linear = env_ambient_color;
ambient_linear.r *= env_ambient_energy;
ambient_linear.g *= env_ambient_energy;
@@ -1769,6 +1806,7 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
sky_light_data.color[2] = light_data.color[2];
sky_light_data.enabled = true;
+ sky_light_data.size = light_data.softshadow_angle;
sky_scene_state.directional_light_count++;
}
@@ -1826,6 +1864,30 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
light_data.atlas_rect[2] = 0;
light_data.atlas_rect[3] = 0;
+ RID projector = storage->light_get_projector(base);
+
+ if (projector.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(projector);
+
+ if (type == RS::LIGHT_SPOT) {
+
+ light_data.projector_rect[0] = rect.position.x;
+ light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped
+ light_data.projector_rect[2] = rect.size.width;
+ light_data.projector_rect[3] = -rect.size.height;
+ } else {
+ light_data.projector_rect[0] = rect.position.x;
+ light_data.projector_rect[1] = rect.position.y;
+ light_data.projector_rect[2] = rect.size.width;
+ light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half
+ }
+ } else {
+ light_data.projector_rect[0] = 0;
+ light_data.projector_rect[1] = 0;
+ light_data.projector_rect[2] = 0;
+ light_data.projector_rect[3] = 0;
+ }
+
if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) {
// fill in the shadow information
@@ -1877,17 +1939,11 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
} else if (type == RS::LIGHT_SPOT) {
- //used for clamping in this light type
- light_data.atlas_rect[2] += light_data.atlas_rect[0];
- light_data.atlas_rect[3] += light_data.atlas_rect[1];
-
Transform modelview = (p_camera_inverse_transform * light_transform).inverse();
CameraMatrix bias;
bias.set_light_bias();
- CameraMatrix rectm;
- rectm.set_light_atlas_rect(rect);
- CameraMatrix shadow_mtx = rectm * bias * light_instance_get_shadow_camera(li, 0) * modelview;
+ CameraMatrix shadow_mtx = bias * light_instance_get_shadow_camera(li, 0) * modelview;
store_camera(shadow_mtx, light_data.shadow_matrix);
if (size > 0.0) {
@@ -1925,7 +1981,140 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
}
}
-void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color) {
+void RasterizerSceneHighEndRD::_setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform) {
+
+ Transform uv_xform;
+ uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0));
+ uv_xform.origin = Vector3(-1.0, 0.0, -1.0);
+
+ p_decal_count = MIN((uint32_t)p_decal_count, scene_state.max_decals);
+ int idx = 0;
+ for (int i = 0; i < p_decal_count; i++) {
+
+ RID di = p_decal_instances[i];
+ RID decal = decal_instance_get_base(di);
+
+ Transform xform = decal_instance_get_transform(di);
+
+ float fade = 1.0;
+
+ if (storage->decal_is_distance_fade_enabled(decal)) {
+ real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
+ float fade_begin = storage->decal_get_distance_fade_begin(decal);
+ float fade_length = storage->decal_get_distance_fade_length(decal);
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ continue; // do not use this decal, its invisible
+ }
+
+ fade = 1.0 - (distance - fade_begin) / fade_length;
+ }
+ }
+
+ DecalData &dd = scene_state.decals[idx];
+
+ Vector3 decal_extents = storage->decal_get_extents(decal);
+
+ Transform scale_xform;
+ scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z));
+ Transform to_decal_xform = (p_camera_inverse_xform * decal_instance_get_transform(di) * scale_xform * uv_xform).affine_inverse();
+ store_transform(to_decal_xform, dd.xform);
+
+ Vector3 normal = xform.basis.get_axis(Vector3::AXIS_Y).normalized();
+ normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine
+
+ dd.normal[0] = normal.x;
+ dd.normal[1] = normal.y;
+ dd.normal[2] = normal.z;
+ dd.normal_fade = storage->decal_get_normal_fade(decal);
+
+ RID albedo_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ALBEDO);
+ RID emission_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_EMISSION);
+ if (albedo_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(albedo_tex);
+ dd.albedo_rect[0] = rect.position.x;
+ dd.albedo_rect[1] = rect.position.y;
+ dd.albedo_rect[2] = rect.size.x;
+ dd.albedo_rect[3] = rect.size.y;
+ } else {
+
+ if (!emission_tex.is_valid()) {
+ continue; //no albedo, no emission, no decal.
+ }
+ dd.albedo_rect[0] = 0;
+ dd.albedo_rect[1] = 0;
+ dd.albedo_rect[2] = 0;
+ dd.albedo_rect[3] = 0;
+ }
+
+ RID normal_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_NORMAL);
+
+ if (normal_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(normal_tex);
+ dd.normal_rect[0] = rect.position.x;
+ dd.normal_rect[1] = rect.position.y;
+ dd.normal_rect[2] = rect.size.x;
+ dd.normal_rect[3] = rect.size.y;
+
+ Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized();
+ store_basis_3x4(normal_xform, dd.normal_xform);
+ } else {
+ dd.normal_rect[0] = 0;
+ dd.normal_rect[1] = 0;
+ dd.normal_rect[2] = 0;
+ dd.normal_rect[3] = 0;
+ }
+
+ RID orm_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ORM);
+ if (orm_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(orm_tex);
+ dd.orm_rect[0] = rect.position.x;
+ dd.orm_rect[1] = rect.position.y;
+ dd.orm_rect[2] = rect.size.x;
+ dd.orm_rect[3] = rect.size.y;
+ } else {
+ dd.orm_rect[0] = 0;
+ dd.orm_rect[1] = 0;
+ dd.orm_rect[2] = 0;
+ dd.orm_rect[3] = 0;
+ }
+
+ if (emission_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(emission_tex);
+ dd.emission_rect[0] = rect.position.x;
+ dd.emission_rect[1] = rect.position.y;
+ dd.emission_rect[2] = rect.size.x;
+ dd.emission_rect[3] = rect.size.y;
+ } else {
+ dd.emission_rect[0] = 0;
+ dd.emission_rect[1] = 0;
+ dd.emission_rect[2] = 0;
+ dd.emission_rect[3] = 0;
+ }
+
+ Color modulate = storage->decal_get_modulate(decal);
+ dd.modulate[0] = modulate.r;
+ dd.modulate[1] = modulate.g;
+ dd.modulate[2] = modulate.b;
+ dd.modulate[3] = modulate.a * fade;
+ dd.emission_energy = storage->decal_get_emission_energy(decal) * fade;
+ dd.albedo_mix = storage->decal_get_albedo_mix(decal);
+ dd.mask = storage->decal_get_cull_mask(decal);
+ dd.upper_fade = storage->decal_get_upper_fade(decal);
+ dd.lower_fade = storage->decal_get_lower_fade(decal);
+
+ cluster_builder.add_decal(xform, decal_extents);
+
+ idx++;
+ }
+
+ if (idx > 0) {
+ RD::get_singleton()->buffer_update(scene_state.decal_buffer, 0, sizeof(DecalData) * idx, scene_state.decals, true);
+ }
+}
+
+void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color) {
RenderBufferDataHighEnd *render_buffer = nullptr;
if (p_render_buffer.is_valid()) {
@@ -2042,6 +2231,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
cluster_builder.begin(p_cam_transform.affine_inverse(), p_cam_projection); //prepare cluster
_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows);
+ _setup_decals(p_decal_cull_result, p_decal_cull_count, p_cam_transform.affine_inverse());
_setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment);
_setup_gi_probes(p_gi_probe_cull_result, p_gi_probe_cull_count, p_cam_transform);
_setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false);
@@ -2086,23 +2276,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
clear_color.b *= bg_energy;
} break;
case RS::ENV_BG_SKY: {
- RID sky = environment_get_sky(p_environment);
- if (sky.is_valid()) {
-
- RENDER_TIMESTAMP("Setup Sky");
- CameraMatrix projection = p_cam_projection;
- if (p_reflection_probe.is_valid()) {
- CameraMatrix correction;
- correction.set_depth_correction(true);
- projection = correction * p_cam_projection;
- }
-
- _setup_sky(p_environment, p_cam_transform.origin, screen_size);
- _update_sky(p_environment, projection, p_cam_transform);
- radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET);
-
- draw_sky = true;
- }
+ draw_sky = true;
} break;
case RS::ENV_BG_CANVAS: {
keep_color = true;
@@ -2116,6 +2290,27 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
default: {
}
}
+ // setup sky if used for ambient, reflections, or background
+ if (draw_sky || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+ RID sky = environment_get_sky(p_environment);
+ if (sky.is_valid()) {
+
+ RENDER_TIMESTAMP("Setup Sky");
+ CameraMatrix projection = p_cam_projection;
+ if (p_reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ projection = correction * p_cam_projection;
+ }
+
+ _setup_sky(p_environment, p_cam_transform.origin, screen_size);
+ _update_sky(p_environment, projection, p_cam_transform);
+ radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET);
+ } else {
+ // do not try to draw sky if invalid
+ draw_sky = false;
+ }
+ }
} else {
clear_color = p_default_bg_color;
@@ -2483,17 +2678,40 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
-
{
RD::Uniform u;
u.binding = 10;
u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(cluster_builder.get_cluster_texture());
+ RID decal_atlas = storage->decal_atlas_get_texture();
+ u.ids.push_back(decal_atlas);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 11;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID decal_atlas = storage->decal_atlas_get_texture_srgb();
+ u.ids.push_back(decal_atlas);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 12;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(scene_state.decal_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 13;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(cluster_builder.get_cluster_texture());
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 14;
u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(cluster_builder.get_cluster_indices_buffer());
uniforms.push_back(u);
@@ -2501,7 +2719,7 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() {
{
RD::Uniform u;
- u.binding = 12;
+ u.binding = 15;
u.type = RD::UNIFORM_TYPE_TEXTURE;
if (directional_shadow_get_texture().is_valid()) {
u.ids.push_back(directional_shadow_get_texture());
@@ -2511,6 +2729,14 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 16;
+ u.ids.push_back(storage->global_variables_get_storage_buffer());
+ uniforms.push_back(u);
+ }
+
render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, SCENE_UNIFORM_SET);
}
}
@@ -2722,6 +2948,13 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
defines += "\n#define MAX_GI_PROBES " + itos(scene_state.max_gi_probes) + "\n";
}
+ { //decals
+ scene_state.max_decals = MIN(1024 * 1024, uniform_max_size) / sizeof(DecalData); //1mb of decals
+ uint32_t decal_buffer_size = scene_state.max_decals * sizeof(DecalData);
+ scene_state.decals = memnew_arr(DecalData, scene_state.max_decals);
+ scene_state.decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size);
+ }
+
Vector<String> shader_versions;
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n");
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
@@ -2880,6 +3113,8 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+ actions.global_buffer_array_variable = "global_variables.data";
+ actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs";
shader.compiler.initialize(actions);
}
@@ -3001,10 +3236,12 @@ RasterizerSceneHighEndRD::~RasterizerSceneHighEndRD() {
RD::get_singleton()->free(scene_state.directional_light_buffer);
RD::get_singleton()->free(scene_state.light_buffer);
RD::get_singleton()->free(scene_state.reflection_buffer);
+ RD::get_singleton()->free(scene_state.decal_buffer);
memdelete_arr(scene_state.instances);
memdelete_arr(scene_state.gi_probes);
memdelete_arr(scene_state.directional_lights);
memdelete_arr(scene_state.lights);
memdelete_arr(scene_state.reflections);
+ memdelete_arr(scene_state.decals);
}
}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
index 6ae4720306..a48e2e2259 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
@@ -152,6 +152,8 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const;
+
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
@@ -279,6 +281,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
float soft_shadow_scale;
uint32_t mask;
uint32_t pad[2];
+ float projector_rect[4];
};
struct DirectionalLightData {
@@ -328,6 +331,24 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
uint32_t pad[1];
};
+ struct DecalData {
+ float xform[16];
+ float inv_extents[3];
+ float albedo_mix;
+ float albedo_rect[4];
+ float normal_rect[4];
+ float orm_rect[4];
+ float emission_rect[4];
+ float modulate[4];
+ float emission_energy;
+ uint32_t mask;
+ float upper_fade;
+ float lower_fade;
+ float normal_xform[12];
+ float normal[3];
+ float normal_fade;
+ };
+
enum {
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
@@ -342,7 +363,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
float transform[16];
float normal_transform[16];
uint32_t flags;
- uint32_t instance_ofs; //instance_offset in instancing/skeleton buffer
+ uint32_t instance_uniforms_ofs; //instance_offset in instancing/skeleton buffer
uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap)
uint32_t mask;
};
@@ -413,6 +434,10 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
RID gi_probe_buffer;
uint32_t max_gi_probe_probes_per_instance;
+ DecalData *decals;
+ uint32_t max_decals;
+ RID decal_buffer;
+
LightData *lights;
uint32_t max_lights;
RID light_buffer;
@@ -604,6 +629,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
void _setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false);
void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows);
+ void _setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform);
void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment);
void _setup_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform);
@@ -615,7 +641,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_no_gi);
protected:
- virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color);
+ virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color);
virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake);
virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
index 2ec09b2528..8877de87ac 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -655,7 +655,8 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, const Vector3 &p_position,
sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
- sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled) {
+ sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
+ sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
light_data_dirty = true;
break;
}
@@ -851,18 +852,22 @@ void RasterizerSceneRD::SkyShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light;
actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light;
actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light;
actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light;
actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light;
actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light;
actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light;
actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light;
actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light;
actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light;
actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light;
actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light;
actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light;
actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light;
actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light;
actions.uniforms = &uniforms;
@@ -926,6 +931,10 @@ void RasterizerSceneRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_para
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
if (E->get().texture_order >= 0) {
order[E->get().texture_order + 100000] = E->key();
} else {
@@ -941,6 +950,23 @@ void RasterizerSceneRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_para
}
}
+void RasterizerSceneRD::SkyShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const {
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RasterizerStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E->get());
+ p.info.name = E->key(); //supply name
+ p.index = E->get().instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p_param_list->push_back(p);
+ }
+}
+
bool RasterizerSceneRD::SkyShaderData::is_param_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
@@ -1179,12 +1205,12 @@ Color RasterizerSceneRD::environment_get_ambient_light_color(RID p_env) const {
ERR_FAIL_COND_V(!env, Color());
return env->ambient_light;
}
-RS::EnvironmentAmbientSource RasterizerSceneRD::environment_get_ambient_light_ambient_source(RID p_env) const {
+RS::EnvironmentAmbientSource RasterizerSceneRD::environment_get_ambient_source(RID p_env) const {
Environent *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG);
return env->ambient_source;
}
-float RasterizerSceneRD::environment_get_ambient_light_ambient_energy(RID p_env) const {
+float RasterizerSceneRD::environment_get_ambient_light_energy(RID p_env) const {
Environent *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->ambient_light_energy;
@@ -2116,6 +2142,21 @@ RasterizerSceneRD::ShadowMap *RasterizerSceneRD::_get_shadow_map(const Size2i &p
return &shadow_maps[p_size];
}
+
+//////////////////////////
+
+RID RasterizerSceneRD::decal_instance_create(RID p_decal) {
+ DecalInstance di;
+ di.decal = p_decal;
+ return decal_instance_owner.make_rid(di);
+}
+
+void RasterizerSceneRD::decal_instance_set_transform(RID p_decal, const Transform &p_transform) {
+ DecalInstance *di = decal_instance_owner.getornull(p_decal);
+ ERR_FAIL_COND(!di);
+ di->transform = p_transform;
+}
+
/////////////////////////////////
RID RasterizerSceneRD::gi_probe_instance_create(RID p_base) {
@@ -3493,6 +3534,16 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s
}
}
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_DECAL_ATLAS) {
+ RID decal_atlas = storage->decal_atlas_get_texture();
+
+ if (decal_atlas.is_valid()) {
+ Size2 rtsize = storage->render_target_get_size(rb->render_target);
+
+ effects->copy_to_fb_rect(decal_atlas, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, false, true);
+ }
+ }
+
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE) {
if (rb->luminance.current.is_valid()) {
Size2 rtsize = storage->render_target_get_size(rb->render_target);
@@ -3686,7 +3737,7 @@ RasterizerSceneRD::RenderBufferData *RasterizerSceneRD::render_buffers_get_data(
return rb->data;
}
-void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
+void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
Color clear_color;
if (p_render_buffers.is_valid()) {
@@ -3697,7 +3748,7 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca
clear_color = storage->get_default_clear_color();
}
- _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color);
+ _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_decal_cull_result, p_decal_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color);
if (p_render_buffers.is_valid()) {
RENDER_TIMESTAMP("Tonemap");
@@ -3917,6 +3968,8 @@ bool RasterizerSceneRD::free(RID p_rid) {
//ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid);
reflection_probe_release_atlas_index(p_rid);
reflection_probe_instance_owner.free(p_rid);
+ } else if (decal_instance_owner.owns(p_rid)) {
+ decal_instance_owner.free(p_rid);
} else if (gi_probe_instance_owner.owns(p_rid)) {
GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_rid);
if (gi_probe->texture.is_valid()) {
@@ -4160,21 +4213,25 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color";
actions.renames["RADIANCE"] = "radiance";
actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled";
- actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction";
- actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].energy";
- actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color";
+ actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz";
+ actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w";
+ actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz";
+ actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w";
actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled";
- actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction";
- actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].energy";
- actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color";
+ actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz";
+ actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w";
+ actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz";
+ actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w";
actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled";
- actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction";
- actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].energy";
- actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color";
+ actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz";
+ actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w";
+ actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz";
+ actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w";
actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled";
- actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction";
- actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].energy";
- actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color";
+ actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz";
+ actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w";
+ actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz";
+ actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w";
actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS";
actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS";
actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS";
@@ -4190,6 +4247,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+ actions.global_buffer_array_variable = "global_variables.data";
sky_shader.compiler.initialize(actions);
}
@@ -4197,7 +4255,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
{
// default material and shader for sky shader
sky_shader.default_shader = storage->shader_create();
- storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void fragment() { COLOR = mix(vec3(0.3), vec3(0.2, 0.4, 0.9), smoothstep(0.0, 0.05, EYEDIR.y)); } \n");
+ storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void fragment() { COLOR = vec3(0.0); } \n");
sky_shader.default_material = storage->material_create();
storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader);
@@ -4227,6 +4285,14 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
uniforms.push_back(u);
}
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(storage->global_variables_get_storage_buffer());
+ uniforms.push_back(u);
+ }
+
sky_scene_state.sampler_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_SAMPLERS);
}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
index 859b654214..a511838e16 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
@@ -56,7 +56,9 @@ protected:
float direction[3];
float energy;
float color[3];
+ float size;
uint32_t enabled;
+ uint32_t pad[3];
};
struct SkySceneState {
@@ -78,7 +80,7 @@ protected:
};
virtual RenderBufferData *_create_render_buffer_data() = 0;
- virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color) = 0;
+ virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color) = 0;
virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake) = 0;
virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;
@@ -189,6 +191,7 @@ private:
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
@@ -324,6 +327,16 @@ private:
mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
+ /* REFLECTION PROBE INSTANCE */
+
+ struct DecalInstance {
+
+ RID decal;
+ Transform transform;
+ };
+
+ mutable RID_Owner<DecalInstance> decal_instance_owner;
+
/* GIPROBE INSTANCE */
struct GIProbeLight {
@@ -856,8 +869,8 @@ public:
float environment_get_bg_energy(RID p_env) const;
int environment_get_canvas_max_layer(RID p_env) const;
Color environment_get_ambient_light_color(RID p_env) const;
- RS::EnvironmentAmbientSource environment_get_ambient_light_ambient_source(RID p_env) const;
- float environment_get_ambient_light_ambient_energy(RID p_env) const;
+ RS::EnvironmentAmbientSource environment_get_ambient_source(RID p_env) const;
+ float environment_get_ambient_light_energy(RID p_env) const;
float environment_get_ambient_sky_contribution(RID p_env) const;
RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const;
Color environment_get_ao_color(RID p_env) const;
@@ -1103,6 +1116,19 @@ public:
return rpi->atlas_index;
}
+ virtual RID decal_instance_create(RID p_decal);
+ virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform);
+
+ _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal) const {
+ DecalInstance *decal = decal_instance_owner.getornull(p_decal);
+ return decal->decal;
+ }
+
+ _FORCE_INLINE_ Transform decal_instance_get_transform(RID p_decal) const {
+ DecalInstance *decal = decal_instance_owner.getornull(p_decal);
+ return decal->transform;
+ }
+
RID gi_probe_instance_create(RID p_base);
void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
bool gi_probe_needs_update(RID p_probe) const;
@@ -1168,7 +1194,7 @@ public:
RID render_buffers_get_ao_texture(RID p_render_buffers);
RID render_buffers_get_back_buffer_texture(RID p_render_buffers);
- void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
+ void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
index 6ac1f7c95e..0689429014 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -31,6 +31,7 @@
#include "rasterizer_storage_rd.h"
#include "core/engine.h"
+#include "core/io/resource_loader.h"
#include "core/project_settings.h"
#include "servers/rendering/shader_language.h"
@@ -809,6 +810,12 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) {
}
//delete last, so proxies can be updated
texture_owner.free(p_by_texture);
+
+ if (decal_atlas.textures.has(p_texture)) {
+ //belongs to decal atlas..
+
+ decal_atlas.dirty = true; //mark it dirty since it was most likely modified
+ }
}
void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) {
Texture *tex = texture_owner.getornull(p_texture);
@@ -915,6 +922,7 @@ void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) {
Material *material = E->get();
if (shader->data) {
material->data = material_data_request_func[new_type](shader->data);
+ material->data->self = material->self;
material->data->set_next_pass(material->next_pass);
material->data->set_render_priority(material->priority);
}
@@ -1015,8 +1023,8 @@ void RasterizerStorageRD::_material_queue_update(Material *material, bool p_unif
material->update_next = material_update_list;
material_update_list = material;
material->update_requested = true;
- material->uniform_dirty = p_uniform;
- material->texture_dirty = p_texture;
+ material->uniform_dirty = material->uniform_dirty || p_uniform;
+ material->texture_dirty = material->texture_dirty || p_texture;
}
void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) {
@@ -1053,6 +1061,7 @@ void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) {
ERR_FAIL_COND(shader->data == nullptr);
material->data = material_data_request_func[shader->type](shader->data);
+ material->data->self = p_material;
material->data->set_next_pass(material->next_pass);
material->data->set_render_priority(material->priority);
//updating happens later
@@ -1138,6 +1147,19 @@ bool RasterizerStorageRD::material_casts_shadows(RID p_material) {
return true; //by default everything casts shadows
}
+void RasterizerStorageRD::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) {
+
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+ if (material->shader && material->shader->data) {
+ material->shader->data->get_instance_param_list(r_parameters);
+
+ if (material->next_pass.is_valid()) {
+ material_get_instance_shader_parameters(material->next_pass, r_parameters);
+ }
+ }
+}
+
void RasterizerStorageRD::material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) {
Material *material = material_owner.getornull(p_material);
ERR_FAIL_COND(!material);
@@ -1625,11 +1647,36 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
+ bool uses_global_buffer = false;
+
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) {
if (E->get().order < 0)
continue; // texture, does not go here
+ if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue; //instance uniforms don't appear in the bufferr
+ }
+
+ if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
+ //this is a global variable, get the index to it
+ RasterizerStorageRD *rs = base_singleton;
+
+ GlobalVariables::Variable *gv = rs->global_variables.variables.getptr(E->key());
+ uint32_t index = 0;
+ if (gv) {
+ index = gv->buffer_index;
+ } else {
+ WARN_PRINT("Shader uses global uniform '" + E->key() + "', but it was removed at some point. Material will not display correctly.");
+ }
+
+ uint32_t offset = p_uniform_offsets[E->get().order];
+ uint32_t *intptr = (uint32_t *)&p_buffer[offset];
+ *intptr = index;
+ uses_global_buffer = true;
+ continue;
+ }
+
//regular uniform
uint32_t offset = p_uniform_offsets[E->get().order];
#ifdef DEBUG_ENABLED
@@ -1658,6 +1705,38 @@ void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringNa
}
}
}
+
+ if (uses_global_buffer != (global_buffer_E != nullptr)) {
+ RasterizerStorageRD *rs = base_singleton;
+ if (uses_global_buffer) {
+ global_buffer_E = rs->global_variables.materials_using_buffer.push_back(self);
+ } else {
+ rs->global_variables.materials_using_buffer.erase(global_buffer_E);
+ global_buffer_E = nullptr;
+ }
+ }
+}
+
+RasterizerStorageRD::MaterialData::~MaterialData() {
+ if (global_buffer_E) {
+ //unregister global buffers
+ RasterizerStorageRD *rs = base_singleton;
+ rs->global_variables.materials_using_buffer.erase(global_buffer_E);
+ }
+
+ if (global_texture_E) {
+ //unregister global textures
+ RasterizerStorageRD *rs = base_singleton;
+
+ for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) {
+ GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E->key());
+ if (v) {
+ v->texture_materials.erase(self);
+ }
+ }
+ //unregister material from those using global textures
+ rs->global_variables.materials_using_texture.erase(global_texture_E);
+ }
}
void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) {
@@ -1669,22 +1748,57 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va
Texture *normal_detect_texture = nullptr;
#endif
+ bool uses_global_textures = false;
+ global_textures_pass++;
+
for (int i = 0; i < p_texture_uniforms.size(); i++) {
const StringName &uniform_name = p_texture_uniforms[i].name;
RID texture;
- const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
- if (V) {
- texture = V->get();
- }
+ if (p_texture_uniforms[i].global) {
- if (!texture.is_valid()) {
- const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
- if (W) {
+ RasterizerStorageRD *rs = base_singleton;
- texture = W->get();
+ uses_global_textures = true;
+
+ GlobalVariables::Variable *v = rs->global_variables.variables.getptr(uniform_name);
+ if (v) {
+ if (v->buffer_index >= 0) {
+ WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it changed type and is no longer a texture!.");
+
+ } else {
+
+ Map<StringName, uint64_t>::Element *E = used_global_textures.find(uniform_name);
+ if (!E) {
+ E = used_global_textures.insert(uniform_name, global_textures_pass);
+ v->texture_materials.insert(self);
+ } else {
+ E->get() = global_textures_pass;
+ }
+
+ texture = v->override.get_type() != Variant::NIL ? v->override : v->value;
+ }
+
+ } else {
+ WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly.");
+ }
+ } else {
+ if (!texture.is_valid()) {
+
+ const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
+ if (V) {
+ texture = V->get();
+ }
+ }
+
+ if (!texture.is_valid()) {
+ const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
+ if (W) {
+
+ texture = W->get();
+ }
}
}
@@ -1747,6 +1861,36 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va
roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
}
#endif
+ {
+ //for textures no longer used, unregister them
+ List<Map<StringName, uint64_t>::Element *> to_delete;
+ RasterizerStorageRD *rs = base_singleton;
+
+ for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) {
+ if (E->get() != global_textures_pass) {
+ to_delete.push_back(E);
+
+ GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E->key());
+ if (v) {
+ v->texture_materials.erase(self);
+ }
+ }
+ }
+
+ while (to_delete.front()) {
+ used_global_textures.erase(to_delete.front()->get());
+ to_delete.pop_front();
+ }
+ //handle registering/unregistering global textures
+ if (uses_global_textures != (global_texture_E != nullptr)) {
+ if (uses_global_textures) {
+ global_texture_E = rs->global_variables.materials_using_texture.push_back(self);
+ } else {
+ rs->global_variables.materials_using_texture.erase(global_texture_E);
+ global_texture_E = nullptr;
+ }
+ }
+ }
}
void RasterizerStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) {
@@ -2197,14 +2341,14 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su
Mesh::Surface::Version &v = s->versions[version];
- Vector<RD::VertexDescription> attributes;
+ Vector<RD::VertexAttribute> attributes;
Vector<RID> buffers;
uint32_t stride = 0;
for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
- RD::VertexDescription vd;
+ RD::VertexAttribute vd;
RID buffer;
vd.location = i;
@@ -3174,7 +3318,19 @@ void RasterizerStorageRD::light_set_projector(RID p_light, RID p_texture) {
Light *light = light_owner.getornull(p_light);
ERR_FAIL_COND(!light);
+ if (light->projector == p_texture) {
+ return;
+ }
+
+ if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) {
+ texture_remove_from_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
+ }
+
light->projector = p_texture;
+
+ if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) {
+ texture_add_to_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
+ }
}
void RasterizerStorageRD::light_set_negative(RID p_light, bool p_enable) {
@@ -3553,6 +3709,94 @@ float RasterizerStorageRD::reflection_probe_get_interior_ambient_probe_contribut
return reflection_probe->interior_ambient_probe_contrib;
}
+RID RasterizerStorageRD::decal_create() {
+ return decal_owner.make_rid(Decal());
+}
+
+void RasterizerStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->extents = p_extents;
+ decal->instance_dependency.instance_notify_changed(true, false);
+}
+void RasterizerStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ ERR_FAIL_INDEX(p_type, RS::DECAL_TEXTURE_MAX);
+
+ if (decal->textures[p_type] == p_texture) {
+ return;
+ }
+
+ ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture));
+
+ if (decal->textures[p_type].is_valid() && texture_owner.owns(decal->textures[p_type])) {
+ texture_remove_from_decal_atlas(decal->textures[p_type]);
+ }
+
+ decal->textures[p_type] = p_texture;
+
+ if (decal->textures[p_type].is_valid()) {
+ texture_add_to_decal_atlas(decal->textures[p_type]);
+ }
+
+ decal->instance_dependency.instance_notify_changed(false, true);
+}
+void RasterizerStorageRD::decal_set_emission_energy(RID p_decal, float p_energy) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->emission_energy = p_energy;
+}
+
+void RasterizerStorageRD::decal_set_albedo_mix(RID p_decal, float p_mix) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->albedo_mix = p_mix;
+}
+
+void RasterizerStorageRD::decal_set_modulate(RID p_decal, const Color &p_modulate) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->modulate = p_modulate;
+}
+void RasterizerStorageRD::decal_set_cull_mask(RID p_decal, uint32_t p_layers) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->cull_mask = p_layers;
+ decal->instance_dependency.instance_notify_changed(true, false);
+}
+
+void RasterizerStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) {
+
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->distance_fade = p_enabled;
+ decal->distance_fade_begin = p_begin;
+ decal->distance_fade_length = p_length;
+}
+
+void RasterizerStorageRD::decal_set_fade(RID p_decal, float p_above, float p_below) {
+
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->upper_fade = p_above;
+ decal->lower_fade = p_below;
+}
+
+void RasterizerStorageRD::decal_set_normal_fade(RID p_decal, float p_fade) {
+
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->normal_fade = p_fade;
+}
+
+AABB RasterizerStorageRD::decal_get_aabb(RID p_decal) const {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND_V(!decal, AABB());
+
+ return AABB(-decal->extents, decal->extents * 2.0);
+}
+
RID RasterizerStorageRD::gi_probe_create() {
return gi_probe_owner.make_rid(GIProbe());
@@ -4243,6 +4487,9 @@ void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::In
} else if (reflection_probe_owner.owns(p_base)) {
ReflectionProbe *rp = reflection_probe_owner.getornull(p_base);
p_instance->update_dependency(&rp->instance_dependency);
+ } else if (decal_owner.owns(p_base)) {
+ Decal *decal = decal_owner.getornull(p_base);
+ p_instance->update_dependency(&decal->instance_dependency);
} else if (gi_probe_owner.owns(p_base)) {
GIProbe *gip = gi_probe_owner.getornull(p_base);
p_instance->update_dependency(&gip->instance_dependency);
@@ -4271,6 +4518,9 @@ RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const {
if (reflection_probe_owner.owns(p_rid)) {
return RS::INSTANCE_REFLECTION_PROBE;
}
+ if (decal_owner.owns(p_rid)) {
+ return RS::INSTANCE_DECAL;
+ }
if (gi_probe_owner.owns(p_rid)) {
return RS::INSTANCE_GI_PROBE;
}
@@ -4280,10 +4530,924 @@ RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const {
return RS::INSTANCE_NONE;
}
+
+void RasterizerStorageRD::texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp) {
+ if (!decal_atlas.textures.has(p_texture)) {
+ DecalAtlas::Texture t;
+ t.users = 1;
+ t.panorama_to_dp_users = p_panorama_to_dp ? 1 : 0;
+ decal_atlas.textures[p_texture] = t;
+ decal_atlas.dirty = true;
+ } else {
+ DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
+ t->users++;
+ if (p_panorama_to_dp) {
+ t->panorama_to_dp_users++;
+ }
+ }
+}
+
+void RasterizerStorageRD::texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp) {
+ DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
+ ERR_FAIL_COND(!t);
+ t->users--;
+ if (p_panorama_to_dp) {
+ ERR_FAIL_COND(t->panorama_to_dp_users == 0);
+ t->panorama_to_dp_users--;
+ }
+ if (t->users == 0) {
+ decal_atlas.textures.erase(p_texture);
+ //do not mark it dirty, there is no need to since it remains working
+ }
+}
+
+RID RasterizerStorageRD::decal_atlas_get_texture() const {
+ return decal_atlas.texture;
+}
+
+RID RasterizerStorageRD::decal_atlas_get_texture_srgb() const {
+ return decal_atlas.texture;
+}
+
+void RasterizerStorageRD::_update_decal_atlas() {
+ if (!decal_atlas.dirty) {
+ return; //nothing to do
+ }
+
+ decal_atlas.dirty = false;
+
+ if (decal_atlas.texture.is_valid()) {
+ RD::get_singleton()->free(decal_atlas.texture);
+ decal_atlas.texture = RID();
+ decal_atlas.texture_srgb = RID();
+ decal_atlas.texture_mipmaps.clear();
+ }
+
+ int border = 1 << decal_atlas.mipmaps;
+
+ if (decal_atlas.textures.size()) {
+ //generate atlas
+ Vector<DecalAtlas::SortItem> itemsv;
+ itemsv.resize(decal_atlas.textures.size());
+ int base_size = 8;
+ const RID *K = NULL;
+
+ int idx = 0;
+ while ((K = decal_atlas.textures.next(K))) {
+ DecalAtlas::SortItem &si = itemsv.write[idx];
+
+ Texture *src_tex = texture_owner.getornull(*K);
+
+ si.size.width = (src_tex->width / border) + 1;
+ si.size.height = (src_tex->height / border) + 1;
+ si.pixel_size = Size2i(src_tex->width, src_tex->height);
+
+ if (base_size < si.size.width) {
+ base_size = nearest_power_of_2_templated(si.size.width);
+ }
+
+ si.texture = *K;
+ idx++;
+ }
+
+ //sort items by size
+ itemsv.sort();
+
+ //attempt to create atlas
+ int item_count = itemsv.size();
+ DecalAtlas::SortItem *items = itemsv.ptrw();
+
+ int atlas_height = 0;
+
+ while (true) {
+
+ Vector<int> v_offsetsv;
+ v_offsetsv.resize(base_size);
+
+ int *v_offsets = v_offsetsv.ptrw();
+ zeromem(v_offsets, sizeof(int) * base_size);
+
+ int max_height = 0;
+
+ for (int i = 0; i < item_count; i++) {
+ //best fit
+ DecalAtlas::SortItem &si = items[i];
+ int best_idx = -1;
+ int best_height = 0x7FFFFFFF;
+ for (int j = 0; j <= base_size - si.size.width; j++) {
+ int height = 0;
+ for (int k = 0; k < si.size.width; k++) {
+ int h = v_offsets[k + j];
+ if (h > height) {
+ height = h;
+ if (height > best_height) {
+ break; //already bad
+ }
+ }
+ }
+
+ if (height < best_height) {
+ best_height = height;
+ best_idx = j;
+ }
+ }
+
+ //update
+ for (int k = 0; k < si.size.width; k++) {
+ v_offsets[k + best_idx] = best_height + si.size.height;
+ }
+
+ si.pos.x = best_idx;
+ si.pos.y = best_height;
+
+ if (si.pos.y + si.size.height > max_height) {
+ max_height = si.pos.y + si.size.height;
+ }
+ }
+
+ if (max_height <= base_size * 2) {
+ atlas_height = max_height;
+ break; //good ratio, break;
+ }
+
+ base_size *= 2;
+ }
+
+ decal_atlas.size.width = base_size * border;
+ decal_atlas.size.height = nearest_power_of_2_templated(atlas_height * border);
+
+ for (int i = 0; i < item_count; i++) {
+ DecalAtlas::Texture *t = decal_atlas.textures.getptr(items[i].texture);
+ t->uv_rect.position = items[i].pos * border + Vector2i(border / 2, border / 2);
+ t->uv_rect.size = items[i].pixel_size;
+ //print_line("blitrect: " + t->uv_rect);
+ t->uv_rect.position /= Size2(decal_atlas.size);
+ t->uv_rect.size /= Size2(decal_atlas.size);
+ }
+ } else {
+
+ //use border as size, so it at least has enough mipmaps
+ decal_atlas.size.width = border;
+ decal_atlas.size.height = border;
+ }
+
+ //blit textures
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tformat.width = decal_atlas.size.width;
+ tformat.height = decal_atlas.size.height;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ tformat.type = RD::TEXTURE_TYPE_2D;
+ tformat.mipmaps = decal_atlas.mipmaps;
+ tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM);
+ tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB);
+
+ decal_atlas.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+
+ {
+ //create the framebuffer
+
+ Size2i s = decal_atlas.size;
+
+ for (int i = 0; i < decal_atlas.mipmaps; i++) {
+ DecalAtlas::MipMap mm;
+ mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), decal_atlas.texture, 0, i);
+ Vector<RID> fb;
+ fb.push_back(mm.texture);
+ mm.fb = RD::get_singleton()->framebuffer_create(fb);
+ mm.size = s;
+ decal_atlas.texture_mipmaps.push_back(mm);
+
+ s.width = MAX(1, s.width >> 1);
+ s.height = MAX(1, s.height >> 1);
+ }
+ {
+ //create the SRGB variant
+ RD::TextureView rd_view;
+ rd_view.format_override = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ decal_atlas.texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, decal_atlas.texture);
+ }
+ }
+
+ RID prev_texture;
+ for (int i = 0; i < decal_atlas.texture_mipmaps.size(); i++) {
+ const DecalAtlas::MipMap &mm = decal_atlas.texture_mipmaps[i];
+
+ Color clear_color(0, 0, 0, 0);
+
+ if (decal_atlas.textures.size()) {
+
+ if (i == 0) {
+ Vector<Color> cc;
+ cc.push_back(clear_color);
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(mm.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, cc);
+
+ const RID *K = NULL;
+ while ((K = decal_atlas.textures.next(K))) {
+ DecalAtlas::Texture *t = decal_atlas.textures.getptr(*K);
+ Texture *src_tex = texture_owner.getornull(*K);
+ effects.copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0);
+ }
+
+ RD::get_singleton()->draw_list_end();
+
+ prev_texture = mm.texture;
+ } else {
+
+ effects.copy_to_fb_rect(prev_texture, mm.fb, Rect2i(Point2i(), mm.size));
+ prev_texture = mm.texture;
+ }
+ } else {
+ RD::get_singleton()->texture_clear(mm.texture, clear_color, 0, 1, 0, 1, false);
+ }
+ }
+}
+
+int32_t RasterizerStorageRD::_global_variable_allocate(uint32_t p_elements) {
+
+ int32_t idx = 0;
+ while (idx + p_elements <= global_variables.buffer_size) {
+ if (global_variables.buffer_usage[idx].elements == 0) {
+ bool valid = true;
+ for (uint32_t i = 1; i < p_elements; i++) {
+ if (global_variables.buffer_usage[idx + i].elements > 0) {
+ valid = false;
+ idx += i + global_variables.buffer_usage[idx + i].elements;
+ break;
+ }
+ }
+
+ if (!valid) {
+ continue; //if not valid, idx is in new position
+ }
+
+ return idx;
+ } else {
+ idx += global_variables.buffer_usage[idx].elements;
+ }
+ }
+
+ return -1;
+}
+
+void RasterizerStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS::GlobalVariableType p_type, const Variant &p_value) {
+
+ switch (p_type) {
+ case RS::GLOBAL_VAR_TYPE_BOOL: {
+
+ GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
+ bool b = p_value;
+ bv.x = b ? 1.0 : 0.0;
+ bv.y = 0.0;
+ bv.z = 0.0;
+ bv.w = 0.0;
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_BVEC2: {
+ GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
+ uint32_t bvec = p_value;
+ bv.x = (bvec & 1) ? 1.0 : 0.0;
+ bv.y = (bvec & 2) ? 1.0 : 0.0;
+ bv.z = 0.0;
+ bv.w = 0.0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_BVEC3: {
+ GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
+ uint32_t bvec = p_value;
+ bv.x = (bvec & 1) ? 1.0 : 0.0;
+ bv.y = (bvec & 2) ? 1.0 : 0.0;
+ bv.z = (bvec & 4) ? 1.0 : 0.0;
+ bv.w = 0.0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_BVEC4: {
+ GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
+ uint32_t bvec = p_value;
+ bv.x = (bvec & 1) ? 1.0 : 0.0;
+ bv.y = (bvec & 2) ? 1.0 : 0.0;
+ bv.z = (bvec & 4) ? 1.0 : 0.0;
+ bv.w = (bvec & 8) ? 1.0 : 0.0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_INT: {
+ GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index];
+ int32_t v = p_value;
+ bv.x = v;
+ bv.y = 0;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_IVEC2: {
+ GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index];
+ Vector2i v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_IVEC3: {
+ GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index];
+ Vector3i v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = v.z;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_IVEC4: {
+ GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index];
+ Vector<int32_t> v = p_value;
+ bv.x = v.size() >= 1 ? v[0] : 0;
+ bv.y = v.size() >= 2 ? v[1] : 0;
+ bv.z = v.size() >= 3 ? v[2] : 0;
+ bv.w = v.size() >= 4 ? v[3] : 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_RECT2I: {
+ GlobalVariables::ValueInt &bv = *(GlobalVariables::ValueInt *)&global_variables.buffer_values[p_index];
+ Rect2i v = p_value;
+ bv.x = v.position.x;
+ bv.y = v.position.y;
+ bv.z = v.size.x;
+ bv.w = v.size.y;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UINT: {
+ GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index];
+ uint32_t v = p_value;
+ bv.x = v;
+ bv.y = 0;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UVEC2: {
+ GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index];
+ Vector2i v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UVEC3: {
+ GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index];
+ Vector3i v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = v.z;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UVEC4: {
+ GlobalVariables::ValueUInt &bv = *(GlobalVariables::ValueUInt *)&global_variables.buffer_values[p_index];
+ Vector<int32_t> v = p_value;
+ bv.x = v.size() >= 1 ? v[0] : 0;
+ bv.y = v.size() >= 2 ? v[1] : 0;
+ bv.z = v.size() >= 3 ? v[2] : 0;
+ bv.w = v.size() >= 4 ? v[3] : 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_FLOAT: {
+ GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
+ float v = p_value;
+ bv.x = v;
+ bv.y = 0;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_VEC2: {
+ GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
+ Vector2 v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_VEC3: {
+ GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
+ Vector3 v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = v.z;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_VEC4: {
+ GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
+ Plane v = p_value;
+ bv.x = v.normal.x;
+ bv.y = v.normal.y;
+ bv.z = v.normal.z;
+ bv.w = v.d;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_COLOR: {
+ GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
+ Color v = p_value;
+ bv.x = v.r;
+ bv.y = v.g;
+ bv.z = v.b;
+ bv.w = v.a;
+
+ GlobalVariables::Value &bv_linear = global_variables.buffer_values[p_index + 1];
+ v = v.to_linear();
+ bv_linear.x = v.r;
+ bv_linear.y = v.g;
+ bv_linear.z = v.b;
+ bv_linear.w = v.a;
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_RECT2: {
+ GlobalVariables::Value &bv = global_variables.buffer_values[p_index];
+ Rect2 v = p_value;
+ bv.x = v.position.x;
+ bv.y = v.position.y;
+ bv.z = v.size.x;
+ bv.w = v.size.y;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_MAT2: {
+ GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
+ Vector<float> m2 = p_value;
+ if (m2.size() < 4) {
+ m2.resize(4);
+ }
+ bv[0].x = m2[0];
+ bv[0].y = m2[1];
+ bv[0].z = 0;
+ bv[0].w = 0;
+
+ bv[1].x = m2[2];
+ bv[1].y = m2[3];
+ bv[1].z = 0;
+ bv[1].w = 0;
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_MAT3: {
+
+ GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
+ Basis v = p_value;
+ bv[0].x = v.elements[0][0];
+ bv[0].y = v.elements[1][0];
+ bv[0].z = v.elements[2][0];
+ bv[0].w = 0;
+
+ bv[1].x = v.elements[0][1];
+ bv[1].y = v.elements[1][1];
+ bv[1].z = v.elements[2][1];
+ bv[1].w = 0;
+
+ bv[2].x = v.elements[0][2];
+ bv[2].y = v.elements[1][2];
+ bv[2].z = v.elements[2][2];
+ bv[2].w = 0;
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_MAT4: {
+
+ GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
+
+ Vector<float> m2 = p_value;
+ if (m2.size() < 16) {
+ m2.resize(16);
+ }
+
+ bv[0].x = m2[0];
+ bv[0].y = m2[1];
+ bv[0].z = m2[2];
+ bv[0].w = m2[3];
+
+ bv[1].x = m2[4];
+ bv[1].y = m2[5];
+ bv[1].z = m2[6];
+ bv[1].w = m2[7];
+
+ bv[2].x = m2[8];
+ bv[2].y = m2[9];
+ bv[2].z = m2[10];
+ bv[2].w = m2[11];
+
+ bv[3].x = m2[12];
+ bv[3].y = m2[13];
+ bv[3].z = m2[14];
+ bv[3].w = m2[15];
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {
+
+ GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
+ Transform2D v = p_value;
+ bv[0].x = v.elements[0][0];
+ bv[0].y = v.elements[0][1];
+ bv[0].z = 0;
+ bv[0].w = 0;
+
+ bv[1].x = v.elements[1][0];
+ bv[1].y = v.elements[1][1];
+ bv[1].z = 0;
+ bv[1].w = 0;
+
+ bv[2].x = v.elements[2][0];
+ bv[2].y = v.elements[2][1];
+ bv[2].z = 1;
+ bv[2].w = 0;
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
+
+ GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
+ Transform v = p_value;
+ bv[0].x = v.basis.elements[0][0];
+ bv[0].y = v.basis.elements[1][0];
+ bv[0].z = v.basis.elements[2][0];
+ bv[0].w = 0;
+
+ bv[1].x = v.basis.elements[0][1];
+ bv[1].y = v.basis.elements[1][1];
+ bv[1].z = v.basis.elements[2][1];
+ bv[1].w = 0;
+
+ bv[2].x = v.basis.elements[0][2];
+ bv[2].y = v.basis.elements[1][2];
+ bv[2].z = v.basis.elements[2][2];
+ bv[2].w = 0;
+
+ bv[2].x = v.origin.x;
+ bv[2].y = v.origin.y;
+ bv[2].z = v.origin.z;
+ bv[2].w = 1;
+
+ } break;
+ default: {
+ ERR_FAIL();
+ }
+ }
+}
+
+void RasterizerStorageRD::_global_variable_mark_buffer_dirty(int32_t p_index, int32_t p_elements) {
+
+ int32_t prev_chunk = -1;
+
+ for (int32_t i = 0; i < p_elements; i++) {
+ int32_t chunk = (p_index + i) / GlobalVariables::BUFFER_DIRTY_REGION_SIZE;
+ if (chunk != prev_chunk) {
+ if (!global_variables.buffer_dirty_regions[chunk]) {
+ global_variables.buffer_dirty_regions[chunk] = true;
+ global_variables.buffer_dirty_region_count++;
+ }
+ }
+
+ prev_chunk = chunk;
+ }
+}
+
+void RasterizerStorageRD::global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) {
+
+ ERR_FAIL_COND(global_variables.variables.has(p_name));
+ GlobalVariables::Variable gv;
+ gv.type = p_type;
+ gv.value = p_value;
+ gv.buffer_index = -1;
+
+ if (p_type >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
+ //is texture
+ global_variables.must_update_texture_materials = true; //normally ther are no
+ } else {
+
+ gv.buffer_elements = 1;
+ if (p_type == RS::GLOBAL_VAR_TYPE_COLOR || p_type == RS::GLOBAL_VAR_TYPE_MAT2) {
+ //color needs to elements to store srgb and linear
+ gv.buffer_elements = 2;
+ }
+ if (p_type == RS::GLOBAL_VAR_TYPE_MAT3 || p_type == RS::GLOBAL_VAR_TYPE_TRANSFORM_2D) {
+ //color needs to elements to store srgb and linear
+ gv.buffer_elements = 3;
+ }
+ if (p_type == RS::GLOBAL_VAR_TYPE_MAT4 || p_type == RS::GLOBAL_VAR_TYPE_TRANSFORM) {
+ //color needs to elements to store srgb and linear
+ gv.buffer_elements = 4;
+ }
+
+ //is vector, allocate in buffer and update index
+ gv.buffer_index = _global_variable_allocate(gv.buffer_elements);
+ ERR_FAIL_COND_MSG(gv.buffer_index < 0, vformat("Failed allocating global variable '%s' out of buffer memory. Consider increasing it in the Project Settings.", String(p_name)));
+ global_variables.buffer_usage[gv.buffer_index].elements = gv.buffer_elements;
+ _global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.value);
+ _global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
+
+ global_variables.must_update_buffer_materials = true; //normally ther are no
+ }
+
+ global_variables.variables[p_name] = gv;
+}
+
+void RasterizerStorageRD::global_variable_remove(const StringName &p_name) {
+ if (!global_variables.variables.has(p_name)) {
+ return;
+ }
+ GlobalVariables::Variable &gv = global_variables.variables[p_name];
+
+ if (gv.buffer_index >= 0) {
+ global_variables.buffer_usage[gv.buffer_index].elements = 0;
+ global_variables.must_update_buffer_materials = true;
+ } else {
+ global_variables.must_update_texture_materials = true;
+ }
+
+ global_variables.variables.erase(p_name);
+}
+Vector<StringName> RasterizerStorageRD::global_variable_get_list() const {
+
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ ERR_FAIL_V_MSG(Vector<StringName>(), "This function should never be used outside the editor, it can severely damage performance.");
+ }
+
+ const StringName *K = NULL;
+ Vector<StringName> names;
+ while ((K = global_variables.variables.next(K))) {
+ names.push_back(*K);
+ }
+ names.sort_custom<StringName::AlphCompare>();
+ return names;
+}
+
+void RasterizerStorageRD::global_variable_set(const StringName &p_name, const Variant &p_value) {
+ ERR_FAIL_COND(!global_variables.variables.has(p_name));
+ GlobalVariables::Variable &gv = global_variables.variables[p_name];
+ gv.value = p_value;
+ if (gv.override.get_type() == Variant::NIL) {
+ if (gv.buffer_index >= 0) {
+ //buffer
+ _global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.value);
+ _global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
+ } else {
+ //texture
+ for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) {
+ Material *material = material_owner.getornull(E->get());
+ ERR_CONTINUE(!material);
+ _material_queue_update(material, false, true);
+ }
+ }
+ }
+}
+void RasterizerStorageRD::global_variable_set_override(const StringName &p_name, const Variant &p_value) {
+ if (!global_variables.variables.has(p_name)) {
+ return; //variable may not exist
+ }
+ GlobalVariables::Variable &gv = global_variables.variables[p_name];
+
+ gv.override = p_value;
+
+ if (gv.buffer_index >= 0) {
+ //buffer
+ if (gv.override.get_type() == Variant::NIL) {
+ _global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.value);
+ } else {
+ _global_variable_store_in_buffer(gv.buffer_index, gv.type, gv.override);
+ }
+
+ _global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
+ } else {
+ //texture
+ //texture
+ for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) {
+ Material *material = material_owner.getornull(E->get());
+ ERR_CONTINUE(!material);
+ _material_queue_update(material, false, true);
+ }
+ }
+}
+
+Variant RasterizerStorageRD::global_variable_get(const StringName &p_name) const {
+
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ ERR_FAIL_V_MSG(Variant(), "This function should never be used outside the editor, it can severely damage performance.");
+ }
+
+ if (!global_variables.variables.has(p_name)) {
+ return Variant();
+ }
+
+ return global_variables.variables[p_name].value;
+}
+
+RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type_internal(const StringName &p_name) const {
+
+ if (!global_variables.variables.has(p_name)) {
+ return RS::GLOBAL_VAR_TYPE_MAX;
+ }
+
+ return global_variables.variables[p_name].type;
+}
+
+RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type(const StringName &p_name) const {
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ ERR_FAIL_V_MSG(RS::GLOBAL_VAR_TYPE_MAX, "This function should never be used outside the editor, it can severely damage performance.");
+ }
+
+ return global_variable_get_type_internal(p_name);
+}
+
+void RasterizerStorageRD::global_variables_load_settings(bool p_load_textures) {
+
+ List<PropertyInfo> settings;
+ ProjectSettings::get_singleton()->get_property_list(&settings);
+
+ for (List<PropertyInfo>::Element *E = settings.front(); E; E = E->next()) {
+ if (E->get().name.begins_with("shader_globals/")) {
+ StringName name = E->get().name.get_slice("/", 1);
+ Dictionary d = ProjectSettings::get_singleton()->get(E->get().name);
+
+ ERR_CONTINUE(!d.has("type"));
+ ERR_CONTINUE(!d.has("value"));
+
+ String type = d["type"];
+
+ static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = {
+ "bool",
+ "bvec2",
+ "bvec3",
+ "bvec4",
+ "int",
+ "ivec2",
+ "ivec3",
+ "ivec4",
+ "rect2i",
+ "uint",
+ "uvec2",
+ "uvec3",
+ "uvec4",
+ "float",
+ "vec2",
+ "vec3",
+ "vec4",
+ "color",
+ "rect2",
+ "mat2",
+ "mat3",
+ "mat4",
+ "transform_2d",
+ "transform",
+ "sampler2D",
+ "sampler2DArray",
+ "sampler3D",
+ "samplerCube",
+ };
+
+ RS::GlobalVariableType gvtype = RS::GLOBAL_VAR_TYPE_MAX;
+
+ for (int i = 0; i < RS::GLOBAL_VAR_TYPE_MAX; i++) {
+ if (global_var_type_names[i] == type) {
+ gvtype = RS::GlobalVariableType(i);
+ break;
+ }
+ }
+
+ ERR_CONTINUE(gvtype == RS::GLOBAL_VAR_TYPE_MAX); //type invalid
+
+ Variant value = d["value"];
+
+ if (gvtype >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
+ //textire
+ if (!p_load_textures) {
+ value = RID();
+ continue;
+ }
+
+ String path = value;
+ RES resource = ResourceLoader::load(path);
+ ERR_CONTINUE(resource.is_null());
+ value = resource;
+ }
+
+ if (global_variables.variables.has(name)) {
+ //has it, update it
+ global_variable_set(name, value);
+ } else {
+ global_variable_add(name, gvtype, value);
+ }
+ }
+ }
+}
+
+void RasterizerStorageRD::global_variables_clear() {
+ global_variables.variables.clear(); //not right but for now enough
+}
+
+RID RasterizerStorageRD::global_variables_get_storage_buffer() const {
+ return global_variables.buffer;
+}
+
+int32_t RasterizerStorageRD::global_variables_instance_allocate(RID p_instance) {
+ ERR_FAIL_COND_V(global_variables.instance_buffer_pos.has(p_instance), -1);
+ int32_t pos = _global_variable_allocate(ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES);
+ global_variables.instance_buffer_pos[p_instance] = pos; //save anyway
+ ERR_FAIL_COND_V_MSG(pos < 0, -1, "Too many instances using shader instance variables. Increase buffer size in Project Settings.");
+ global_variables.buffer_usage[pos].elements = ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES;
+ return pos;
+}
+
+void RasterizerStorageRD::global_variables_instance_free(RID p_instance) {
+ ERR_FAIL_COND(!global_variables.instance_buffer_pos.has(p_instance));
+ int32_t pos = global_variables.instance_buffer_pos[p_instance];
+ if (pos >= 0) {
+ global_variables.buffer_usage[pos].elements = 0;
+ }
+ global_variables.instance_buffer_pos.erase(p_instance);
+}
+void RasterizerStorageRD::global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) {
+
+ if (!global_variables.instance_buffer_pos.has(p_instance)) {
+ return; //just not allocated, ignore
+ }
+ int32_t pos = global_variables.instance_buffer_pos[p_instance];
+
+ if (pos < 0) {
+ return; //again, not allocated, ignore
+ }
+ ERR_FAIL_INDEX(p_index, ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES);
+ ERR_FAIL_COND_MSG(p_value.get_type() > Variant::COLOR, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported
+
+ ShaderLanguage::DataType datatype_from_value[Variant::COLOR + 1] = {
+ ShaderLanguage::TYPE_MAX, //nil
+ ShaderLanguage::TYPE_BOOL, //bool
+ ShaderLanguage::TYPE_INT, //int
+ ShaderLanguage::TYPE_FLOAT, //float
+ ShaderLanguage::TYPE_MAX, //string
+ ShaderLanguage::TYPE_VEC2, //vec2
+ ShaderLanguage::TYPE_IVEC2, //vec2i
+ ShaderLanguage::TYPE_VEC4, //rect2
+ ShaderLanguage::TYPE_IVEC4, //rect2i
+ ShaderLanguage::TYPE_VEC3, // vec3
+ ShaderLanguage::TYPE_IVEC3, //vec3i
+ ShaderLanguage::TYPE_MAX, //xform2d not supported here
+ ShaderLanguage::TYPE_VEC4, //plane
+ ShaderLanguage::TYPE_VEC4, //quat
+ ShaderLanguage::TYPE_MAX, //aabb not supported here
+ ShaderLanguage::TYPE_MAX, //basis not supported here
+ ShaderLanguage::TYPE_MAX, //xform not supported here
+ ShaderLanguage::TYPE_VEC4 //color
+ };
+
+ ShaderLanguage::DataType datatype = datatype_from_value[p_value.get_type()];
+
+ ERR_FAIL_COND_MSG(datatype == ShaderLanguage::TYPE_MAX, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported
+
+ pos += p_index;
+
+ _fill_std140_variant_ubo_value(datatype, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer
+ _global_variable_mark_buffer_dirty(pos, 1);
+}
+
+void RasterizerStorageRD::_update_global_variables() {
+
+ if (global_variables.buffer_dirty_region_count > 0) {
+ uint32_t total_regions = global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE;
+ if (total_regions / global_variables.buffer_dirty_region_count <= 4) {
+ // 25% of regions dirty, just update all buffer
+ RD::get_singleton()->buffer_update(global_variables.buffer, 0, sizeof(GlobalVariables::Value) * global_variables.buffer_size, global_variables.buffer_values);
+ zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * total_regions);
+ } else {
+ uint32_t region_byte_size = sizeof(GlobalVariables::Value) * GlobalVariables::BUFFER_DIRTY_REGION_SIZE;
+
+ for (uint32_t i = 0; i < total_regions; i++) {
+ if (global_variables.buffer_dirty_regions[i]) {
+
+ RD::get_singleton()->buffer_update(global_variables.buffer, i * region_byte_size, region_byte_size, global_variables.buffer_values);
+
+ global_variables.buffer_dirty_regions[i] = false;
+ }
+ }
+ }
+
+ global_variables.buffer_dirty_region_count = 0;
+ }
+
+ if (global_variables.must_update_buffer_materials) {
+ // only happens in the case of a buffer variable added or removed,
+ // so not often.
+ for (List<RID>::Element *E = global_variables.materials_using_buffer.front(); E; E = E->next()) {
+ Material *material = material_owner.getornull(E->get());
+ ERR_CONTINUE(!material); //wtf
+
+ _material_queue_update(material, true, false);
+ }
+
+ global_variables.must_update_buffer_materials = false;
+ }
+
+ if (global_variables.must_update_texture_materials) {
+ // only happens in the case of a buffer variable added or removed,
+ // so not often.
+ for (List<RID>::Element *E = global_variables.materials_using_texture.front(); E; E = E->next()) {
+ Material *material = material_owner.getornull(E->get());
+ ERR_CONTINUE(!material); //wtf
+
+ _material_queue_update(material, false, true);
+ print_line("update material texture?");
+ }
+
+ global_variables.must_update_texture_materials = false;
+ }
+}
+
void RasterizerStorageRD::update_dirty_resources() {
+ _update_global_variables(); //must do before materials, so it can queue them for update
_update_queued_materials();
_update_dirty_multimeshes();
_update_dirty_skeletons();
+ _update_decal_atlas();
}
bool RasterizerStorageRD::has_os_feature(const String &p_feature) const {
@@ -4332,6 +5496,11 @@ bool RasterizerStorageRD::free(RID p_rid) {
}
}
+ if (decal_atlas.textures.has(p_rid)) {
+ decal_atlas.textures.erase(p_rid);
+ //there is not much a point of making it dirty, just let it be.
+ }
+
for (int i = 0; i < t->proxies.size(); i++) {
Texture *p = texture_owner.getornull(t->proxies[i]);
ERR_CONTINUE(!p);
@@ -4382,6 +5551,15 @@ bool RasterizerStorageRD::free(RID p_rid) {
ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid);
reflection_probe->instance_dependency.instance_notify_deleted(p_rid);
reflection_probe_owner.free(p_rid);
+ } else if (decal_owner.owns(p_rid)) {
+ Decal *decal = decal_owner.getornull(p_rid);
+ for (int i = 0; i < RS::DECAL_TEXTURE_MAX; i++) {
+ if (decal->textures[i].is_valid() && texture_owner.owns(decal->textures[i])) {
+ texture_remove_from_decal_atlas(decal->textures[i]);
+ }
+ }
+ decal->instance_dependency.instance_notify_deleted(p_rid);
+ decal_owner.free(p_rid);
} else if (gi_probe_owner.owns(p_rid)) {
gi_probe_allocate(p_rid, Transform(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate
GIProbe *gi_probe = gi_probe_owner.getornull(p_rid);
@@ -4390,6 +5568,7 @@ bool RasterizerStorageRD::free(RID p_rid) {
} else if (light_owner.owns(p_rid)) {
+ light_set_projector(p_rid, RID()); //clear projector
// delete the texture
Light *light = light_owner.getornull(p_rid);
light->instance_dependency.instance_notify_deleted(p_rid);
@@ -4443,12 +5622,27 @@ String RasterizerStorageRD::get_captured_timestamp_name(uint32_t p_index) const
return RD::get_singleton()->get_captured_timestamp_name(p_index);
}
+RasterizerStorageRD *RasterizerStorageRD::base_singleton = nullptr;
+
RasterizerStorageRD::RasterizerStorageRD() {
+ base_singleton = this;
+
for (int i = 0; i < SHADER_TYPE_MAX; i++) {
shader_data_request_func[i] = nullptr;
}
+ static_assert(sizeof(GlobalVariables::Value) == 16);
+
+ global_variables.buffer_size = GLOBAL_GET("rendering/high_end/global_shader_variables_buffer_size");
+ global_variables.buffer_size = MAX(4096, global_variables.buffer_size);
+ global_variables.buffer_values = memnew_arr(GlobalVariables::Value, global_variables.buffer_size);
+ zeromem(global_variables.buffer_values, sizeof(GlobalVariables::Value) * global_variables.buffer_size);
+ global_variables.buffer_usage = memnew_arr(GlobalVariables::ValueUsage, global_variables.buffer_size);
+ global_variables.buffer_dirty_regions = memnew_arr(bool, global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
+ zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
+ global_variables.buffer = RD::get_singleton()->storage_buffer_create(sizeof(GlobalVariables::Value) * global_variables.buffer_size);
+
material_update_list = nullptr;
{ //create default textures
@@ -4485,6 +5679,10 @@ RasterizerStorageRD::RasterizerStorageRD() {
Vector<Vector<uint8_t>> vpv;
vpv.push_back(pv);
default_rd_textures[DEFAULT_RD_TEXTURE_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+
+ //take the chance and initialize decal atlas to something
+ decal_atlas.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ decal_atlas.texture_srgb = decal_atlas.texture;
}
for (int i = 0; i < 16; i++) {
@@ -4676,9 +5874,11 @@ RasterizerStorageRD::RasterizerStorageRD() {
//default rd buffers
{
- { //vertex
+ //vertex
+ {
Vector<uint8_t> buffer;
+
buffer.resize(sizeof(float) * 3);
{
uint8_t *w = buffer.ptrw();
@@ -4796,6 +5996,11 @@ RasterizerStorageRD::RasterizerStorageRD() {
RasterizerStorageRD::~RasterizerStorageRD() {
+ memdelete_arr(global_variables.buffer_values);
+ memdelete_arr(global_variables.buffer_usage);
+ memdelete_arr(global_variables.buffer_dirty_regions);
+ RD::get_singleton()->free(global_variables.buffer);
+
//def textures
for (int i = 0; i < DEFAULT_RD_TEXTURE_MAX; i++) {
RD::get_singleton()->free(default_rd_textures[i]);
@@ -4813,4 +6018,12 @@ RasterizerStorageRD::~RasterizerStorageRD() {
RD::get_singleton()->free(mesh_default_rd_buffers[i]);
}
giprobe_sdf_shader.version_free(giprobe_sdf_shader_version);
+
+ if (decal_atlas.textures.size()) {
+ ERR_PRINT("Decal Atlas: " + itos(decal_atlas.textures.size()) + " textures were not removed from the atlas.");
+ }
+
+ if (decal_atlas.texture.is_valid()) {
+ RD::get_singleton()->free(decal_atlas.texture);
+ }
}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
index 29a45ca90e..f874c3baf8 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
@@ -52,6 +52,8 @@ public:
virtual void set_code(const String &p_Code) = 0;
virtual void set_default_texture_param(const StringName &p_name, RID p_texture) = 0;
virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0;
+
+ virtual void get_instance_param_list(List<InstanceShaderParam> *p_param_list) const = 0;
virtual bool is_param_texture(const StringName &p_param) const = 0;
virtual bool is_animated() const = 0;
virtual bool casts_shadows() const = 0;
@@ -69,7 +71,15 @@ public:
virtual void set_render_priority(int p_priority) = 0;
virtual void set_next_pass(RID p_pass) = 0;
virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
- virtual ~MaterialData() {}
+ virtual ~MaterialData();
+
+ private:
+ friend class RasterizerStorageRD;
+ RID self;
+ List<RID>::Element *global_buffer_E = nullptr;
+ List<RID>::Element *global_texture_E = nullptr;
+ uint64_t global_textures_pass = 0;
+ Map<StringName, uint64_t> used_global_textures;
};
typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
@@ -173,6 +183,51 @@ private:
RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+ /* DECAL ATLAS */
+
+ struct DecalAtlas {
+ struct Texture {
+
+ int panorama_to_dp_users;
+ int users;
+ Rect2 uv_rect;
+ };
+
+ struct SortItem {
+ RID texture;
+ Size2i pixel_size;
+ Size2i size;
+ Point2i pos;
+
+ bool operator<(const SortItem &p_item) const {
+ //sort larger to smaller
+ if (size.height == p_item.size.height) {
+ return size.width > p_item.size.width;
+ } else {
+ return size.height > p_item.size.height;
+ }
+ }
+ };
+
+ HashMap<RID, Texture> textures;
+ bool dirty = true;
+ int mipmaps = 5;
+
+ RID texture;
+ RID texture_srgb;
+ struct MipMap {
+ RID fb;
+ RID texture;
+ Size2i size;
+ };
+ Vector<MipMap> texture_mipmaps;
+
+ Size2i size;
+
+ } decal_atlas;
+
+ void _update_decal_atlas();
+
/* SHADER */
struct Material;
@@ -403,6 +458,28 @@ private:
mutable RID_Owner<ReflectionProbe> reflection_probe_owner;
+ /* DECAL */
+
+ struct Decal {
+
+ Vector3 extents = Vector3(1, 1, 1);
+ RID textures[RS::DECAL_TEXTURE_MAX];
+ float emission_energy = 1.0;
+ float albedo_mix = 1.0;
+ Color modulate = Color(1, 1, 1, 1);
+ uint32_t cull_mask = (1 << 20) - 1;
+ float upper_fade = 0.3;
+ float lower_fade = 0.3;
+ bool distance_fade = false;
+ float distance_fade_begin = 10;
+ float distance_fade_length = 1;
+ float normal_fade = 0.0;
+
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ mutable RID_Owner<Decal> decal_owner;
+
/* GI PROBE */
struct GIProbe {
@@ -488,6 +565,73 @@ private:
void _update_render_target(RenderTarget *rt);
void _create_render_target_backbuffer(RenderTarget *rt);
+ /* GLOBAL SHADER VARIABLES */
+
+ struct GlobalVariables {
+
+ enum {
+ BUFFER_DIRTY_REGION_SIZE = 1024
+ };
+ struct Variable {
+ Set<RID> texture_materials; // materials using this
+
+ RS::GlobalVariableType type;
+ Variant value;
+ Variant override;
+ int32_t buffer_index; //for vectors
+ int32_t buffer_elements; //for vectors
+ };
+
+ HashMap<StringName, Variable> variables;
+
+ struct Value {
+ float x;
+ float y;
+ float z;
+ float w;
+ };
+
+ struct ValueInt {
+ int32_t x;
+ int32_t y;
+ int32_t z;
+ int32_t w;
+ };
+
+ struct ValueUInt {
+ uint32_t x;
+ uint32_t y;
+ uint32_t z;
+ uint32_t w;
+ };
+
+ struct ValueUsage {
+ uint32_t elements = 0;
+ };
+
+ List<RID> materials_using_buffer;
+ List<RID> materials_using_texture;
+
+ RID buffer;
+ Value *buffer_values;
+ ValueUsage *buffer_usage;
+ bool *buffer_dirty_regions;
+ uint32_t buffer_dirty_region_count = 0;
+
+ uint32_t buffer_size;
+
+ bool must_update_texture_materials = false;
+ bool must_update_buffer_materials = false;
+
+ HashMap<RID, int32_t> instance_buffer_pos;
+
+ } global_variables;
+
+ int32_t _global_variable_allocate(uint32_t p_elements);
+ void _global_variable_store_in_buffer(int32_t p_index, RS::GlobalVariableType p_type, const Variant &p_value);
+ void _global_variable_mark_buffer_dirty(int32_t p_index, int32_t p_elements);
+
+ void _update_global_variables();
/* EFFECTS */
RasterizerEffectsRD effects;
@@ -533,6 +677,20 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy);
+ virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false);
+ virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false);
+
+ RID decal_atlas_get_texture() const;
+ RID decal_atlas_get_texture_srgb() const;
+ _FORCE_INLINE_ Rect2 decal_atlas_get_texture_rect(RID p_texture) {
+ DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
+ if (!t) {
+ return Rect2();
+ }
+
+ return t->uv_rect;
+ }
+
//internal usage
_FORCE_INLINE_ RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) {
@@ -594,6 +752,8 @@ public:
bool material_is_animated(RID p_material);
bool material_casts_shadows(RID p_material);
+ void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters);
+
void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance);
void material_force_update_textures(RID p_material, ShaderType p_shader_type);
@@ -884,6 +1044,14 @@ public:
return light->param[p_param];
}
+ _FORCE_INLINE_ RID light_get_projector(RID p_light) {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, RID());
+
+ return light->projector;
+ }
+
_FORCE_INLINE_ Color light_get_color(RID p_light) {
const Light *light = light_owner.getornull(p_light);
@@ -972,6 +1140,81 @@ public:
void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance);
void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance);
+ /* DECAL API */
+
+ virtual RID decal_create();
+ virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents);
+ virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture);
+ virtual void decal_set_emission_energy(RID p_decal, float p_energy);
+ virtual void decal_set_albedo_mix(RID p_decal, float p_mix);
+ virtual void decal_set_modulate(RID p_decal, const Color &p_modulate);
+ virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers);
+ virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length);
+ virtual void decal_set_fade(RID p_decal, float p_above, float p_below);
+ virtual void decal_set_normal_fade(RID p_decal, float p_fade);
+
+ _FORCE_INLINE_ Vector3 decal_get_extents(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->extents;
+ }
+
+ _FORCE_INLINE_ RID decal_get_texture(RID p_decal, RS::DecalTexture p_texture) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->textures[p_texture];
+ }
+
+ _FORCE_INLINE_ Color decal_get_modulate(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->modulate;
+ }
+
+ _FORCE_INLINE_ float decal_get_emission_energy(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->emission_energy;
+ }
+
+ _FORCE_INLINE_ float decal_get_albedo_mix(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->albedo_mix;
+ }
+
+ _FORCE_INLINE_ uint32_t decal_get_cull_mask(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->cull_mask;
+ }
+
+ _FORCE_INLINE_ float decal_get_upper_fade(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->upper_fade;
+ }
+
+ _FORCE_INLINE_ float decal_get_lower_fade(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->lower_fade;
+ }
+
+ _FORCE_INLINE_ float decal_get_normal_fade(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->normal_fade;
+ }
+
+ _FORCE_INLINE_ bool decal_is_distance_fade_enabled(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->distance_fade;
+ }
+
+ _FORCE_INLINE_ float decal_get_distance_fade_begin(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->distance_fade_begin;
+ }
+
+ _FORCE_INLINE_ float decal_get_distance_fade_length(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->distance_fade_length;
+ }
+
+ virtual AABB decal_get_aabb(RID p_decal) const;
+
/* GI PROBE API */
RID gi_probe_create();
@@ -1082,6 +1325,27 @@ public:
virtual bool particles_is_inactive(RID p_particles) const { return false; }
+ /* GLOBAL VARIABLES API */
+
+ virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value);
+ virtual void global_variable_remove(const StringName &p_name);
+ virtual Vector<StringName> global_variable_get_list() const;
+
+ virtual void global_variable_set(const StringName &p_name, const Variant &p_value);
+ virtual void global_variable_set_override(const StringName &p_name, const Variant &p_value);
+ virtual Variant global_variable_get(const StringName &p_name) const;
+ virtual RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const;
+ RS::GlobalVariableType global_variable_get_type_internal(const StringName &p_name) const;
+
+ virtual void global_variables_load_settings(bool p_load_textures = true);
+ virtual void global_variables_clear();
+
+ virtual int32_t global_variables_instance_allocate(RID p_instance);
+ virtual void global_variables_instance_free(RID p_instance);
+ virtual void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value);
+
+ RID global_variables_get_storage_buffer() const;
+
/* RENDER TARGET API */
RID render_target_create();
@@ -1131,7 +1395,7 @@ public:
virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const;
virtual String get_captured_timestamp_name(uint32_t p_index) const;
- static RasterizerStorage *base_singleton;
+ static RasterizerStorageRD *base_singleton;
RasterizerEffectsRD *get_effects();
diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
index 4a0b4f02b1..9cbff2571a 100644
--- a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
@@ -32,6 +32,8 @@
#include "core/os/os.h"
#include "core/project_settings.h"
+#include "rasterizer_storage_rd.h"
+#include "servers/rendering_server.h"
#define SL ShaderLanguage
@@ -91,6 +93,9 @@ static int _get_datatype_size(SL::DataType p_type) {
case SL::TYPE_USAMPLER3D: return 16;
case SL::TYPE_SAMPLERCUBE: return 16;
case SL::TYPE_STRUCT: return 0;
+ case SL::TYPE_MAX: {
+ ERR_FAIL_V(0);
+ };
}
ERR_FAIL_V(0);
@@ -131,6 +136,9 @@ static int _get_datatype_alignment(SL::DataType p_type) {
case SL::TYPE_USAMPLER3D: return 16;
case SL::TYPE_SAMPLERCUBE: return 16;
case SL::TYPE_STRUCT: return 0;
+ case SL::TYPE_MAX: {
+ ERR_FAIL_V(0);
+ }
}
ERR_FAIL_V(0);
@@ -341,6 +349,71 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S
}
}
+static String _get_global_variable_from_type_and_index(const String &p_buffer, const String &p_index, ShaderLanguage::DataType p_type) {
+ switch (p_type) {
+ case ShaderLanguage::TYPE_BOOL: {
+ return "(" + p_buffer + "[" + p_index + "].x != 0.0)";
+ }
+ case ShaderLanguage::TYPE_BVEC2: {
+ return "(" + p_buffer + "[" + p_index + "].xy != vec2(0.0))";
+ }
+ case ShaderLanguage::TYPE_BVEC3: {
+ return "(" + p_buffer + "[" + p_index + "].xyz != vec3(0.0))";
+ }
+ case ShaderLanguage::TYPE_BVEC4: {
+ return "(" + p_buffer + "[" + p_index + "].xyzw != vec4(0.0))";
+ }
+ case ShaderLanguage::TYPE_INT: {
+ return "floatBitsToInt(" + p_buffer + "[" + p_index + "].x)";
+ }
+ case ShaderLanguage::TYPE_IVEC2: {
+ return "floatBitsToInt(" + p_buffer + "[" + p_index + "].xy)";
+ }
+ case ShaderLanguage::TYPE_IVEC3: {
+ return "floatBitsToInt(" + p_buffer + "[" + p_index + "].xyz)";
+ }
+ case ShaderLanguage::TYPE_IVEC4: {
+ return "floatBitsToInt(" + p_buffer + "[" + p_index + "].xyzw)";
+ }
+ case ShaderLanguage::TYPE_UINT: {
+ return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].x)";
+ }
+ case ShaderLanguage::TYPE_UVEC2: {
+ return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xy)";
+ }
+ case ShaderLanguage::TYPE_UVEC3: {
+ return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xyz)";
+ }
+ case ShaderLanguage::TYPE_UVEC4: {
+ return "floatBitsToUInt(" + p_buffer + "[" + p_index + "].xyzw)";
+ }
+ case ShaderLanguage::TYPE_FLOAT: {
+ return "(" + p_buffer + "[" + p_index + "].x)";
+ }
+ case ShaderLanguage::TYPE_VEC2: {
+ return "(" + p_buffer + "[" + p_index + "].xy)";
+ }
+ case ShaderLanguage::TYPE_VEC3: {
+ return "(" + p_buffer + "[" + p_index + "].xyz)";
+ }
+ case ShaderLanguage::TYPE_VEC4: {
+ return "(" + p_buffer + "[" + p_index + "].xyzw)";
+ }
+ case ShaderLanguage::TYPE_MAT2: {
+ return "mat2(" + p_buffer + "[" + p_index + "].xy," + p_buffer + "[" + p_index + "+1].xy)";
+ }
+ case ShaderLanguage::TYPE_MAT3: {
+ return "mat3(" + p_buffer + "[" + p_index + "].xyz," + p_buffer + "[" + p_index + "+1].xyz," + p_buffer + "[" + p_index + "+2].xyz)";
+ }
+ case ShaderLanguage::TYPE_MAT4: {
+ return "mat4(" + p_buffer + "[" + p_index + "].xyzw," + p_buffer + "[" + p_index + "+1].xyzw," + p_buffer + "[" + p_index + "+2].xyzw," + p_buffer + "[" + p_index + "+3].xyzw)";
+ }
+ default: {
+ ERR_FAIL_V("void");
+ }
+ }
+}
+
String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning) {
String code;
@@ -408,10 +481,17 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
int max_uniforms = 0;
for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
- if (SL::is_sampler_type(E->get().type))
+
+ if (SL::is_sampler_type(E->get().type)) {
max_texture_uniforms++;
- else
+ } else {
+
+ if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue; //instances are indexed directly, dont need index uniforms
+ }
+
max_uniforms++;
+ }
}
r_gen_code.texture_uniforms.resize(max_texture_uniforms);
@@ -428,12 +508,25 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
String ucode;
+ if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ //insert, but don't generate any code.
+ p_actions.uniforms->insert(E->key(), E->get());
+ continue; //instances are indexed directly, dont need index uniforms
+ }
if (SL::is_sampler_type(E->get().type)) {
ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + E->get().texture_order) + ") uniform ";
}
- ucode += _prestr(E->get().precision);
- ucode += _typestr(E->get().type);
+ bool is_buffer_global = !SL::is_sampler_type(E->get().type) && E->get().scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
+
+ if (is_buffer_global) {
+ //this is an integer to index the global table
+ ucode += _typestr(ShaderLanguage::TYPE_UINT);
+ } else {
+ ucode += _prestr(E->get().precision);
+ ucode += _typestr(E->get().type);
+ }
+
ucode += " " + _mkid(E->key());
ucode += ";\n";
if (SL::is_sampler_type(E->get().type)) {
@@ -446,6 +539,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
texture.type = E->get().type;
texture.filter = E->get().filter;
texture.repeat = E->get().repeat;
+ texture.global = E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;
+ if (texture.global) {
+ r_gen_code.uses_global_textures = true;
+ }
r_gen_code.texture_uniforms.write[E->get().texture_order] = texture;
} else {
@@ -455,8 +552,14 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
uses_uniforms = true;
}
uniform_defines.write[E->get().order] = ucode;
- uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
- uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
+ if (is_buffer_global) {
+ //globals are indices into the global table
+ uniform_sizes.write[E->get().order] = _get_datatype_size(ShaderLanguage::TYPE_UINT);
+ uniform_alignments.write[E->get().order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
+ } else {
+ uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
+ uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
+ }
}
p_actions.uniforms->insert(E->key(), E->get());
@@ -690,9 +793,29 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
if (p_default_actions.renames.has(vnode->name))
code = p_default_actions.renames[vnode->name];
else {
- code = _mkid(vnode->name);
- if (actions.base_uniform_string != String() && shader->uniforms.has(vnode->name) && shader->uniforms[vnode->name].texture_order < 0) {
- code = actions.base_uniform_string + code;
+ if (shader->uniforms.has(vnode->name)) {
+ //its a uniform!
+ const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[vnode->name];
+ if (u.texture_order >= 0) {
+ code = _mkid(vnode->name); //texture, use as is
+ } else {
+ //a scalar or vector
+ if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
+ code = actions.base_uniform_string + _mkid(vnode->name); //texture, use as is
+ //global variable, this means the code points to an index to the global table
+ code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type);
+ } else if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ //instance variable, index it as such
+ code = "(" + p_default_actions.instance_uniform_index_variable + "+" + itos(u.instance_index) + ")";
+ code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type);
+ } else {
+ //regular uniform, index from UBO
+ code = actions.base_uniform_string + _mkid(vnode->name);
+ }
+ }
+
+ } else {
+ code = _mkid(vnode->name); //its something else (local var most likely) use as is
}
}
@@ -1037,9 +1160,14 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
return code;
}
+ShaderLanguage::DataType ShaderCompilerRD::_get_variable_type(const StringName &p_type) {
+ RS::GlobalVariableType gvt = ((RasterizerStorageRD *)(RasterizerStorage::base_singleton))->global_variable_get_type_internal(p_type);
+ return RS::global_variable_type_get_shader_datatype(gvt);
+}
+
Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) {
- Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types());
+ Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types(), _get_variable_type);
if (err != OK) {
@@ -1060,6 +1188,7 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide
r_gen_code.light = String();
r_gen_code.uses_fragment_time = false;
r_gen_code.uses_vertex_time = false;
+ r_gen_code.uses_global_textures = false;
used_name_defines.clear();
used_rmode_defines.clear();
diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.h b/servers/rendering/rasterizer_rd/shader_compiler_rd.h
index 7d78469e9c..16d53197a7 100644
--- a/servers/rendering/rasterizer_rd/shader_compiler_rd.h
+++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.h
@@ -57,6 +57,7 @@ public:
ShaderLanguage::ShaderNode::Uniform::Hint hint;
ShaderLanguage::TextureFilter filter;
ShaderLanguage::TextureRepeat repeat;
+ bool global;
};
Vector<Texture> texture_uniforms;
@@ -70,6 +71,7 @@ public:
String fragment;
String light;
+ bool uses_global_textures;
bool uses_fragment_time;
bool uses_vertex_time;
};
@@ -86,6 +88,8 @@ public:
int base_texture_binding_index = 0;
int texture_layout_set = 0;
String base_uniform_string;
+ String global_buffer_array_variable;
+ String instance_uniform_index_variable;
uint32_t base_varying_index = 0;
};
@@ -113,6 +117,8 @@ private:
DefaultIdentifierActions actions;
+ static ShaderLanguage::DataType _get_variable_type(const StringName &p_type);
+
public:
Error compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code);
diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
index 1ac43480cd..a39866004b 100644
--- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
@@ -132,6 +132,11 @@ layout(set = 2, binding = 6) uniform sampler shadow_sampler;
#endif
+layout(set = 2, binding = 7, std430) restrict readonly buffer GlobalVariableData {
+ vec4 data[];
+}
+global_variables;
+
/* SET3: Render Target Data */
#ifdef SCREEN_TEXTURE_USED
diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl
index 48c49ff7de..2d7661f65f 100644
--- a/servers/rendering/rasterizer_rd/shaders/copy.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl
@@ -35,7 +35,7 @@ layout(push_constant, binding = 1, std430) uniform Params {
// DOF.
float camera_z_far;
float camera_z_near;
- uvec2 pad2;
+ uint pad2[2];
}
params;
diff --git a/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl b/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl
index 1f499cf372..07f8d09743 100644
--- a/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl
@@ -13,6 +13,7 @@ layout(push_constant, binding = 1, std430) uniform Params {
vec2 pixel_size;
bool flip_y;
bool use_section;
+
bool force_luminance;
uint pad[3];
}
@@ -23,11 +24,12 @@ void main() {
vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
uv_interp = base_arr[gl_VertexIndex];
+ vec2 vpos = uv_interp;
if (params.use_section) {
- uv_interp = params.section.xy + uv_interp * params.section.zw;
+ vpos = params.section.xy + vpos * params.section.zw;
}
- gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+ gl_Position = vec4(vpos * 2.0 - 1.0, 0.0, 1.0);
if (params.flip_y) {
uv_interp.y = 1.0 - uv_interp.y;
@@ -46,8 +48,10 @@ layout(push_constant, binding = 1, std430) uniform Params {
vec2 pixel_size;
bool flip_y;
bool use_section;
+
bool force_luminance;
- uint pad[3];
+ bool alpha_to_zero;
+ uint pad[2];
} params;
@@ -60,9 +64,41 @@ layout(location = 0) out vec4 frag_color;
void main() {
- vec4 color = texture(source_color, uv_interp, 0.0);
+ vec2 uv = uv_interp;
+
+#ifdef MODE_PANORAMA_TO_DP
+
+ //obtain normal from dual paraboloid uv
+#define M_PI 3.14159265359
+
+ float side;
+ uv.y = modf(uv.y * 2.0, side);
+ side = side * 2.0 - 1.0;
+ vec3 normal = vec3(uv * 2.0 - 1.0, 0.0);
+ normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
+ normal *= -side;
+ normal = normalize(normal);
+
+ //now convert normal to panorama uv
+
+ vec2 st = vec2(atan(normal.x, normal.z), acos(normal.y));
+
+ if (st.x < 0.0)
+ st.x += M_PI * 2.0;
+
+ uv = st / vec2(M_PI * 2.0, M_PI);
+
+ if (side < 0.0) {
+ //uv.y = 1.0 - uv.y;
+ uv = 1.0 - uv;
+ }
+#endif
+ vec4 color = textureLod(source_color, uv, 0.0);
if (params.force_luminance) {
color.rgb = vec3(max(max(color.r, color.g), color.b));
}
+ if (params.alpha_to_zero) {
+ color.rgb *= color.a;
+ }
frag_color = color;
}
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
index ea9d50c11d..ec47887036 100644
--- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
@@ -20,9 +20,7 @@ layout(location = 2) in vec4 tangent_attrib;
layout(location = 3) in vec4 color_attrib;
#endif
-#if defined(UV_USED)
layout(location = 4) in vec2 uv_attrib;
-#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
layout(location = 5) in vec2 uv2_attrib;
@@ -39,9 +37,7 @@ layout(location = 1) out vec3 normal_interp;
layout(location = 2) out vec4 color_interp;
#endif
-#if defined(UV_USED)
layout(location = 3) out vec2 uv_interp;
-#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
layout(location = 4) out vec2 uv2_interp;
@@ -157,9 +153,7 @@ void main() {
#endif
}
-#if defined(UV_USED)
uv_interp = uv_attrib;
-#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
uv2_interp = uv2_attrib;
@@ -290,9 +284,7 @@ layout(location = 1) in vec3 normal_interp;
layout(location = 2) in vec4 color_interp;
#endif
-#if defined(UV_USED)
layout(location = 3) in vec2 uv_interp;
-#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
layout(location = 4) in vec2 uv2_interp;
@@ -792,7 +784,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
#endif //USE_NO_SHADOWS
-void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -984,8 +976,8 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
//redo shadowmapping, but shrink the model a bit to avoid arctifacts
splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0));
- shadow_len = length(splane);
- splane = normalize(splane);
+ shadow_len = length(splane.xyz);
+ splane = normalize(splane.xyz);
if (splane.z >= 0.0) {
@@ -1007,7 +999,70 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
}
#endif
- shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
+ vec3 no_shadow = vec3(1.0);
+
+ if (lights.data[idx].projector_rect != vec4(0.0)) {
+
+ vec3 local_v = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
+ local_v = normalize(local_v);
+
+ vec4 atlas_rect = lights.data[idx].projector_rect;
+
+ if (local_v.z >= 0.0) {
+
+ local_v.z += 1.0;
+ atlas_rect.y += atlas_rect.w;
+
+ } else {
+
+ local_v.z = 1.0 - local_v.z;
+ }
+
+ local_v.xy /= local_v.z;
+ local_v.xy = local_v.xy * 0.5 + 0.5;
+ vec2 proj_uv = local_v.xy * atlas_rect.zw;
+
+ vec2 proj_uv_ddx;
+ vec2 proj_uv_ddy;
+ {
+ vec3 local_v_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
+ local_v_ddx = normalize(local_v_ddx);
+
+ if (local_v_ddx.z >= 0.0) {
+
+ local_v_ddx.z += 1.0;
+ } else {
+
+ local_v_ddx.z = 1.0 - local_v_ddx.z;
+ }
+
+ local_v_ddx.xy /= local_v_ddx.z;
+ local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
+
+ proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
+
+ vec3 local_v_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
+ local_v_ddy = normalize(local_v_ddy);
+
+ if (local_v_ddy.z >= 0.0) {
+
+ local_v_ddy.z += 1.0;
+ } else {
+
+ local_v_ddy.z = 1.0 - local_v_ddy.z;
+ }
+
+ local_v_ddy.xy /= local_v_ddy.z;
+ local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
+
+ proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
+ }
+
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ no_shadow = mix(no_shadow, proj.rgb, proj.a);
+ }
+
+ shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow);
}
#endif //USE_NO_SHADOWS
@@ -1038,7 +1093,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
specular_light);
}
-void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -1122,6 +1177,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
//find blocker
+ vec2 shadow_uv = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy;
+
float blocker_count = 0.0;
float blocker_average = 0.0;
@@ -1134,10 +1191,11 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
}
float uv_size = lights.data[idx].soft_shadow_size * z_norm * lights.data[idx].soft_shadow_scale;
+ vec2 clamp_max = lights.data[idx].atlas_rect.xy + lights.data[idx].atlas_rect.zw;
for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
- vec2 suv = splane.xy + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
- suv = clamp(suv, lights.data[idx].atlas_rect.xy, lights.data[idx].atlas_rect.zw);
+ vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
+ suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max);
float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
if (d < z_norm) {
blocker_average += d;
@@ -1154,8 +1212,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
shadow = 0.0;
for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
- vec2 suv = splane.xy + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
- suv = clamp(suv, lights.data[idx].atlas_rect.xy, lights.data[idx].atlas_rect.zw);
+ vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
+ suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max);
shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
}
@@ -1168,17 +1226,41 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
} else {
//hard shadow
- splane.z = z_norm;
- shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
+ vec4 shadow_uv = vec4(splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy, z_norm, 1.0);
+
+ shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
+ }
+
+ vec3 no_shadow = vec3(1.0);
+
+ if (lights.data[idx].projector_rect != vec4(0.0)) {
+
+ splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
+ splane /= splane.w;
+
+ vec2 proj_uv = splane.xy * lights.data[idx].projector_rect.zw;
+
+ //ensure we have proper mipmaps
+ vec4 splane_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0));
+ splane_ddx /= splane_ddx.w;
+ vec2 proj_uv_ddx = splane_ddx.xy * lights.data[idx].projector_rect.zw - proj_uv;
+
+ vec4 splane_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0));
+ splane_ddy /= splane_ddy.w;
+ vec2 proj_uv_ddy = splane_ddy.xy * lights.data[idx].projector_rect.zw - proj_uv;
+
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ no_shadow = mix(no_shadow, proj.rgb, proj.a);
}
- shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
+ shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow);
#ifdef LIGHT_TRANSMITTANCE_USED
{
- vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0));
+ splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0));
splane /= splane.w;
+ splane.xy = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy;
float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
//reconstruct depth
@@ -1612,9 +1694,7 @@ void main() {
}
#endif
-#if defined(UV_USED)
vec2 uv = uv_interp;
-#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
vec2 uv2 = uv2_interp;
@@ -1696,7 +1776,81 @@ FRAGMENT_SHADER_CODE
discard;
}
#endif
+ /////////////////////// DECALS ////////////////////////////////
+
+#ifndef MODE_RENDER_DEPTH
+
+ uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)));
+ //used for interpolating anything cluster related
+ vec3 vertex_ddx = dFdx(vertex);
+ vec3 vertex_ddy = dFdy(vertex);
+
+ { // process decals
+
+ uint decal_count = cluster_cell.w >> CLUSTER_COUNTER_SHIFT;
+ uint decal_pointer = cluster_cell.w & CLUSTER_POINTER_MASK;
+
+ //do outside for performance and avoiding arctifacts
+
+ for (uint i = 0; i < decal_count; i++) {
+
+ uint decal_index = cluster_data.indices[decal_pointer + i];
+ if (!bool(decals.data[decal_index].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
+
+ vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz;
+ if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) {
+ continue; //out of decal
+ }
+
+ //we need ddx/ddy for mipmaps, so simulate them
+ vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
+ vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
+ float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade);
+
+ if (decals.data[decal_index].normal_fade > 0.0) {
+ fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5);
+ }
+
+ if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
+ //has albedo
+ vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ decal_albedo *= decals.data[decal_index].modulate;
+ decal_albedo.a *= fade;
+ albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix);
+
+ if (decals.data[decal_index].normal_rect != vec4(0.0)) {
+
+ vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software
+ decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy)));
+ //convert to view space, use xzy because y is up
+ decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz;
+
+ normal = normalize(mix(normal, decal_normal, decal_albedo.a));
+ }
+
+ if (decals.data[decal_index].orm_rect != vec4(0.0)) {
+
+ vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+#if defined(AO_USED)
+ ao = mix(ao, decal_orm.r, decal_albedo.a);
+#endif
+ roughness = mix(roughness, decal_orm.g, decal_albedo.a);
+ metallic = mix(metallic, decal_orm.b, decal_albedo.a);
+ }
+ }
+
+ if (decals.data[decal_index].emission_rect != vec4(0.0)) {
+ //emission is additive, so its independent from albedo
+ emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ }
+ }
+ }
+
+#endif //not render depth
/////////////////////// LIGHTING //////////////////////////////
//apply energy conservation
@@ -1801,8 +1955,6 @@ FRAGMENT_SHADER_CODE
}
#endif
- uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)));
-
{ // process reflections
vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
@@ -2134,7 +2286,7 @@ FRAGMENT_SHADER_CODE
continue; //not masked
}
- light_process_omni(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity,
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -2173,7 +2325,7 @@ FRAGMENT_SHADER_CODE
continue; //not masked
}
- light_process_spot(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity,
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
index db11e4b005..ce4fabf9f2 100644
--- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
@@ -134,12 +134,12 @@ struct InstanceData {
mat4 transform;
mat4 normal_transform;
uint flags;
- uint instance_ofs; //instance_offset in instancing/skeleton buffer
+ uint instance_uniforms_ofs; //base offset in global buffer for instance variables
uint gi_offset; //GI information when using lightmapping (VCT or lightmap)
uint layer_mask;
};
-layout(set = 0, binding = 4, std430) buffer Instances {
+layout(set = 0, binding = 4, std430) restrict readonly buffer Instances {
InstanceData data[];
}
instances;
@@ -153,7 +153,7 @@ struct LightData { //this structure needs to be as packed as possible
uint color_specular; //rgb color, a specular (8 bit unorm)
uint cone_attenuation_angle; // attenuation and angle, (16bit float)
uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm)
- vec4 atlas_rect; // used for spot
+ vec4 atlas_rect; // rect in the shadow atlas
mat4 shadow_matrix;
float shadow_bias;
float shadow_normal_bias;
@@ -162,9 +162,10 @@ struct LightData { //this structure needs to be as packed as possible
float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
uint mask;
uint pad[2];
+ vec4 projector_rect; //projector rect in srgb decal atlas
};
-layout(set = 0, binding = 5, std430) buffer Lights {
+layout(set = 0, binding = 5, std430) restrict readonly buffer Lights {
LightData data[];
}
lights;
@@ -251,14 +252,45 @@ layout(set = 0, binding = 9) uniform texture3D gi_probe_textures[MAX_GI_PROBE_TE
#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1)
#define CLUSTER_COUNTER_MASK 0xfff
-layout(set = 0, binding = 10) uniform utexture3D cluster_texture;
+layout(set = 0, binding = 10) uniform texture2D decal_atlas;
+layout(set = 0, binding = 11) uniform texture2D decal_atlas_srgb;
+
+struct DecalData {
+ mat4 xform; //to decal transform
+ vec3 inv_extents;
+ float albedo_mix;
+ vec4 albedo_rect;
+ vec4 normal_rect;
+ vec4 orm_rect;
+ vec4 emission_rect;
+ vec4 modulate;
+ float emission_energy;
+ uint mask;
+ float upper_fade;
+ float lower_fade;
+ mat3x4 normal_xform;
+ vec3 normal;
+ float normal_fade;
+};
+
+layout(set = 0, binding = 12, std430) restrict readonly buffer Decals {
+ DecalData data[];
+}
+decals;
-layout(set = 0, binding = 11, std430) buffer ClusterData {
+layout(set = 0, binding = 13) uniform utexture3D cluster_texture;
+
+layout(set = 0, binding = 14, std430) restrict readonly buffer ClusterData {
uint indices[];
}
cluster_data;
-layout(set = 0, binding = 12) uniform texture2D directional_shadow_atlas;
+layout(set = 0, binding = 15) uniform texture2D directional_shadow_atlas;
+
+layout(set = 0, binding = 16, std430) restrict readonly buffer GlobalVariableData {
+ vec4 data[];
+}
+global_variables;
// decal atlas
@@ -290,7 +322,7 @@ layout(set = 3, binding = 4) uniform texture2D ao_buffer;
/* Set 4 Skeleton & Instancing (Multimesh) */
-layout(set = 4, binding = 0, std430) buffer Transforms {
+layout(set = 4, binding = 0, std430) restrict readonly buffer Transforms {
vec4 data[];
}
transforms;
diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/rasterizer_rd/shaders/sky.glsl
index c6c863ec60..536077980d 100644
--- a/servers/rendering/rasterizer_rd/shaders/sky.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/sky.glsl
@@ -58,6 +58,11 @@ params;
layout(set = 0, binding = 0) uniform sampler material_samplers[12];
+layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalVariableData {
+ vec4 data[];
+}
+global_variables;
+
#ifdef USE_MATERIAL_UNIFORMS
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
/* clang-format off */
@@ -96,9 +101,8 @@ layout(set = 2, binding = 2) uniform texture2D quarter_res;
#endif
struct DirectionalLightData {
- vec3 direction;
- float energy;
- vec3 color;
+ vec4 direction_energy;
+ vec4 color_size;
bool enabled;
};