summaryrefslogtreecommitdiffstats
path: root/servers/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering')
-rw-r--r--servers/rendering/dummy/rasterizer_canvas_dummy.h2
-rw-r--r--servers/rendering/dummy/storage/particles_storage.h3
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp18
-rw-r--r--servers/rendering/renderer_canvas_cull.h7
-rw-r--r--servers/rendering/renderer_canvas_render.h5
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp6
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp30
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h5
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp1
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h2
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp236
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h52
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp3
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h2
-rw-r--r--servers/rendering/renderer_rd/pipeline_cache_rd.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp51
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h6
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl47
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl5
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl167
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl7
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl124
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl40
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/skeleton.glsl28
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp222
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h27
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp50
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h18
-rw-r--r--servers/rendering/renderer_scene_cull.cpp3
-rw-r--r--servers/rendering/rendering_device.cpp2
-rw-r--r--servers/rendering/rendering_device.h4
-rw-r--r--servers/rendering/rendering_server_default.h6
-rw-r--r--servers/rendering/shader_language.cpp4
-rw-r--r--servers/rendering/shader_types.cpp6
-rw-r--r--servers/rendering/storage/particles_storage.h3
38 files changed, 847 insertions, 355 deletions
diff --git a/servers/rendering/dummy/rasterizer_canvas_dummy.h b/servers/rendering/dummy/rasterizer_canvas_dummy.h
index 455a669277..862b941a73 100644
--- a/servers/rendering/dummy/rasterizer_canvas_dummy.h
+++ b/servers/rendering/dummy/rasterizer_canvas_dummy.h
@@ -55,6 +55,8 @@ public:
bool free(RID p_rid) override { return true; }
void update() override {}
+ virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) override {}
+
RasterizerCanvasDummy() {}
~RasterizerCanvasDummy() {}
};
diff --git a/servers/rendering/dummy/storage/particles_storage.h b/servers/rendering/dummy/storage/particles_storage.h
index a40c96a8f5..33dad3f2f4 100644
--- a/servers/rendering/dummy/storage/particles_storage.h
+++ b/servers/rendering/dummy/storage/particles_storage.h
@@ -47,6 +47,7 @@ public:
virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override {}
virtual void particles_set_emitting(RID p_particles, bool p_emitting) override {}
virtual void particles_set_amount(RID p_particles, int p_amount) override {}
+ virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) override {}
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override {}
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override {}
virtual void particles_set_pre_process_time(RID p_particles, double p_time) override {}
@@ -81,6 +82,8 @@ public:
virtual AABB particles_get_aabb(RID p_particles) const override { return AABB(); }
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override {}
+ virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) override {}
+ virtual void particles_set_interp_to_end(RID p_particles, float p_interp) override {}
virtual bool particles_get_emitting(RID p_particles) override { return false; }
virtual int particles_get_draw_passes(RID p_particles) const override { return 0; }
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index d6040e8820..c5206017f7 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -30,6 +30,7 @@
#include "renderer_canvas_cull.h"
+#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
#include "renderer_viewport.h"
#include "rendering_server_default.h"
@@ -1557,6 +1558,11 @@ void RendererCanvasCull::canvas_item_clear(RID p_item) {
ERR_FAIL_NULL(canvas_item);
canvas_item->clear();
+#ifdef DEBUG_ENABLED
+ if (debug_redraw) {
+ canvas_item->debug_redraw_time = debug_redraw_time;
+ }
+#endif
}
void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) {
@@ -1612,6 +1618,15 @@ void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_
}
}
+void RendererCanvasCull::canvas_item_set_debug_redraw(bool p_enabled) {
+ debug_redraw = p_enabled;
+ RSG::canvas_render->set_debug_redraw(p_enabled, debug_redraw_time, debug_redraw_color);
+}
+
+bool RendererCanvasCull::canvas_item_get_debug_redraw() const {
+ return debug_redraw;
+}
+
void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_NULL(canvas_item);
@@ -2151,6 +2166,9 @@ RendererCanvasCull::RendererCanvasCull() {
z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
disable_scale = false;
+
+ debug_redraw_time = GLOBAL_DEF("debug/canvas_items/debug_redraw_time", 1.0);
+ debug_redraw_color = GLOBAL_DEF("debug/canvas_items/debug_redraw_color", Color(1.0, 0.2, 0.2, 0.5));
}
RendererCanvasCull::~RendererCanvasCull() {
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index 4f11d2c7b1..0f51abbb26 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -174,6 +174,10 @@ public:
bool sdf_used = false;
bool snapping_2d_transforms_to_pixel = false;
+ bool debug_redraw = false;
+ double debug_redraw_time = 0;
+ Color debug_redraw_color;
+
PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator;
SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list;
@@ -260,6 +264,9 @@ public:
void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false);
+ void canvas_item_set_debug_redraw(bool p_enabled);
+ bool canvas_item_get_debug_redraw() const;
+
RID canvas_light_allocate();
void canvas_light_initialize(RID p_rid);
diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h
index c30e53c29e..ef4de9ce54 100644
--- a/servers/rendering/renderer_canvas_render.h
+++ b/servers/rendering/renderer_canvas_render.h
@@ -358,6 +358,9 @@ public:
Command *last_command = nullptr;
Vector<CommandBlock> blocks;
uint32_t current_block;
+#ifdef DEBUG_ENABLED
+ mutable double debug_redraw_time = 0;
+#endif
template <class T>
T *alloc_command() {
@@ -517,6 +520,8 @@ public:
virtual bool free(RID p_rid) = 0;
virtual void update() = 0;
+ virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) = 0;
+
RendererCanvasRender() { singleton = this; }
virtual ~RendererCanvasRender() {}
};
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 5e1014e0de..7d4eb0e038 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -228,7 +228,7 @@ void Fog::init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_lay
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_DISABLE;
- actions.global_buffer_array_variable = "global_variables.data";
+ actions.global_buffer_array_variable = "global_shader_uniforms.data";
volumetric_fog.compiler.initialize(actions);
}
@@ -543,7 +543,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
if (p_cam_projection.is_orthogonal()) {
fog_near_size = fog_far_size;
} else {
- fog_near_size = Vector2();
+ fog_near_size = frustum_near_size.max(Vector2(0.001, 0.001));
}
params.fog_frustum_size_begin[0] = fog_near_size.x;
@@ -1002,7 +1002,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
if (p_cam_projection.is_orthogonal()) {
fog_near_size = fog_far_size;
} else {
- fog_near_size = Vector2();
+ fog_near_size = frustum_near_size.max(Vector2(0.001, 0.001));
}
params.fog_frustum_size_begin[0] = fog_near_size.x;
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index ece3b5597d..efec3b5072 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -728,7 +728,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i
RendererRD::MaterialStorage::store_transform(inst->prev_transform, instance_data.prev_transform);
#ifdef REAL_T_IS_DOUBLE
- // Split the origin into two components, the float approximation and the missing precision
+ // Split the origin into two components, the float approximation and the missing precision.
// In the shader we will combine these back together to restore the lost precision.
RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &instance_data.transform[12], &instance_data.transform[3]);
RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &instance_data.transform[13], &instance_data.transform[7]);
@@ -748,6 +748,28 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i
instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
+ AABB surface_aabb = AABB(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0));
+ uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(surface->surface);
+ Vector4 uv_scale = Vector4(0.0, 0.0, 0.0, 0.0);
+
+ if (format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ surface_aabb = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_aabb(surface->surface);
+ uv_scale = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_uv_scale(surface->surface);
+ }
+
+ instance_data.compressed_aabb_position[0] = surface_aabb.position.x;
+ instance_data.compressed_aabb_position[1] = surface_aabb.position.y;
+ instance_data.compressed_aabb_position[2] = surface_aabb.position.z;
+
+ instance_data.compressed_aabb_size[0] = surface_aabb.size.x;
+ instance_data.compressed_aabb_size[1] = surface_aabb.size.y;
+ instance_data.compressed_aabb_size[2] = surface_aabb.size.z;
+
+ instance_data.uv_scale[0] = uv_scale.x;
+ instance_data.uv_scale[1] = uv_scale.y;
+ instance_data.uv_scale[2] = uv_scale.z;
+ instance_data.uv_scale[3] = uv_scale.w;
+
bool cant_repeat = instance_data.flags & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid();
if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2 && inst->mirror == prev_surface->owner->mirror && repeats < RenderElementInfo::MAX_REPEATS) {
@@ -3617,7 +3639,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
SceneShaderForwardClustered::MaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
- if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK && !p_material->shader_data->uses_point_size) {
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK && !p_material->shader_data->uses_point_size && !p_material->shader_data->uses_world_coordinates) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
material_shadow = static_cast<SceneShaderForwardClustered::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
@@ -3942,7 +3964,7 @@ RenderGeometryInstance *RenderForwardClustered::geometry_instance_create(RID p_b
return ginstance;
}
-void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) {
+void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
uint64_t frame = RSG::rasterizer->get_frame_number();
if (frame != prev_transform_change_frame) {
prev_transform = transform;
@@ -3950,7 +3972,7 @@ void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(con
prev_transform_dirty = true;
}
- RenderGeometryInstanceBase::set_transform(p_transform, p_aabb, p_transformed_aabbb);
+ RenderGeometryInstanceBase::set_transform(p_transform, p_aabb, p_transformed_aabb);
}
void RenderForwardClustered::GeometryInstanceForwardClustered::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 6955d4f6ef..46deb30cde 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -298,6 +298,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index)
uint32_t layer_mask;
float lightmap_uv_scale[4];
+ float compressed_aabb_position[4];
+ float compressed_aabb_size[4];
+ float uv_scale[4];
};
UBO ubo;
@@ -479,7 +482,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
virtual void _mark_dirty() override;
- virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override;
+ virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override;
virtual void set_lightmap_capture(const Color *p_sh9) override;
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 7e8dc358d0..9676474a66 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -105,6 +105,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
actions.render_mode_flags["unshaded"] = &unshaded;
actions.render_mode_flags["wireframe"] = &wireframe;
actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
+ actions.render_mode_flags["world_vertex_coords"] = &uses_world_coordinates;
actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index 761b74defa..0739cd9f86 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -142,7 +142,7 @@ public:
bool valid = false;
RID version;
- uint32_t vertex_input_mask = 0;
+ uint64_t vertex_input_mask = 0;
PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_VERSION_MAX];
PipelineCacheRD color_pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_COLOR_PASS_FLAG_COUNT];
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 4706249142..8a672d8628 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -68,53 +68,40 @@ void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::For
forward_id_allocators[p_type].map[p_id] = p_index;
}
-void RenderForwardMobile::ForwardIDStorageMobile::fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) {
- // first zero out our indices
+void RenderForwardMobile::fill_push_constant_instance_indices(SceneState::InstanceData *p_instance_data, const GeometryInstanceForwardMobile *p_instance) {
+ // First zero out our indices.
- p_push_constant->omni_lights[0] = 0xFFFFFFFF;
- p_push_constant->omni_lights[1] = 0xFFFFFFFF;
+ p_instance_data->omni_lights[0] = 0xFFFFFFFF;
+ p_instance_data->omni_lights[1] = 0xFFFFFFFF;
- p_push_constant->spot_lights[0] = 0xFFFFFFFF;
- p_push_constant->spot_lights[1] = 0xFFFFFFFF;
+ p_instance_data->spot_lights[0] = 0xFFFFFFFF;
+ p_instance_data->spot_lights[1] = 0xFFFFFFFF;
- p_push_constant->decals[0] = 0xFFFFFFFF;
- p_push_constant->decals[1] = 0xFFFFFFFF;
+ p_instance_data->decals[0] = 0xFFFFFFFF;
+ p_instance_data->decals[1] = 0xFFFFFFFF;
- p_push_constant->reflection_probes[0] = 0xFFFFFFFF;
- p_push_constant->reflection_probes[1] = 0xFFFFFFFF;
-
- if (p_instance->omni_light_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
- }
- if (p_instance->spot_light_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
- }
- if (p_instance->reflection_probe_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
- }
- if (p_instance->decals_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
- }
+ p_instance_data->reflection_probes[0] = 0xFFFFFFFF;
+ p_instance_data->reflection_probes[1] = 0xFFFFFFFF;
for (uint32_t i = 0; i < MAX_RDL_CULL; i++) {
uint32_t ofs = i < 4 ? 0 : 1;
uint32_t shift = (i & 0x3) << 3;
uint32_t mask = ~(0xFF << shift);
if (i < p_instance->omni_light_count) {
- p_push_constant->omni_lights[ofs] &= mask;
- p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
+ p_instance_data->omni_lights[ofs] &= mask;
+ p_instance_data->omni_lights[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
}
if (i < p_instance->spot_light_count) {
- p_push_constant->spot_lights[ofs] &= mask;
- p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
+ p_instance_data->spot_lights[ofs] &= mask;
+ p_instance_data->spot_lights[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
}
if (i < p_instance->decals_count) {
- p_push_constant->decals[ofs] &= mask;
- p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
+ p_instance_data->decals[ofs] &= mask;
+ p_instance_data->decals[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
}
if (i < p_instance->reflection_probe_count) {
- p_push_constant->reflection_probes[ofs] &= mask;
- p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
+ p_instance_data->reflection_probes[ofs] &= mask;
+ p_instance_data->reflection_probes[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
}
}
}
@@ -367,6 +354,18 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
}
{
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ RID instance_buffer = scene_state.instance_buffer[p_render_list];
+ if (instance_buffer == RID()) {
+ instance_buffer = scene_shader.default_vec4_xform_buffer; // Any buffer will do since its not used.
+ }
+ u.append_id(instance_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
RID radiance_texture;
if (p_radiance_texture.is_valid()) {
radiance_texture = p_radiance_texture;
@@ -461,15 +460,6 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
uniforms.push_back(u);
}
-
- {
- RD::Uniform u;
- u.binding = 8;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer;
- u.append_id(cb);
- uniforms.push_back(u);
- }
*/
{
@@ -682,8 +672,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
- _fill_element_info(RENDER_LIST_OPAQUE);
- _fill_element_info(RENDER_LIST_ALPHA);
+ _fill_instance_data(RENDER_LIST_OPAQUE);
+ _fill_instance_data(RENDER_LIST_ALPHA);
if (p_render_data->render_info) {
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_render_data->instances->size();
@@ -1290,7 +1280,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, true);
uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
- _fill_element_info(RENDER_LIST_SECONDARY, render_list_from, render_list_size);
+ _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size);
{
//regular forward for now
@@ -1373,7 +1363,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_element_info(RENDER_LIST_SECONDARY);
+ _fill_instance_data(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@@ -1418,7 +1408,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_element_info(RENDER_LIST_SECONDARY);
+ _fill_instance_data(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@@ -1499,7 +1489,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_element_info(RENDER_LIST_SECONDARY);
+ _fill_instance_data(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@@ -1691,6 +1681,91 @@ RID RenderForwardMobile::_render_buffers_get_velocity_texture(Ref<RenderSceneBuf
return RID();
}
+void RenderForwardMobile::_update_instance_data_buffer(RenderListType p_render_list) {
+ if (scene_state.instance_data[p_render_list].size() > 0) {
+ if (scene_state.instance_buffer[p_render_list] == RID() || scene_state.instance_buffer_size[p_render_list] < scene_state.instance_data[p_render_list].size()) {
+ if (scene_state.instance_buffer[p_render_list] != RID()) {
+ RD::get_singleton()->free(scene_state.instance_buffer[p_render_list]);
+ }
+ uint32_t new_size = nearest_power_of_2_templated(MAX(uint64_t(INSTANCE_DATA_BUFFER_MIN_SIZE), scene_state.instance_data[p_render_list].size()));
+ scene_state.instance_buffer[p_render_list] = RD::get_singleton()->storage_buffer_create(new_size * sizeof(SceneState::InstanceData));
+ scene_state.instance_buffer_size[p_render_list] = new_size;
+ }
+ RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER);
+ }
+}
+
+void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
+ RenderList *rl = &render_list[p_render_list];
+ uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
+
+ scene_state.instance_data[p_render_list].resize(p_offset + element_total);
+ rl->element_info.resize(p_offset + element_total);
+
+ for (uint32_t i = 0; i < element_total; i++) {
+ GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset];
+ GeometryInstanceForwardMobile *inst = surface->owner;
+
+ SceneState::InstanceData &instance_data = scene_state.instance_data[p_render_list][i + p_offset];
+
+ if (inst->store_transform_cache) {
+ RendererRD::MaterialStorage::store_transform(inst->transform, instance_data.transform);
+
+#ifdef REAL_T_IS_DOUBLE
+ // Split the origin into two components, the float approximation and the missing precision.
+ // In the shader we will combine these back together to restore the lost precision.
+ RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &instance_data.transform[12], &instance_data.transform[3]);
+ RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &instance_data.transform[13], &instance_data.transform[7]);
+ RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &instance_data.transform[14], &instance_data.transform[11]);
+#endif
+ } else {
+ RendererRD::MaterialStorage::store_transform(Transform3D(), instance_data.transform);
+ }
+
+ instance_data.flags = inst->flags_cache;
+ instance_data.gi_offset = inst->gi_offset_cache;
+ instance_data.layer_mask = inst->layer_mask;
+ instance_data.instance_uniforms_ofs = uint32_t(inst->shader_uniforms_offset);
+ instance_data.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x;
+ instance_data.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y;
+ instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
+ instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
+
+ AABB surface_aabb = AABB(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0));
+ uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(surface->surface);
+ Vector4 uv_scale = Vector4(0.0, 0.0, 0.0, 0.0);
+
+ if (format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ surface_aabb = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_aabb(surface->surface);
+ uv_scale = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_uv_scale(surface->surface);
+ }
+
+ fill_push_constant_instance_indices(&instance_data, inst);
+
+ instance_data.compressed_aabb_position[0] = surface_aabb.position.x;
+ instance_data.compressed_aabb_position[1] = surface_aabb.position.y;
+ instance_data.compressed_aabb_position[2] = surface_aabb.position.z;
+
+ instance_data.compressed_aabb_size[0] = surface_aabb.size.x;
+ instance_data.compressed_aabb_size[1] = surface_aabb.size.y;
+ instance_data.compressed_aabb_size[2] = surface_aabb.size.z;
+
+ instance_data.uv_scale[0] = uv_scale.x;
+ instance_data.uv_scale[1] = uv_scale.y;
+ instance_data.uv_scale[2] = uv_scale.z;
+ instance_data.uv_scale[3] = uv_scale.w;
+
+ RenderElementInfo &element_info = rl->element_info[p_offset + i];
+
+ element_info.lod_index = surface->lod_index;
+ element_info.uses_lightmap = surface->sort.uses_lightmap;
+ }
+
+ if (p_update_buffer) {
+ _update_instance_data_buffer(p_render_list);
+ }
+}
+
_FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) {
static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 };
static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
@@ -1911,21 +1986,6 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers, false);
}
-void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) {
- RenderList *rl = &render_list[p_render_list];
- uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
-
- rl->element_info.resize(p_offset + element_total);
-
- for (uint32_t i = 0; i < element_total; i++) {
- GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset];
- RenderElementInfo &element_info = rl->element_info[p_offset + i];
-
- element_info.lod_index = surface->lod_index;
- element_info.uses_lightmap = surface->sort.uses_lightmap;
- }
-}
-
/// RENDERING ///
void RenderForwardMobile::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
@@ -2011,39 +2071,17 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
uint32_t base_spec_constants = p_params->spec_constant_base_flags;
- // GeometryInstanceForwardMobile::PushConstant push_constant = inst->push_constant;
- GeometryInstanceForwardMobile::PushConstant push_constant;
-
- if (inst->store_transform_cache) {
- RendererRD::MaterialStorage::store_transform(inst->transform, push_constant.transform);
+ SceneState::PushConstant push_constant;
+ push_constant.base_index = i + p_params->element_offset;
-#ifdef REAL_T_IS_DOUBLE
- // Split the origin into two components, the float approximation and the missing precision
- // In the shader we will combine these back together to restore the lost precision.
- RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &push_constant.transform[12], &push_constant.transform[3]);
- RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &push_constant.transform[13], &push_constant.transform[7]);
- RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &push_constant.transform[14], &push_constant.transform[11]);
-#endif
+ if constexpr (p_pass_mode == PASS_MODE_DEPTH_MATERIAL) {
+ push_constant.uv_offset[0] = p_params->uv_offset.x;
+ push_constant.uv_offset[1] = p_params->uv_offset.y;
} else {
- RendererRD::MaterialStorage::store_transform(Transform3D(), push_constant.transform);
+ push_constant.uv_offset[0] = 0.0;
+ push_constant.uv_offset[1] = 0.0;
}
- push_constant.flags = inst->flags_cache;
- push_constant.gi_offset = inst->gi_offset_cache;
- push_constant.layer_mask = inst->layer_mask;
- push_constant.instance_uniforms_ofs = uint32_t(inst->shader_uniforms_offset);
-
- if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) {
- // abuse lightmap_uv_scale[0] here, should not be needed here
- push_constant.lightmap_uv_scale[0] = p_params->uv_offset.x;
- push_constant.lightmap_uv_scale[1] = p_params->uv_offset.y;
- } else {
- push_constant.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x;
- push_constant.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y;
- push_constant.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
- push_constant.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
- };
-
RID material_uniform_set;
SceneShaderForwardMobile::ShaderData *shader;
void *mesh_surface;
@@ -2060,7 +2098,19 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
if (inst->use_soft_shadow) {
base_spec_constants |= 1 << SPEC_CONSTANT_USING_SOFT_SHADOWS;
}
- forward_id_storage_mobile->fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst);
+
+ if (inst->omni_light_count == 0) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
+ }
+ if (inst->spot_light_count == 0) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
+ }
+ if (inst->reflection_probe_count == 0) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
+ }
+ if (inst->decals_count == 0) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
+ }
#ifdef DEBUG_ENABLED
if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
@@ -2184,7 +2234,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
prev_material_uniform_set = material_uniform_set;
}
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(GeometryInstanceForwardMobile::PushConstant));
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant));
uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : 1;
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) {
@@ -2376,7 +2426,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
SceneShaderForwardMobile::MaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
- if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing) {
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing && !p_material->shader_data->uses_world_coordinates) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
material_shadow = static_cast<SceneShaderForwardMobile::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index 65723e5aa5..50bf83b612 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -202,9 +202,9 @@ private:
void _update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers);
+ void _update_instance_data_buffer(RenderListType p_render_list);
+ void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
- void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1);
- // void _update_instance_data_buffer(RenderListType p_render_list);
void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
@@ -229,6 +229,32 @@ private:
struct SceneState {
LocalVector<RID> uniform_buffers;
+ struct PushConstant {
+ float uv_offset[2];
+ uint32_t base_index;
+ uint32_t pad;
+ };
+
+ struct InstanceData {
+ float transform[16];
+ uint32_t flags;
+ uint32_t instance_uniforms_ofs; // Base offset in global buffer for instance variables.
+ uint32_t gi_offset; // GI information when using lightmapping (VCT or lightmap index).
+ uint32_t layer_mask = 1;
+ float lightmap_uv_scale[4]; // Doubles as uv_offset when needed.
+ uint32_t reflection_probes[2]; // Packed reflection probes.
+ uint32_t omni_lights[2]; // Packed omni lights.
+ uint32_t spot_lights[2]; // Packed spot lights.
+ uint32_t decals[2]; // Packed spot lights.
+ float compressed_aabb_position[4];
+ float compressed_aabb_size[4];
+ float uv_scale[4];
+ };
+
+ RID instance_buffer[RENDER_LIST_MAX];
+ uint32_t instance_buffer_size[RENDER_LIST_MAX] = { 0, 0, 0 };
+ LocalVector<InstanceData> instance_data[RENDER_LIST_MAX];
+
// !BAS! We need to change lightmaps, we're not going to do this with a buffer but pushing the used lightmap in
LightmapData lightmaps[MAX_LIGHTMAPS];
RID lightmap_ids[MAX_LIGHTMAPS];
@@ -447,27 +473,11 @@ protected:
class GeometryInstanceForwardMobile : public RenderGeometryInstanceBase {
public:
- // this structure maps to our push constant in our shader and is populated right before our draw call
- struct PushConstant {
- float transform[16];
- uint32_t flags;
- uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables
- uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index)
- uint32_t layer_mask = 1;
- float lightmap_uv_scale[4]; // doubles as uv_offset when needed
- uint32_t reflection_probes[2]; // packed reflection probes
- uint32_t omni_lights[2]; // packed omni lights
- uint32_t spot_lights[2]; // packed spot lights
- uint32_t decals[2]; // packed spot lights
- };
-
- // PushConstant push_constant; // we populate this from our instance data
-
//used during rendering
RID transforms_uniform_set;
bool use_projector = false;
bool use_soft_shadow = false;
- bool store_transform_cache = true; // if true we copy our transform into our PushConstant, if false we use our transforms UBO and clear our PushConstants transform
+ bool store_transform_cache = true; // If true we copy our transform into our per-draw buffer, if false we use our transforms UBO and clear our per-draw transform.
uint32_t instance_count = 0;
uint32_t trail_steps = 1;
@@ -534,12 +544,12 @@ protected:
virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) override;
virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) override;
virtual bool uses_forward_ids() const override { return true; }
-
- void fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance);
};
ForwardIDStorageMobile *forward_id_storage_mobile = nullptr;
+ void fill_push_constant_instance_indices(SceneState::InstanceData *p_instance_data, const GeometryInstanceForwardMobile *p_instance);
+
virtual RendererRD::ForwardIDStorage *create_forward_id_storage() override {
forward_id_storage_mobile = memnew(ForwardIDStorageMobile);
return forward_id_storage_mobile;
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index eeaff0ccb1..b2c0d4b1bd 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -106,6 +106,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
actions.render_mode_flags["unshaded"] = &unshaded;
actions.render_mode_flags["wireframe"] = &wireframe;
actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
+ actions.render_mode_flags["world_vertex_coords"] = &uses_world_coordinates;
actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
@@ -620,7 +621,7 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
actions.global_buffer_array_variable = "global_shader_uniforms.data";
- actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
+ actions.instance_uniform_index_variable = "instances.data[draw_call.instance_index].instance_uniforms_ofs";
actions.apply_luminance_multiplier = true; // apply luminance multiplier to screen texture
actions.check_multiview_samplers = RendererCompositorRD::get_singleton()->is_xr_enabled(); // Make sure we check sampling multiview textures.
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index 0b98746d06..5c76d89247 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -97,7 +97,7 @@ public:
bool valid = false;
RID version;
- uint32_t vertex_input_mask = 0;
+ uint64_t vertex_input_mask = 0;
PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h
index 52877109f7..2f1e79b397 100644
--- a/servers/rendering/renderer_rd/pipeline_cache_rd.h
+++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h
@@ -91,7 +91,7 @@ public:
return result;
}
- _FORCE_INLINE_ uint32_t get_vertex_input_mask() {
+ _FORCE_INLINE_ uint64_t get_vertex_input_mask() {
if (input_mask == 0) {
ERR_FAIL_COND_V(shader.is_null(), 0);
input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader);
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 3c23e68d72..ecf2c29956 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -485,7 +485,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
continue;
}
- push_constant.flags = base_flags | (push_constant.flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
+ push_constant.flags = base_flags | (push_constant.flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); // Reset on each command for safety, keep canvastexture binding config.
switch (c->type) {
case Item::Command::TYPE_RECT: {
@@ -894,7 +894,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface);
ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
- uint32_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask();
+ uint64_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask();
RID vertex_array;
RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID;
@@ -957,7 +957,48 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
c = c->next;
}
+#ifdef DEBUG_ENABLED
+ if (debug_redraw && p_item->debug_redraw_time > 0.0) {
+ Color dc = debug_redraw_color;
+ dc.a *= p_item->debug_redraw_time / debug_redraw_time;
+ RID pipeline = pipeline_variants->variants[PIPELINE_LIGHT_MODE_DISABLED][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
+
+ //bind textures
+
+ _bind_canvas_texture(p_draw_list, RID(), current_filter, current_repeat, last_texture, push_constant, texpixel_size);
+
+ Rect2 src_rect;
+ Rect2 dst_rect;
+
+ dst_rect = Rect2(Vector2(), p_item->rect.size);
+ src_rect = Rect2(0, 0, 1, 1);
+
+ push_constant.modulation[0] = dc.r;
+ push_constant.modulation[1] = dc.g;
+ push_constant.modulation[2] = dc.b;
+ push_constant.modulation[3] = dc.a;
+
+ push_constant.src_rect[0] = src_rect.position.x;
+ push_constant.src_rect[1] = src_rect.position.y;
+ push_constant.src_rect[2] = src_rect.size.width;
+ push_constant.src_rect[3] = src_rect.size.height;
+
+ push_constant.dst_rect[0] = dst_rect.position.x;
+ push_constant.dst_rect[1] = dst_rect.position.y;
+ push_constant.dst_rect[2] = dst_rect.size.width;
+ push_constant.dst_rect[3] = dst_rect.size.height;
+
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
+ RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
+ RD::get_singleton()->draw_list_draw(p_draw_list, true);
+
+ p_item->debug_redraw_time -= RSG::rasterizer->get_frame_delta_time();
+
+ RenderingServerDefault::redraw_request();
+ }
+#endif
if (current_clip && reclip) {
//will make it re-enable clipping if needed afterwards
current_clip = nullptr;
@@ -2742,6 +2783,12 @@ void RendererCanvasRenderRD::set_shadow_texture_size(int p_size) {
}
}
+void RendererCanvasRenderRD::set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) {
+ debug_redraw = p_enabled;
+ debug_redraw_time = p_time;
+ debug_redraw_color = p_color;
+}
+
RendererCanvasRenderRD::~RendererCanvasRenderRD() {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
//canvas state
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 4c8cbd1c9f..7dbcd903e6 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -418,6 +418,10 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer);
+ bool debug_redraw = false;
+ Color debug_redraw_color;
+ double debug_redraw_time = 1.0;
+
inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size, bool p_texture_is_data = false); //recursive, so regular inline used instead.
void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used);
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false);
@@ -450,6 +454,8 @@ public:
virtual void set_shadow_texture_size(int p_size);
+ void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color);
+
void set_time(double p_time);
void update();
bool free(RID p_rid);
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
index 1e01d94533..fecf70bd01 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
@@ -184,7 +184,7 @@ void main() {
vec4 test_normal_roughness = imageLoad(source_normal_roughness, test_pos);
vec3 test_normal = test_normal_roughness.xyz * 2.0 - 1.0;
test_normal = normalize(test_normal);
- test_normal.y = -test_normal.y; //because this code reads flipped
+ test_normal.y = -test_normal.y; // Because this code reads flipped.
if (dot(ray_dir, test_normal) < 0.001) {
// if depth was surpassed
@@ -203,6 +203,7 @@ void main() {
if (found) {
float margin_blend = 1.0;
+ vec2 final_pos = pos;
vec2 margin = vec2((params.screen_size.x + params.screen_size.y) * 0.05); // make a uniform margin
if (any(bvec4(lessThan(pos, vec2(0.0, 0.0)), greaterThan(pos, params.screen_size)))) {
@@ -219,16 +220,40 @@ void main() {
//margin_blend = 1.0;
}
- vec2 final_pos;
+ // Fade In / Fade Out
float grad = (steps_taken + 1.0) / float(params.num_steps);
float initial_fade = params.curve_fade_in == 0.0 ? 1.0 : pow(clamp(grad, 0.0, 1.0), params.curve_fade_in);
float fade = pow(clamp(1.0 - grad, 0.0, 1.0), params.distance_fade) * initial_fade;
+
+ // Ensure that precision errors do not introduce any fade. Even if it is just slightly below 1.0,
+ // strong specular light can leak through the reflection.
+ if (fade > 0.999) {
+ fade = 1.0;
+ }
+
// This is an ad-hoc term to fade out the SSR as roughness increases. Values used
// are meant to match the visual appearance of a ReflectionProbe.
float roughness_fade = smoothstep(0.4, 0.7, 1.0 - normal_roughness.w);
- final_pos = pos;
- vec4 final_color;
+ // Schlick term.
+ float metallic = texelFetch(source_metallic, ssC << 1, 0).w;
+
+ // F0 is the reflectance of normally incident light (perpendicular to the surface).
+ // Dielectric materials have a widely accepted default value of 0.04. We assume that metals reflect all light, so their F0 is 1.0.
+ float f0 = mix(0.04, 1.0, metallic);
+ float m = clamp(1.0 - dot(normal, -view_dir), 0.0, 1.0);
+ float m2 = m * m;
+ m = m2 * m2 * m; // pow(m,5)
+ float fresnel_term = f0 + (1.0 - f0) * m; // Fresnel Schlick term.
+
+ // The alpha value of final_color controls the blending with specular light in specular_merge.glsl.
+ // Note that the Fresnel term is multiplied with the RGB color instead of being a part of the alpha value.
+ // There is a key difference:
+ // - multiplying a term with RGB darkens the SSR light without introducing/taking away specular light.
+ // - combining a term into the Alpha value introduces specular light at the expense of the SSR light.
+ vec4 final_color = vec4(imageLoad(source_diffuse, ivec2(final_pos - 0.5)).rgb * fresnel_term, fade * margin_blend * roughness_fade);
+
+ imageStore(ssr_image, ssC, final_color);
#ifdef MODE_ROUGH
@@ -259,20 +284,6 @@ void main() {
#endif // MODE_ROUGH
- final_color = vec4(imageLoad(source_diffuse, ivec2(final_pos - 0.5)).rgb, fade * margin_blend * roughness_fade);
-
- // Schlick term.
- float metallic = texelFetch(source_metallic, ssC << 1, 0).w;
- // F0 is the reflectance of normally incident light (perpendicular to the surface).
- // Dielectric materials have a widely accepted default value of 0.04. We assume that metals reflect all light, so their F0 is 1.0.
- float f0 = mix(0.04, 1.0, metallic);
- float m = clamp(1.0 - dot(normal, -view_dir), 0.0, 1.0);
- float m2 = m * m;
- m = m2 * m2 * m; // pow(m,5)
- final_color.a *= f0 + (1.0 - f0) * m; // Fresnel Schlick term.
-
- imageStore(ssr_image, ssC, final_color);
-
} else {
#ifdef MODE_ROUGH
imageStore(blur_radius_image, ssC, vec4(0.0));
diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
index f961249dce..57b9a4c320 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
@@ -576,8 +576,9 @@ void main() {
float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation);
vec3 spot_dir = spot_lights.data[light_index].direction;
- float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle);
- float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle));
+ highp float cone_angle = spot_lights.data[light_index].cone_angle;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), cone_angle);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cone_angle));
attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation);
vec3 light = spot_lights.data[light_index].color;
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 878b629c25..8e6db7583e 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -10,21 +10,17 @@
/* INPUT ATTRIBS */
-layout(location = 0) in vec3 vertex_attrib;
+// Always contains vertex position in XYZ, can contain tangent angle in W.
+layout(location = 0) in vec4 vertex_angle_attrib;
//only for pure render depth when normal is not used
-#ifdef NORMAL_USED
-layout(location = 1) in vec2 normal_attrib;
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+// Contains Normal/Axis in RG, can contain tangent in BA.
+layout(location = 1) in vec4 axis_tangent_attrib;
#endif
-#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED))
-#define TANGENT_USED
-#endif
-
-#ifdef TANGENT_USED
-layout(location = 2) in vec2 tangent_attrib;
-#endif
+// Location 2 is unused.
#if defined(COLOR_USED)
layout(location = 3) in vec4 color_attrib;
@@ -63,15 +59,12 @@ layout(location = 11) in vec4 weight_attrib;
#endif
#ifdef MOTION_VECTORS
-layout(location = 12) in vec3 previous_vertex_attrib;
+layout(location = 12) in vec4 previous_vertex_attrib;
-#ifdef NORMAL_USED
-layout(location = 13) in vec2 previous_normal_attrib;
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+layout(location = 13) in vec4 previous_normal_attrib;
#endif
-#ifdef TANGENT_USED
-layout(location = 14) in vec2 previous_tangent_attrib;
-#endif
#endif // MOTION_VECTORS
vec3 oct_to_vec3(vec2 e) {
@@ -81,6 +74,16 @@ vec3 oct_to_vec3(vec2 e) {
return normalize(v);
}
+void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) {
+ float c = cos(angle);
+ float s = sin(angle);
+ vec3 omc_axis = (1.0 - c) * axis;
+ vec3 s_axis = s * axis;
+ tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y);
+ binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x);
+ normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c);
+}
+
/* Varyings */
layout(location = 0) out vec3 vertex_interp;
@@ -179,10 +182,11 @@ vec3 double_add_vec3(vec3 base_a, vec3 prec_a, vec3 base_b, vec3 prec_b, out vec
void vertex_shader(vec3 vertex_input,
#ifdef NORMAL_USED
- in vec2 normal_input,
+ in vec3 normal_input,
#endif
#ifdef TANGENT_USED
- in vec2 tangent_input,
+ in vec3 tangent_input,
+ in vec3 binormal_input,
#endif
in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
vec4 instance_custom = vec4(0.0);
@@ -314,14 +318,12 @@ void vertex_shader(vec3 vertex_input,
vec3 vertex = vertex_input;
#ifdef NORMAL_USED
- vec3 normal = oct_to_vec3(normal_input * 2.0 - 1.0);
+ vec3 normal = normal_input;
#endif
#ifdef TANGENT_USED
- vec2 signed_tangent_input = tangent_input * 2.0 - 1.0;
- vec3 tangent = oct_to_vec3(vec2(signed_tangent_input.x, abs(signed_tangent_input.y) * 2.0 - 1.0));
- float binormalf = sign(signed_tangent_input.y);
- vec3 binormal = normalize(cross(normal, tangent) * binormalf);
+ vec3 tangent = tangent_input;
+ vec3 binormal = binormal_input;
#endif
#ifdef UV_USED
@@ -332,6 +334,17 @@ void vertex_shader(vec3 vertex_input,
uv2_interp = uv2_attrib;
#endif
+ vec4 uv_scale = instances.data[instance_index].uv_scale;
+
+ if (uv_scale != vec4(0.0)) { // Compression enabled
+#ifdef UV_USED
+ uv_interp = (uv_interp - 0.5) * uv_scale.xy;
+#endif
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ uv2_interp = (uv2_interp - 0.5) * uv_scale.zw;
+#endif
+ }
+
#ifdef OVERRIDE_POSITION
vec4 position;
#endif
@@ -398,13 +411,12 @@ void vertex_shader(vec3 vertex_input,
normal = modelview_normal * normal;
#endif
-#endif
-
#ifdef TANGENT_USED
binormal = modelview_normal * binormal;
tangent = modelview_normal * tangent;
#endif
+#endif // !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
//using world coordinates
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
@@ -484,6 +496,46 @@ void vertex_shader(vec3 vertex_input,
#endif
}
+void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position, vec3 p_compressed_aabb_size,
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+ vec4 p_normal_in,
+#ifdef NORMAL_USED
+ out vec3 r_normal,
+#endif
+ out vec3 r_tangent,
+ out vec3 r_binormal,
+#endif
+ out vec3 r_vertex) {
+
+ r_vertex = p_vertex_in.xyz * p_compressed_aabb_size + p_compressed_aabb_position;
+#ifdef NORMAL_USED
+ r_normal = oct_to_vec3(p_normal_in.xy * 2.0 - 1.0);
+#endif
+
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+
+ float binormal_sign;
+
+ // This works because the oct value (0, 1) maps onto (0, 0, -1) which encodes to (1, 1).
+ // Accordingly, if p_normal_in.z contains octahedral values, it won't equal (0, 1).
+ if (p_normal_in.z > 0.0 || p_normal_in.w < 1.0) {
+ // Uncompressed format.
+ vec2 signed_tangent_attrib = p_normal_in.zw * 2.0 - 1.0;
+ r_tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
+ binormal_sign = sign(signed_tangent_attrib.y);
+ r_binormal = normalize(cross(r_normal, r_tangent) * binormal_sign);
+ } else {
+ // Compressed format.
+ float angle = p_vertex_in.w;
+ binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller.
+ angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably.
+ vec3 axis = r_normal;
+ axis_angle_to_tbn(axis, angle, r_tangent, r_binormal, r_normal);
+ r_binormal *= binormal_sign;
+ }
+#endif
+}
+
void main() {
uint instance_index = draw_call.instance_index;
@@ -498,13 +550,38 @@ void main() {
#ifdef MOTION_VECTORS
// Previous vertex.
- global_time = scene_data_block.prev_data.time;
- vertex_shader(previous_vertex_attrib,
+ vec3 prev_vertex;
#ifdef NORMAL_USED
+ vec3 prev_normal;
+#endif
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+ vec3 prev_tangent;
+ vec3 prev_binormal;
+#endif
+
+ _unpack_vertex_attributes(
+ previous_vertex_attrib,
+ instances.data[instance_index].compressed_aabb_position_pad.xyz,
+ instances.data[instance_index].compressed_aabb_size_pad.xyz,
+
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
previous_normal_attrib,
+#ifdef NORMAL_USED
+ prev_normal,
+#endif
+ prev_tangent,
+ prev_binormal,
+#endif
+ prev_vertex);
+
+ global_time = scene_data_block.prev_data.time;
+ vertex_shader(prev_vertex,
+#ifdef NORMAL_USED
+ prev_normal,
#endif
#ifdef TANGENT_USED
- previous_tangent_attrib,
+ prev_tangent,
+ prev_binormal,
#endif
instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
#else
@@ -512,14 +589,38 @@ void main() {
vec4 screen_position;
#endif
+ vec3 vertex;
+#ifdef NORMAL_USED
+ vec3 normal;
+#endif
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+ vec3 tangent;
+ vec3 binormal;
+#endif
+
+ _unpack_vertex_attributes(
+ vertex_angle_attrib,
+ instances.data[instance_index].compressed_aabb_position_pad.xyz,
+ instances.data[instance_index].compressed_aabb_size_pad.xyz,
+#if defined(NORMAL_USED) || defined(TANGENT_USED)
+ axis_tangent_attrib,
+#ifdef NORMAL_USED
+ normal,
+#endif
+ tangent,
+ binormal,
+#endif
+ vertex);
+
// Current vertex.
global_time = scene_data_block.data.time;
- vertex_shader(vertex_attrib,
+ vertex_shader(vertex,
#ifdef NORMAL_USED
- normal_attrib,
+ normal,
#endif
#ifdef TANGENT_USED
- tangent_attrib,
+ tangent,
+ binormal,
#endif
instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
}
@@ -575,10 +676,6 @@ layout(location = 3) in vec2 uv_interp;
layout(location = 4) in vec2 uv2_interp;
#endif
-#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED))
-#define TANGENT_USED
-#endif
-
#ifdef TANGENT_USED
layout(location = 5) in vec3 tangent_interp;
layout(location = 6) in vec3 binormal_interp;
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
index 8ead363f3b..bfd87b4ea1 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
@@ -28,6 +28,10 @@
#endif
#endif
+#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED))
+#define TANGENT_USED
+#endif
+
layout(push_constant, std430) uniform DrawCall {
uint instance_index;
uint uv_offset;
@@ -211,6 +215,9 @@ struct InstanceData {
uint gi_offset; //GI information when using lightmapping (VCT or lightmap index)
uint layer_mask;
vec4 lightmap_uv_scale;
+ vec4 compressed_aabb_position_pad; // Only .xyz is used. .w is padding.
+ vec4 compressed_aabb_size_pad; // Only .xyz is used. .w is padding.
+ vec4 uv_scale;
};
layout(set = 1, binding = 2, std430) buffer restrict readonly InstanceDataBuffer {
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index 7f6a9a50e5..a9e9a617d6 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -11,17 +11,17 @@
/* INPUT ATTRIBS */
-layout(location = 0) in vec3 vertex_attrib;
+// Always contains vertex position in XYZ, can contain tangent angle in W.
+layout(location = 0) in vec4 vertex_angle_attrib;
//only for pure render depth when normal is not used
#ifdef NORMAL_USED
-layout(location = 1) in vec2 normal_attrib;
+// Contains Normal/Axis in RG, can contain tangent in BA.
+layout(location = 1) in vec4 axis_tangent_attrib;
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 2) in vec2 tangent_attrib;
-#endif
+// Location 2 is unused.
#if defined(COLOR_USED)
layout(location = 3) in vec4 color_attrib;
@@ -66,6 +66,16 @@ vec3 oct_to_vec3(vec2 e) {
return normalize(v);
}
+void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) {
+ float c = cos(angle);
+ float s = sin(angle);
+ vec3 omc_axis = (1.0 - c) * axis;
+ vec3 s_axis = s * axis;
+ tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y);
+ binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x);
+ normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c);
+}
+
/* Varyings */
layout(location = 0) highp out vec3 vertex_interp;
@@ -162,9 +172,9 @@ void main() {
color_interp = color_attrib;
#endif
- bool is_multimesh = bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH);
+ bool is_multimesh = bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH);
- mat4 model_matrix = draw_call.transform;
+ mat4 model_matrix = instances.data[draw_call.instance_index].transform;
mat4 inv_view_matrix = scene_data.inv_view_matrix;
#ifdef USE_DOUBLE_PRECISION
vec3 model_precision = vec3(model_matrix[0][3], model_matrix[1][3], model_matrix[2][3]);
@@ -178,7 +188,7 @@ void main() {
#endif
mat3 model_normal_matrix;
- if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
model_normal_matrix = transpose(inverse(mat3(model_matrix)));
} else {
model_normal_matrix = mat3(model_matrix);
@@ -191,7 +201,7 @@ void main() {
//multimesh, instances are for it
#ifdef USE_PARTICLE_TRAILS
- uint trail_size = (draw_call.flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK;
+ uint trail_size = (instances.data[draw_call.instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK;
uint stride = 3 + 1 + 1; //particles always uses this format
uint offset = trail_size * stride * gl_InstanceIndex;
@@ -238,22 +248,22 @@ void main() {
uint stride = 0;
{
//TODO implement a small lookup table for the stride
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
stride += 2;
} else {
stride += 3;
}
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
stride += 1;
}
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
stride += 1;
}
}
uint offset = stride * gl_InstanceIndex;
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
offset += 2;
} else {
@@ -261,14 +271,14 @@ void main() {
offset += 3;
}
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
#ifdef COLOR_USED
color_interp *= transforms.data[offset];
#endif
offset += 1;
}
- if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
instance_custom = transforms.data[offset];
}
@@ -287,16 +297,31 @@ void main() {
model_normal_matrix = model_normal_matrix * mat3(matrix);
}
- vec3 vertex = vertex_attrib;
+ vec3 vertex = vertex_angle_attrib.xyz * instances.data[draw_call.instance_index].compressed_aabb_size_pad.xyz + instances.data[draw_call.instance_index].compressed_aabb_position_pad.xyz;
#ifdef NORMAL_USED
- vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
+ vec3 normal = oct_to_vec3(axis_tangent_attrib.xy * 2.0 - 1.0);
#endif
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
- vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
- float binormalf = sign(signed_tangent_attrib.y);
- vec3 binormal = normalize(cross(normal, tangent) * binormalf);
+#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+
+ vec3 binormal;
+ float binormal_sign;
+ vec3 tangent;
+ if (axis_tangent_attrib.z > 0.0 || axis_tangent_attrib.w < 1.0) {
+ // Uncompressed format.
+ vec2 signed_tangent_attrib = axis_tangent_attrib.zw * 2.0 - 1.0;
+ tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
+ binormal_sign = sign(signed_tangent_attrib.y);
+ binormal = normalize(cross(normal, tangent) * binormal_sign);
+ } else {
+ // Compressed format.
+ float angle = vertex_angle_attrib.w;
+ binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller.
+ angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably.
+ vec3 axis = normal;
+ axis_angle_to_tbn(axis, angle, tangent, binormal, normal);
+ binormal *= binormal_sign;
+ }
#endif
#ifdef UV_USED
@@ -307,6 +332,17 @@ void main() {
uv2_interp = uv2_attrib;
#endif
+ vec4 uv_scale = instances.data[draw_call.instance_index].uv_scale;
+
+ if (uv_scale != vec4(0.0)) { // Compression enabled
+#ifdef UV_USED
+ uv_interp = (uv_interp - 0.5) * uv_scale.xy;
+#endif
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ uv2_interp = (uv2_interp - 0.5) * uv_scale.zw;
+#endif
+ }
+
#ifdef OVERRIDE_POSITION
vec4 position;
#endif
@@ -372,13 +408,12 @@ void main() {
normal = modelview_normal * normal;
#endif
-#endif
-
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
binormal = modelview_normal * binormal;
tangent = modelview_normal * tangent;
#endif
+#endif // !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
//using world coordinates
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
@@ -441,8 +476,7 @@ void main() {
#endif // MODE_RENDER_DEPTH
#ifdef MODE_RENDER_MATERIAL
if (scene_data.material_uv2_mode) {
- vec2 uv_offset = draw_call.lightmap_uv_scale.xy; // we are abusing lightmap_uv_scale here, we shouldn't have a lightmap during a depth pass...
- gl_Position.xy = (uv2_attrib.xy + uv_offset) * 2.0 - 1.0;
+ gl_Position.xy = (uv2_attrib.xy + draw_call.uv_offset) * 2.0 - 1.0;
gl_Position.z = 0.00001;
gl_Position.w = 1.0;
}
@@ -765,7 +799,7 @@ void main() {
#endif // ALPHA_ANTIALIASING_EDGE_USED
mat4 inv_view_matrix = scene_data.inv_view_matrix;
- mat4 read_model_matrix = draw_call.transform;
+ mat4 read_model_matrix = instances.data[draw_call.instance_index].transform;
#ifdef USE_DOUBLE_PRECISION
read_model_matrix[0][3] = 0.0;
read_model_matrix[1][3] = 0.0;
@@ -890,11 +924,11 @@ void main() {
if (!sc_disable_decals) { //Decals
// must implement
- uint decal_indices = draw_call.decals.x;
+ uint decal_indices = instances.data[draw_call.instance_index].decals.x;
for (uint i = 0; i < 8; i++) {
uint decal_index = decal_indices & 0xFF;
if (i == 3) {
- decal_indices = draw_call.decals.y;
+ decal_indices = instances.data[draw_call.instance_index].decals.y;
} else {
decal_indices = decal_indices >> 8;
}
@@ -903,7 +937,7 @@ void main() {
break;
}
- if (!bool(decals.data[decal_index].mask & draw_call.layer_mask)) {
+ if (!bool(decals.data[decal_index].mask & instances.data[draw_call.instance_index].layer_mask)) {
continue; //not masked
}
@@ -1097,8 +1131,8 @@ void main() {
#ifdef USE_LIGHTMAP
//lightmap
- if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture
- uint index = draw_call.gi_offset;
+ if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture
+ uint index = instances.data[draw_call.instance_index].gi_offset;
vec3 wnormal = mat3(scene_data.inv_view_matrix) * normal;
const float c1 = 0.429043;
@@ -1118,12 +1152,12 @@ void main() {
2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z) *
scene_data.emissive_exposure_normalization;
- } else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
- bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
- uint ofs = draw_call.gi_offset & 0xFFFF;
- uint slice = draw_call.gi_offset >> 16;
+ } else if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
+ bool uses_sh = bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
+ uint ofs = instances.data[draw_call.instance_index].gi_offset & 0xFFFF;
+ uint slice = instances.data[draw_call.instance_index].gi_offset >> 16;
vec3 uvw;
- uvw.xy = uv2 * draw_call.lightmap_uv_scale.zw + draw_call.lightmap_uv_scale.xy;
+ uvw.xy = uv2 * instances.data[draw_call.instance_index].lightmap_uv_scale.zw + instances.data[draw_call.instance_index].lightmap_uv_scale.xy;
uvw.z = float(slice);
if (uses_sh) {
@@ -1162,7 +1196,7 @@ void main() {
vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
- uint reflection_indices = draw_call.reflection_probes.x;
+ uint reflection_indices = instances.data[draw_call.instance_index].reflection_probes.x;
#ifdef LIGHT_ANISOTROPY_USED
// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
@@ -1179,7 +1213,7 @@ void main() {
for (uint i = 0; i < 8; i++) {
uint reflection_index = reflection_indices & 0xFF;
if (i == 3) {
- reflection_indices = draw_call.reflection_probes.y;
+ reflection_indices = instances.data[draw_call.instance_index].reflection_probes.y;
} else {
reflection_indices = reflection_indices >> 8;
}
@@ -1260,7 +1294,7 @@ void main() {
break;
}
- if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) {
+ if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
continue; //not masked
}
@@ -1532,7 +1566,7 @@ void main() {
break;
}
- if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) {
+ if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
continue; //not masked
}
@@ -1601,11 +1635,11 @@ void main() {
} //directional light
if (!sc_disable_omni_lights) { //omni lights
- uint light_indices = draw_call.omni_lights.x;
+ uint light_indices = instances.data[draw_call.instance_index].omni_lights.x;
for (uint i = 0; i < 8; i++) {
uint light_index = light_indices & 0xFF;
if (i == 3) {
- light_indices = draw_call.omni_lights.y;
+ light_indices = instances.data[draw_call.instance_index].omni_lights.y;
} else {
light_indices = light_indices >> 8;
}
@@ -1646,11 +1680,11 @@ void main() {
if (!sc_disable_spot_lights) { //spot lights
- uint light_indices = draw_call.spot_lights.x;
+ uint light_indices = instances.data[draw_call.instance_index].spot_lights.x;
for (uint i = 0; i < 8; i++) {
uint light_index = light_indices & 0xFF;
if (i == 3) {
- light_indices = draw_call.spot_lights.y;
+ light_indices = instances.data[draw_call.instance_index].spot_lights.y;
} else {
light_indices = light_indices >> 8;
}
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
index d0a315858d..3de5e76970 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
@@ -15,20 +15,11 @@
#endif
#define USING_MOBILE_RENDERER
-/* don't exceed 128 bytes!! */
-/* put instance data into our push content, not a array */
-layout(push_constant, std430) uniform DrawCall {
- highp mat4 transform; // 64 - 64
- uint flags; // 04 - 68
- uint instance_uniforms_ofs; //base offset in global buffer for instance variables // 04 - 72
- uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) // 04 - 76
- uint layer_mask; // 04 - 80
- highp vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed
- uvec2 reflection_probes; // 08 - 104
- uvec2 omni_lights; // 08 - 112
- uvec2 spot_lights; // 08 - 120
- uvec2 decals; // 08 - 128
+layout(push_constant, std430) uniform DrawCall {
+ vec2 uv_offset;
+ uint instance_index;
+ uint pad;
}
draw_call;
@@ -123,6 +114,29 @@ layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
}
scene_data_block;
+struct InstanceData {
+ highp mat4 transform; // 64 - 64
+ uint flags; // 04 - 68
+ uint instance_uniforms_ofs; // Base offset in global buffer for instance variables. // 04 - 72
+ uint gi_offset; // GI information when using lightmapping (VCT or lightmap index). // 04 - 76
+ uint layer_mask; // 04 - 80
+ highp vec4 lightmap_uv_scale; // 16 - 96 Doubles as uv_offset when needed.
+
+ uvec2 reflection_probes; // 08 - 104
+ uvec2 omni_lights; // 08 - 112
+ uvec2 spot_lights; // 08 - 120
+ uvec2 decals; // 08 - 128
+
+ vec4 compressed_aabb_position_pad; // 16 - 144 // Only .xyz is used. .w is padding.
+ vec4 compressed_aabb_size_pad; // 16 - 160 // Only .xyz is used. .w is padding.
+ vec4 uv_scale; // 16 - 176
+};
+
+layout(set = 1, binding = 1, std430) buffer restrict readonly InstanceDataBuffer {
+ InstanceData data[];
+}
+instances;
+
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
layout(set = 1, binding = 2) uniform mediump textureCubeArray radiance_cubemap;
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index 7ba03a27f7..5fa4154727 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -67,7 +67,7 @@ struct FrameParams {
float delta;
uint frame;
- uint pad0;
+ float amount_ratio;
uint pad1;
uint pad2;
@@ -77,6 +77,8 @@ struct FrameParams {
float particle_size;
mat4 emission_transform;
+ vec3 emitter_velocity;
+ float interp_to_end;
Attractor attractors[MAX_ATTRACTORS];
Collider colliders[MAX_COLLIDERS];
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index aa90ad6876..4fb577d697 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -71,7 +71,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di
mat4 inv_view_matrix = scene_data_block.data.inv_view_matrix;
#ifdef USING_MOBILE_RENDERER
- mat4 read_model_matrix = draw_call.transform;
+ mat4 read_model_matrix = instances.data[draw_call.instance_index].transform;
#else
mat4 read_model_matrix = instances.data[instance_index_interp].transform;
#endif
diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl
index 59c161548c..894dee1728 100644
--- a/servers/rendering/renderer_rd/shaders/skeleton.glsl
+++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl
@@ -49,7 +49,7 @@ layout(push_constant, std430) uniform Params {
uint blend_shape_count;
bool normalized_blend_shapes;
- uint pad0;
+ uint normal_tangent_stride;
uint pad1;
vec2 skeleton_transform_x;
@@ -188,15 +188,15 @@ void main() {
vertex = uintBitsToFloat(uvec3(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1], src_vertices.data[src_offset + 2]));
- src_offset += 3;
+ uint src_normal = params.vertex_count * params.vertex_stride + index * params.normal_tangent_stride;
if (params.has_normal) {
- normal = decode_uint_oct_to_norm(src_vertices.data[src_offset]);
- src_offset++;
+ normal = decode_uint_oct_to_norm(src_vertices.data[src_normal]);
+ src_normal++;
}
if (params.has_tangent) {
- tangent = decode_uint_oct_to_tang(src_vertices.data[src_offset]);
+ tangent = decode_uint_oct_to_tang(src_vertices.data[src_normal]);
}
if (params.has_blend_shape) {
@@ -208,19 +208,19 @@ void main() {
for (uint i = 0; i < params.blend_shape_count; i++) {
float w = blend_shape_weights.data[i];
if (abs(w) > 0.0001) {
- uint base_offset = (params.vertex_count * i + index) * params.vertex_stride;
+ uint base_offset = params.vertex_count * i * (params.vertex_stride + params.normal_tangent_stride) + index * params.vertex_stride;
blend_vertex += uintBitsToFloat(uvec3(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1], src_blend_shapes.data[base_offset + 2])) * w;
- base_offset += 3;
+ uint base_normal = params.vertex_count * i * (params.vertex_stride + params.normal_tangent_stride) + params.vertex_count * params.vertex_stride + index * params.normal_tangent_stride;
if (params.has_normal) {
- blend_normal += decode_uint_oct_to_norm(src_blend_shapes.data[base_offset]) * w;
- base_offset++;
+ blend_normal += decode_uint_oct_to_norm(src_blend_shapes.data[base_normal]) * w;
+ base_normal++;
}
if (params.has_tangent) {
- blend_tangent += decode_uint_oct_to_tang(src_blend_shapes.data[base_offset]).rgb * w;
+ blend_tangent += decode_uint_oct_to_tang(src_blend_shapes.data[base_normal]).rgb * w;
}
blend_total += w;
@@ -291,15 +291,15 @@ void main() {
dst_vertices.data[dst_offset + 1] = uvertex.y;
dst_vertices.data[dst_offset + 2] = uvertex.z;
- dst_offset += 3;
+ uint dst_normal = params.vertex_count * params.vertex_stride + index * params.normal_tangent_stride;
if (params.has_normal) {
- dst_vertices.data[dst_offset] = encode_norm_to_uint_oct(normal);
- dst_offset++;
+ dst_vertices.data[dst_normal] = encode_norm_to_uint_oct(normal);
+ dst_normal++;
}
if (params.has_tangent) {
- dst_vertices.data[dst_offset] = encode_tang_to_uint_oct(tangent);
+ dst_vertices.data[dst_normal] = encode_tang_to_uint_oct(tangent);
}
#endif
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index 3bd35c53cc..2e8c9d7f8e 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -2115,7 +2115,7 @@ void MaterialStorage::material_set_shader(RID p_material, RID p_shader) {
return;
}
- ERR_FAIL_COND(shader->data == nullptr);
+ ERR_FAIL_NULL(shader->data);
material->data = material_data_request_func[shader->type](shader->data);
material->data->self = p_material;
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index cb7eb3cd59..14605b308e 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -270,10 +270,10 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
uint32_t skin_stride = 0;
for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
- if ((p_surface.format & (1 << i))) {
+ if ((p_surface.format & (1ULL << i))) {
switch (i) {
case RS::ARRAY_VERTEX: {
- if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+ if ((p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) || (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
stride += sizeof(float) * 2;
} else {
stride += sizeof(float) * 3;
@@ -281,22 +281,31 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
} break;
case RS::ARRAY_NORMAL: {
- stride += sizeof(int32_t);
+ stride += sizeof(uint16_t) * 2;
} break;
case RS::ARRAY_TANGENT: {
- stride += sizeof(int32_t);
-
+ if (!(p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
+ stride += sizeof(uint16_t) * 2;
+ }
} break;
case RS::ARRAY_COLOR: {
attrib_stride += sizeof(uint32_t);
} break;
case RS::ARRAY_TEX_UV: {
- attrib_stride += sizeof(float) * 2;
+ if (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ attrib_stride += sizeof(uint16_t) * 2;
+ } else {
+ attrib_stride += sizeof(float) * 2;
+ }
} break;
case RS::ARRAY_TEX_UV2: {
- attrib_stride += sizeof(float) * 2;
+ if (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ attrib_stride += sizeof(uint16_t) * 2;
+ } else {
+ attrib_stride += sizeof(float) * 2;
+ }
} break;
case RS::ARRAY_CUSTOM0:
@@ -338,59 +347,96 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
#endif
- Mesh::Surface *s = memnew(Mesh::Surface);
+ uint64_t surface_version = p_surface.format & (uint64_t(RS::ARRAY_FLAG_FORMAT_VERSION_MASK) << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT);
+ RS::SurfaceData new_surface = p_surface;
+#ifdef DISABLE_DEPRECATED
- s->format = p_surface.format;
- s->primitive = p_surface.primitive;
+ ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Surface version provided (" + itos(int(surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT)) + ") does not match current version (" + itos(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) + ")");
- bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0);
+#else
- if (p_surface.vertex_data.size()) {
- s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage);
- s->vertex_buffer_size = p_surface.vertex_data.size();
+ if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) {
+ RS::_fix_surface_compatibility(new_surface);
+ surface_version = new_surface.format & (RS::ARRAY_FLAG_FORMAT_VERSION_MASK << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT);
+ ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION,
+ "Surface version provided (" +
+ itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) +
+ ") does not match current version (" +
+ itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) +
+ ")");
}
+#endif
- if (p_surface.attribute_data.size()) {
- s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data);
+ Mesh::Surface *s = memnew(Mesh::Surface);
+
+ s->format = new_surface.format;
+ s->primitive = new_surface.primitive;
+
+ bool use_as_storage = (new_surface.skin_data.size() || mesh->blend_shape_count > 0);
+
+ if (new_surface.vertex_data.size()) {
+ // If we have an uncompressed surface that contains normals, but not tangents, we need to differentiate the array
+ // from a compressed array in the shader. To do so, we allow the the normal to read 4 components out of the buffer
+ // But only give it 2 components per normal. So essentially, each vertex reads the next normal in normal.zw.
+ // This allows us to avoid adding a shader permutation, and avoid passing dummy tangents. Since the stride is kept small
+ // this should still be a net win for bandwidth.
+ // If we do this, then the last normal will read past the end of the array. So we need to pad the array with dummy data.
+ if (!(new_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (new_surface.format & RS::ARRAY_FORMAT_NORMAL) && !(new_surface.format & RS::ARRAY_FORMAT_TANGENT)) {
+ // Unfortunately, we need to copy the buffer, which is fine as doing a resize triggers a CoW anyway.
+ Vector<uint8_t> new_vertex_data;
+ new_vertex_data.resize_zeroed(new_surface.vertex_data.size() + sizeof(uint16_t) * 2);
+ memcpy(new_vertex_data.ptrw(), new_surface.vertex_data.ptr(), new_surface.vertex_data.size());
+ s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(new_vertex_data.size(), new_vertex_data, use_as_storage);
+ s->vertex_buffer_size = new_vertex_data.size();
+ } else {
+ s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.vertex_data.size(), new_surface.vertex_data, use_as_storage);
+ s->vertex_buffer_size = new_surface.vertex_data.size();
+ }
+ }
+
+ if (new_surface.attribute_data.size()) {
+ s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.attribute_data.size(), new_surface.attribute_data);
}
- if (p_surface.skin_data.size()) {
- s->skin_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.skin_data.size(), p_surface.skin_data, use_as_storage);
- s->skin_buffer_size = p_surface.skin_data.size();
+ if (new_surface.skin_data.size()) {
+ s->skin_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.skin_data.size(), new_surface.skin_data, use_as_storage);
+ s->skin_buffer_size = new_surface.skin_data.size();
}
- s->vertex_count = p_surface.vertex_count;
+ s->vertex_count = new_surface.vertex_count;
- if (p_surface.format & RS::ARRAY_FORMAT_BONES) {
+ if (new_surface.format & RS::ARRAY_FORMAT_BONES) {
mesh->has_bone_weights = true;
}
- if (p_surface.index_count) {
- bool is_index_16 = p_surface.vertex_count <= 65536 && p_surface.vertex_count > 0;
+ if (new_surface.index_count) {
+ bool is_index_16 = new_surface.vertex_count <= 65536 && new_surface.vertex_count > 0;
- s->index_buffer = RD::get_singleton()->index_buffer_create(p_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.index_data, false);
- s->index_count = p_surface.index_count;
+ s->index_buffer = RD::get_singleton()->index_buffer_create(new_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, new_surface.index_data, false);
+ s->index_count = new_surface.index_count;
s->index_array = RD::get_singleton()->index_array_create(s->index_buffer, 0, s->index_count);
- if (p_surface.lods.size()) {
- s->lods = memnew_arr(Mesh::Surface::LOD, p_surface.lods.size());
- s->lod_count = p_surface.lods.size();
+ if (new_surface.lods.size()) {
+ s->lods = memnew_arr(Mesh::Surface::LOD, new_surface.lods.size());
+ s->lod_count = new_surface.lods.size();
- for (int i = 0; i < p_surface.lods.size(); i++) {
- uint32_t indices = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
- s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.lods[i].index_data);
+ for (int i = 0; i < new_surface.lods.size(); i++) {
+ uint32_t indices = new_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
+ s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, new_surface.lods[i].index_data);
s->lods[i].index_array = RD::get_singleton()->index_array_create(s->lods[i].index_buffer, 0, indices);
- s->lods[i].edge_length = p_surface.lods[i].edge_length;
+ s->lods[i].edge_length = new_surface.lods[i].edge_length;
s->lods[i].index_count = indices;
}
}
}
- ERR_FAIL_COND_MSG(!p_surface.index_count && !p_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
+ ERR_FAIL_COND_MSG(!new_surface.index_count && !new_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
- s->aabb = p_surface.aabb;
- s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
+ s->aabb = new_surface.aabb;
+ s->bone_aabbs = new_surface.bone_aabbs; //only really useful for returning them.
+
+ s->uv_scale = new_surface.uv_scale;
if (mesh->blend_shape_count > 0) {
- s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(p_surface.blend_shape_data.size(), p_surface.blend_shape_data);
+ s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(new_surface.blend_shape_data.size(), new_surface.blend_shape_data);
}
if (use_as_storage) {
@@ -433,13 +479,13 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
if (mesh->surface_count == 0) {
- mesh->aabb = p_surface.aabb;
+ mesh->aabb = new_surface.aabb;
} else {
- mesh->aabb.merge_with(p_surface.aabb);
+ mesh->aabb.merge_with(new_surface.aabb);
}
mesh->skeleton_aabb_version = 0;
- s->material = p_surface.material;
+ s->material = new_surface.material;
mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1));
mesh->surfaces[mesh->surface_count] = s;
@@ -545,6 +591,11 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
sd.format = s.format;
if (s.vertex_buffer.is_valid()) {
sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
+ // When using an uncompressed buffer with normals, but without tangents, we have to trim the padding.
+ if (!(s.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (s.format & RS::ARRAY_FORMAT_NORMAL) && !(s.format & RS::ARRAY_FORMAT_TANGENT)) {
+ Vector<uint8_t> new_vertex_data;
+ sd.vertex_data.resize(sd.vertex_data.size() - sizeof(uint16_t) * 2);
+ }
}
if (s.attribute_buffer.is_valid()) {
sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer);
@@ -560,6 +611,7 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
sd.index_data = RD::get_singleton()->buffer_get_data(s.index_buffer);
}
sd.aabb = s.aabb;
+ sd.uv_scale = s.uv_scale;
for (uint32_t i = 0; i < s.lod_count; i++) {
RS::SurfaceData::LOD lod;
lod.edge_length = s.lods[i].edge_length;
@@ -1016,8 +1068,10 @@ void MeshStorage::update_mesh_instances() {
push_constant.has_skeleton = sk != nullptr && sk->use_2d == array_is_2d && (mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES);
push_constant.has_blend_shape = mi->mesh->blend_shape_count > 0;
+ push_constant.normal_tangent_stride = (push_constant.has_normal ? 1 : 0) + (push_constant.has_tangent ? 1 : 0);
+
push_constant.vertex_count = mi->mesh->surfaces[i]->vertex_count;
- push_constant.vertex_stride = (mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4;
+ push_constant.vertex_stride = ((mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4) - push_constant.normal_tangent_stride;
push_constant.skin_stride = (mi->mesh->surfaces[i]->skin_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4;
push_constant.skin_weight_offset = (mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 4 : 2;
@@ -1042,7 +1096,6 @@ void MeshStorage::update_mesh_instances() {
push_constant.blend_shape_count = mi->mesh->blend_shape_count;
push_constant.normalized_blend_shapes = mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED;
- push_constant.pad0 = 0;
push_constant.pad1 = 0;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SkeletonShader::PushConstant));
@@ -1061,11 +1114,13 @@ void MeshStorage::update_mesh_instances() {
RD::get_singleton()->compute_list_end();
}
-void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) {
+void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) {
Vector<RD::VertexAttribute> attributes;
Vector<RID> buffers;
+ Vector<uint64_t> offsets;
- uint32_t stride = 0;
+ uint32_t position_stride = 0;
+ uint32_t normal_tangent_stride = 0;
uint32_t attribute_stride = 0;
uint32_t skin_stride = 0;
@@ -1073,8 +1128,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
RD::VertexAttribute vd;
RID buffer;
vd.location = i;
+ uint64_t offset = 0;
- if (!(s->format & (1 << i))) {
+ if (!(s->format & (1ULL << i))) {
// Not supplied by surface, use default value
buffer = mesh_default_rd_buffers[i];
vd.stride = 0;
@@ -1123,14 +1179,19 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
switch (i) {
case RS::ARRAY_VERTEX: {
- vd.offset = stride;
+ vd.offset = position_stride;
if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- stride += sizeof(float) * 2;
+ position_stride = sizeof(float) * 2;
} else {
- vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
- stride += sizeof(float) * 3;
+ if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+ position_stride = sizeof(uint16_t) * 4;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ position_stride = sizeof(float) * 3;
+ }
}
if (mis) {
@@ -1141,27 +1202,33 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
} break;
case RS::ARRAY_NORMAL: {
- vd.offset = stride;
- vd.format = RD::DATA_FORMAT_R16G16_UNORM;
- stride += sizeof(uint16_t) * 2;
-
- if (mis) {
- buffer = mis->vertex_buffer[p_current_buffer];
+ vd.offset = 0;
+ offset = position_stride * s->vertex_count;
+ if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ normal_tangent_stride += sizeof(uint16_t) * 2;
} else {
- buffer = s->vertex_buffer;
+ vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
+ // A small trick here: if we are uncompressed and we have normals, but no tangents. We need
+ // the shader to think there are 4 components to "axis_tangent_attrib". So we give a size of 4,
+ // but a stride based on only having 2 elements.
+ if (!(s->format & RS::ARRAY_FORMAT_TANGENT)) {
+ normal_tangent_stride += sizeof(uint16_t) * 2;
+ } else {
+ normal_tangent_stride += sizeof(uint16_t) * 4;
+ }
}
- } break;
- case RS::ARRAY_TANGENT: {
- vd.offset = stride;
- vd.format = RD::DATA_FORMAT_R16G16_UNORM;
- stride += sizeof(uint16_t) * 2;
-
if (mis) {
buffer = mis->vertex_buffer[p_current_buffer];
} else {
buffer = s->vertex_buffer;
}
} break;
+ case RS::ARRAY_TANGENT: {
+ buffer = mesh_default_rd_buffers[i];
+ vd.stride = 0;
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ } break;
case RS::ARRAY_COLOR: {
vd.offset = attribute_stride;
@@ -1171,17 +1238,25 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
} break;
case RS::ARRAY_TEX_UV: {
vd.offset = attribute_stride;
-
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- attribute_stride += sizeof(float) * 2;
+ if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ attribute_stride += sizeof(uint16_t) * 2;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ attribute_stride += sizeof(float) * 2;
+ }
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_TEX_UV2: {
vd.offset = attribute_stride;
-
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- attribute_stride += sizeof(float) * 2;
+ if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ attribute_stride += sizeof(uint16_t) * 2;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ attribute_stride += sizeof(float) * 2;
+ }
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_CUSTOM0:
@@ -1216,12 +1291,13 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
}
}
- if (!(p_input_mask & (1 << i))) {
+ if (!(p_input_mask & (1ULL << i))) {
continue; // Shader does not need this, skip it (but computing stride was important anyway)
}
attributes.push_back(vd);
buffers.push_back(buffer);
+ offsets.push_back(offset);
if (p_input_motion_vectors) {
// Since the previous vertex, normal and tangent can't be part of the vertex format but they are required when motion
@@ -1246,6 +1322,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
attributes.push_back(vd);
buffers.push_back(buffer);
+ offsets.push_back(offset);
}
}
}
@@ -1256,9 +1333,10 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
continue; //default location
}
int loc = attributes[i].location;
-
- if ((loc < RS::ARRAY_COLOR) || ((loc >= ATTRIBUTE_LOCATION_PREV_VERTEX) && (loc <= ATTRIBUTE_LOCATION_PREV_TANGENT))) {
- attributes.write[i].stride = stride;
+ if (loc == RS::ARRAY_VERTEX || loc == ATTRIBUTE_LOCATION_PREV_VERTEX) {
+ attributes.write[i].stride = position_stride;
+ } else if ((loc < RS::ARRAY_COLOR) || ((loc >= ATTRIBUTE_LOCATION_PREV_NORMAL) && (loc <= ATTRIBUTE_LOCATION_PREV_TANGENT))) {
+ attributes.write[i].stride = normal_tangent_stride;
} else if (loc < RS::ARRAY_BONES) {
attributes.write[i].stride = attribute_stride;
} else {
@@ -1271,7 +1349,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
v.previous_buffer = p_previous_buffer;
v.input_motion_vectors = p_input_motion_vectors;
v.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
- v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers);
+ v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers, offsets);
}
////////////////// MULTIMESH
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index 1e1db9c47d..f03334baac 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -73,7 +73,7 @@ private:
struct Mesh {
struct Surface {
RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
- uint32_t format = 0;
+ uint64_t format = 0;
RID vertex_buffer;
RID attribute_buffer;
@@ -90,7 +90,7 @@ private:
// cache-efficient structure.
struct Version {
- uint32_t input_mask = 0;
+ uint64_t input_mask = 0;
uint32_t current_buffer = 0;
uint32_t previous_buffer = 0;
bool input_motion_vectors = false;
@@ -120,6 +120,8 @@ private:
Vector<AABB> bone_aabbs;
+ Vector4 uv_scale;
+
RID blend_shape_buffer;
RID material;
@@ -190,7 +192,7 @@ private:
weight_update_list(this), array_update_list(this) {}
};
- void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0);
+ void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0);
void _mesh_instance_clear(MeshInstance *mi);
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
@@ -265,7 +267,7 @@ private:
uint32_t blend_shape_count;
uint32_t normalized_blend_shapes;
- uint32_t pad0;
+ uint32_t normal_tangent_stride;
uint32_t pad1;
float skeleton_transform_x[2];
float skeleton_transform_y[2];
@@ -422,6 +424,21 @@ public:
return s->index_count ? s->index_count : s->vertex_count;
}
+ _FORCE_INLINE_ AABB mesh_surface_get_aabb(void *p_surface) {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return s->aabb;
+ }
+
+ _FORCE_INLINE_ uint64_t mesh_surface_get_format(void *p_surface) {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return s->format;
+ }
+
+ _FORCE_INLINE_ Vector4 mesh_surface_get_uv_scale(void *p_surface) {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return s->uv_scale;
+ }
+
_FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t &r_index_count) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
@@ -484,7 +501,7 @@ public:
s->version_lock.unlock();
}
- _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
+ _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint64_t p_surface_index, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
ERR_FAIL_NULL(mi);
Mesh *mesh = mi->mesh;
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index bf5a597bb9..3d3cb585ac 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -72,6 +72,7 @@ ParticlesStorage::ParticlesStorage() {
actions.renames["ACTIVE"] = "particle_active";
actions.renames["RESTART"] = "restart";
actions.renames["CUSTOM"] = "PARTICLE.custom";
+ actions.renames["AMOUNT_RATIO"] = "FRAME.amount_ratio";
for (int i = 0; i < ParticlesShader::MAX_USERDATAS; i++) {
String udname = "USERDATA" + itos(i + 1);
actions.renames[udname] = "PARTICLE.userdata" + itos(i + 1);
@@ -88,6 +89,8 @@ ParticlesStorage::ParticlesStorage() {
actions.renames["INDEX"] = "index";
//actions.renames["GRAVITY"] = "current_gravity";
actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform";
+ actions.renames["EMITTER_VELOCITY"] = "FRAME.emitter_velocity";
+ actions.renames["INTERPOLATE_TO_END"] = "FRAME.interp_to_end";
actions.renames["RANDOM_SEED"] = "FRAME.random_seed";
actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION";
actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE";
@@ -221,13 +224,15 @@ RID ParticlesStorage::particles_allocate() {
}
void ParticlesStorage::particles_initialize(RID p_rid) {
- particles_owner.initialize_rid(p_rid, Particles());
+ particles_owner.initialize_rid(p_rid);
}
void ParticlesStorage::particles_free(RID p_rid) {
- update_particles();
Particles *particles = particles_owner.get_or_null(p_rid);
+
particles->dependency.deleted_notify(p_rid);
+ particles->update_list.remove_from_list();
+
_particles_free_data(particles);
particles_owner.free(p_rid);
}
@@ -329,6 +334,13 @@ void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
}
+void ParticlesStorage::particles_set_amount_ratio(RID p_particles, float p_amount_ratio) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_NULL(particles);
+
+ particles->amount_ratio = p_amount_ratio;
+}
+
void ParticlesStorage::particles_set_lifetime(RID p_particles, double p_lifetime) {
Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL(particles);
@@ -577,8 +589,10 @@ void ParticlesStorage::particles_request_process(RID p_particles) {
if (!particles->dirty) {
particles->dirty = true;
- particles->update_list = particle_update_list;
- particle_update_list = particles;
+
+ if (!particles->update_list.in_list()) {
+ particle_update_list.add(&particles->update_list);
+ }
}
}
@@ -651,6 +665,20 @@ void ParticlesStorage::particles_set_emission_transform(RID p_particles, const T
particles->emission_transform = p_transform;
}
+void ParticlesStorage::particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_NULL(particles);
+
+ particles->emitter_velocity = p_velocity;
+}
+
+void ParticlesStorage::particles_set_interp_to_end(RID p_particles, float p_interp) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_NULL(particles);
+
+ particles->interp_to_end = p_interp;
+}
+
int ParticlesStorage::particles_get_draw_passes(RID p_particles) const {
const Particles *particles = particles_owner.get_or_null(p_particles);
ERR_FAIL_NULL_V(particles, 0);
@@ -791,9 +819,13 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
frame_params.cycle = p_particles->cycle_number;
frame_params.frame = p_particles->frame_counter++;
- frame_params.pad0 = 0;
+ frame_params.amount_ratio = p_particles->amount_ratio;
frame_params.pad1 = 0;
frame_params.pad2 = 0;
+ frame_params.emitter_velocity[0] = p_particles->emitter_velocity.x;
+ frame_params.emitter_velocity[1] = p_particles->emitter_velocity.y;
+ frame_params.emitter_velocity[2] = p_particles->emitter_velocity.z;
+ frame_params.interp_to_end = p_particles->interp_to_end;
{ //collision and attractors
@@ -1345,14 +1377,12 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
void ParticlesStorage::update_particles() {
uint32_t frame = RSG::rasterizer->get_frame_number();
bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0;
- while (particle_update_list) {
+ while (particle_update_list.first()) {
//use transform feedback to process particles
- Particles *particles = particle_update_list;
+ Particles *particles = particle_update_list.first()->self();
- //take and remove
- particle_update_list = particles->update_list;
- particles->update_list = nullptr;
+ particles->update_list.remove_from_list();
particles->dirty = false;
_particles_update_buffers(particles);
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index b93932f482..a28d7b4154 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -123,7 +123,7 @@ private:
float delta;
uint32_t frame;
- uint32_t pad0;
+ float amount_ratio;
uint32_t pad1;
uint32_t pad2;
@@ -134,6 +134,9 @@ private:
float emission_transform[16];
+ float emitter_velocity[3];
+ float interp_to_end;
+
Attractor attractors[MAX_ATTRACTORS];
Collider colliders[MAX_COLLIDERS];
};
@@ -206,7 +209,7 @@ private:
RID particles_sort_uniform_set;
bool dirty = false;
- Particles *update_list = nullptr;
+ SelfList<Particles> update_list;
RID sub_emitter;
@@ -235,6 +238,9 @@ private:
bool force_sub_emit = false;
Transform3D emission_transform;
+ Vector3 emitter_velocity;
+ float interp_to_end = 0.0;
+ float amount_ratio = 1.0;
Vector<uint8_t> emission_buffer_data;
@@ -250,7 +256,8 @@ private:
LocalVector<ParticlesFrameParams> frame_history;
LocalVector<ParticlesFrameParams> trail_params;
- Particles() {
+ Particles() :
+ update_list(this) {
}
};
@@ -322,7 +329,7 @@ private:
} particles_shader;
- Particles *particle_update_list = nullptr;
+ SelfList<Particles>::List particle_update_list;
mutable RID_Owner<Particles, true> particles_owner;
@@ -425,6 +432,7 @@ public:
virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override;
virtual void particles_set_emitting(RID p_particles, bool p_emitting) override;
virtual void particles_set_amount(RID p_particles, int p_amount) override;
+ virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) override;
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override;
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override;
virtual void particles_set_pre_process_time(RID p_particles, double p_time) override;
@@ -460,6 +468,8 @@ public:
virtual AABB particles_get_aabb(RID p_particles) const override;
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override;
+ virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) override;
+ virtual void particles_set_interp_to_end(RID p_particles, float p_interp_to_end) override;
virtual bool particles_get_emitting(RID p_particles) override;
virtual int particles_get_draw_passes(RID p_particles) const override;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 807eda0f2a..1c5cbe9612 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -1820,7 +1820,8 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
pair.pair_mask |= RS::INSTANCE_GEOMETRY_MASK;
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
- if (RSG::light_storage->light_get_bake_mode(p_instance->base) == RS::LIGHT_BAKE_DYNAMIC) {
+ RS::LightBakeMode bake_mode = RSG::light_storage->light_get_bake_mode(p_instance->base);
+ if (bake_mode == RS::LIGHT_BAKE_STATIC || bake_mode == RS::LIGHT_BAKE_DYNAMIC) {
pair.pair_mask |= (1 << RS::INSTANCE_VOXEL_GI);
pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES];
}
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index cb6479847a..c2fa232eac 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -643,7 +643,7 @@ Error RenderingDevice::_reflect_spirv(const Vector<ShaderStageSPIRVData> &p_spir
for (uint32_t j = 0; j < iv_count; j++) {
if (input_vars[j] && input_vars[j]->decoration_flags == 0) { // Regular input.
- r_reflection_data.vertex_input_mask |= (1 << uint32_t(input_vars[j]->location));
+ r_reflection_data.vertex_input_mask |= (1ULL << uint32_t(input_vars[j]->location));
}
}
}
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index b4bca054e2..b95640acc6 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -758,7 +758,7 @@ public:
virtual RID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder = RID()) = 0;
virtual RID shader_create_placeholder() = 0;
- virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0;
+ virtual uint64_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0;
/******************/
/**** UNIFORMS ****/
@@ -1371,7 +1371,7 @@ protected:
struct SpirvReflectionData {
BitField<ShaderStage> stages_mask;
- uint32_t vertex_input_mask;
+ uint64_t vertex_input_mask;
uint32_t fragment_output_mask;
bool is_compute;
uint32_t compute_local_size[3];
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 9ad2175332..3d75ced3e3 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -490,6 +490,7 @@ public:
FUNC2(particles_set_emitting, RID, bool)
FUNC1R(bool, particles_get_emitting, RID)
FUNC2(particles_set_amount, RID, int)
+ FUNC2(particles_set_amount_ratio, RID, float)
FUNC2(particles_set_lifetime, RID, double)
FUNC2(particles_set_one_shot, RID, bool)
FUNC2(particles_set_pre_process_time, RID, double)
@@ -521,6 +522,8 @@ public:
FUNC1R(AABB, particles_get_current_aabb, RID)
FUNC2(particles_set_emission_transform, RID, const Transform3D &)
+ FUNC2(particles_set_emitter_velocity, RID, const Vector3 &)
+ FUNC2(particles_set_interp_to_end, RID, float)
/* PARTICLES COLLISION */
@@ -891,6 +894,9 @@ public:
FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
+ FUNC1(canvas_item_set_debug_redraw, bool)
+ FUNC0RC(bool, canvas_item_get_debug_redraw)
+
FUNCRIDSPLIT(canvas_light)
FUNC2(canvas_light_set_mode, RID, CanvasLightMode)
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 34ffc1e90f..41f2fbb03f 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -1377,7 +1377,7 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (p_allow_reassign) {
break;
}
- ERR_FAIL_COND_V(!p_block->parent_block, false);
+ ERR_FAIL_NULL_V(p_block->parent_block, false);
p_block = p_block->parent_block;
}
}
@@ -5418,7 +5418,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
if (error) {
- _set_error(vformat(RTR("A constant value cannot be passed for '%s' parameter."), _get_qualifier_str(arg_qual)));
+ _set_error(vformat(RTR("A constant value cannot be passed for the '%s' parameter."), _get_qualifier_str(arg_qual)));
return nullptr;
}
}
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 38574b0597..a6b4646f43 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -348,6 +348,8 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMITTER_VELOCITY"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INTERPOLATE_TO_END"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
@@ -359,6 +361,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["AMOUNT_RATIO"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_PARTICLES].functions["start"].main_function = true;
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
@@ -379,6 +382,8 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMITTER_VELOCITY"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INTERPOLATE_TO_END"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
@@ -389,6 +394,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_DEPTH"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["ATTRACTOR_FORCE"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["AMOUNT_RATIO"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_PARTICLES].functions["process"].main_function = true;
{
diff --git a/servers/rendering/storage/particles_storage.h b/servers/rendering/storage/particles_storage.h
index 78c616f6d5..4f33de912c 100644
--- a/servers/rendering/storage/particles_storage.h
+++ b/servers/rendering/storage/particles_storage.h
@@ -49,6 +49,7 @@ public:
virtual bool particles_get_emitting(RID p_particles) = 0;
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
+ virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) = 0;
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) = 0;
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
virtual void particles_set_pre_process_time(RID p_particles, double p_time) = 0;
@@ -85,6 +86,8 @@ public:
virtual AABB particles_get_aabb(RID p_particles) const = 0;
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) = 0;
+ virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) = 0;
+ virtual void particles_set_interp_to_end(RID p_particles, float p_interp_to_end) = 0;
virtual int particles_get_draw_passes(RID p_particles) const = 0;
virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0;