mirror of
https://github.com/godotengine/godot.git
synced 2025-12-08 06:09:55 +00:00
Added indirect drawing functionality to MultiMesh
Update doc/classes/RenderingServer.xml Co-Authored-By: Micky <66727710+Mickeon@users.noreply.github.com>
This commit is contained in:
parent
d19147e09a
commit
e6daec9cf8
17 changed files with 143 additions and 15 deletions
|
|
@ -1485,7 +1485,7 @@ void MeshStorage::_multimesh_free(RID p_rid) {
|
|||
multimesh_owner.free(p_rid);
|
||||
}
|
||||
|
||||
void MeshStorage::_multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
|
||||
void MeshStorage::_multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data, bool p_use_indirect) {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL(multimesh);
|
||||
|
||||
|
|
@ -1521,6 +1521,9 @@ void MeshStorage::_multimesh_allocate_data(RID p_multimesh, int p_instances, RS:
|
|||
multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 4 : 0);
|
||||
multimesh->buffer_set = false;
|
||||
|
||||
multimesh->indirect = p_use_indirect;
|
||||
multimesh->command_buffer = RID();
|
||||
|
||||
//print_line("allocate, elements: " + itos(p_instances) + " 2D: " + itos(p_transform_format == RS::MULTIMESH_TRANSFORM_2D) + " colors " + itos(multimesh->uses_colors) + " data " + itos(multimesh->uses_custom_data) + " stride " + itos(multimesh->stride_cache) + " total size " + itos(multimesh->stride_cache * multimesh->instances));
|
||||
multimesh->data_cache = Vector<float>();
|
||||
multimesh->aabb = AABB();
|
||||
|
|
@ -1609,6 +1612,30 @@ void MeshStorage::_multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
|
|||
}
|
||||
multimesh->mesh = p_mesh;
|
||||
|
||||
if (multimesh->indirect) {
|
||||
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
||||
ERR_FAIL_NULL(mesh);
|
||||
if (mesh->surface_count > 0) {
|
||||
if (multimesh->command_buffer.is_valid()) {
|
||||
RD::get_singleton()->free(multimesh->command_buffer);
|
||||
}
|
||||
|
||||
Vector<uint8_t> newVector;
|
||||
newVector.resize_zeroed(sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE * mesh->surface_count);
|
||||
|
||||
for (uint32_t i = 0; i < mesh->surface_count; i++) {
|
||||
uint32_t count = mesh_surface_get_vertices_drawn_count(mesh->surfaces[i]);
|
||||
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE, static_cast<uint8_t>(count));
|
||||
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE + 1, static_cast<uint8_t>(count >> 8));
|
||||
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE + 2, static_cast<uint8_t>(count >> 16));
|
||||
newVector.set(i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE + 3, static_cast<uint8_t>(count >> 24));
|
||||
}
|
||||
|
||||
RID newBuffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE * mesh->surface_count, newVector, RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
|
||||
multimesh->command_buffer = newBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
if (multimesh->instances == 0) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -2064,6 +2091,12 @@ void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_
|
|||
}
|
||||
}
|
||||
|
||||
RID MeshStorage::_multimesh_get_command_buffer_rd_rid(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL_V(multimesh, RID());
|
||||
return multimesh->command_buffer;
|
||||
}
|
||||
|
||||
RID MeshStorage::_multimesh_get_buffer_rd_rid(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL_V(multimesh, RID());
|
||||
|
|
@ -2111,6 +2144,15 @@ void MeshStorage::_multimesh_set_visible_instances(RID p_multimesh, int p_visibl
|
|||
|
||||
multimesh->visible_instances = p_visible;
|
||||
|
||||
if (multimesh->indirect) { //we have to update the command buffer for the instance counts, in each stride this will be the second integer.
|
||||
Mesh *mesh = mesh_owner.get_or_null(multimesh->mesh);
|
||||
if (mesh != nullptr) {
|
||||
for (uint32_t i = 0; i < mesh->surface_count; i++) {
|
||||
RD::get_singleton()->buffer_update(multimesh->command_buffer, (i * sizeof(uint32_t) * INDIRECT_MULTIMESH_COMMAND_STRIDE) + sizeof(uint32_t), sizeof(uint32_t), &p_visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,10 @@ public:
|
|||
DEFAULT_RD_BUFFER_MAX,
|
||||
};
|
||||
|
||||
enum IndirectMultiMesh : uint32_t {
|
||||
INDIRECT_MULTIMESH_COMMAND_STRIDE = 5
|
||||
};
|
||||
|
||||
private:
|
||||
static MeshStorage *singleton;
|
||||
|
||||
|
|
@ -226,6 +230,7 @@ private:
|
|||
AABB custom_aabb;
|
||||
bool aabb_dirty = false;
|
||||
bool buffer_set = false;
|
||||
bool indirect = false;
|
||||
bool motion_vectors_enabled = false;
|
||||
uint32_t motion_vectors_current_offset = 0;
|
||||
uint32_t motion_vectors_previous_offset = 0;
|
||||
|
|
@ -243,6 +248,7 @@ private:
|
|||
RID buffer; //storage buffer
|
||||
RID uniform_set_3d;
|
||||
RID uniform_set_2d;
|
||||
RID command_buffer; //used if indirect setting is used
|
||||
|
||||
bool dirty = false;
|
||||
MultiMesh *dirty_list = nullptr;
|
||||
|
|
@ -637,7 +643,7 @@ public:
|
|||
virtual void _multimesh_initialize(RID p_multimesh) override;
|
||||
virtual void _multimesh_free(RID p_rid) override;
|
||||
|
||||
virtual void _multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override;
|
||||
virtual void _multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false, bool p_use_indirect = false) override;
|
||||
virtual int _multimesh_get_instance_count(RID p_multimesh) const override;
|
||||
|
||||
virtual void _multimesh_set_mesh(RID p_multimesh, RID p_mesh) override;
|
||||
|
|
@ -654,6 +660,7 @@ public:
|
|||
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
|
||||
|
||||
virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
|
||||
virtual RID _multimesh_get_command_buffer_rd_rid(RID p_multimesh) const override;
|
||||
virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const override;
|
||||
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
|
||||
|
||||
|
|
@ -672,6 +679,11 @@ public:
|
|||
bool _multimesh_uses_motion_vectors_offsets(RID p_multimesh);
|
||||
bool _multimesh_uses_motion_vectors(RID p_multimesh);
|
||||
|
||||
_FORCE_INLINE_ bool multimesh_uses_indirect(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
return multimesh->indirect;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
return multimesh->xform_format;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue