Compare commits

...

2 Commits

Author SHA1 Message Date
David House
a9cf391206
Merge f484b89ff5 into 9e6098432a 2024-11-21 02:59:51 +00:00
David House
f484b89ff5 Added indirect drawing functionality to MultiMesh 2024-11-20 20:55:38 -06:00
14 changed files with 164 additions and 14 deletions

View File

@ -2518,6 +2518,7 @@
<param index="2" name="transform_format" type="int" enum="RenderingServer.MultimeshTransformFormat" />
<param index="3" name="color_format" type="bool" default="false" />
<param index="4" name="custom_data_format" type="bool" default="false" />
<param index="5" name="use_indirect" type="bool" default="false" />
<description>
</description>
</method>
@ -2552,6 +2553,13 @@
Returns the [RenderingDevice] [RID] handle of the [MultiMesh], which can be used as any other buffer on the Rendering Device.
</description>
</method>
<method name="multimesh_get_command_buffer_rd_rid" qualifiers="const">
<return type="RID" />
<param index="0" name="multimesh" type="RID" />
<description>
Returns the [RenderingDevice] [RID] handle of the [MultiMesh] command buffer, only valid if indirect is set to true when allocating data, can be used to directly modify instance count via buffer.
</description>
</method>
<method name="multimesh_get_custom_aabb" qualifiers="const">
<return type="AABB" />
<param index="0" name="multimesh" type="RID" />

View File

@ -1451,7 +1451,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);
@ -1974,6 +1974,10 @@ void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_
}
}
RID MeshStorage::_multimesh_get_command_buffer_rd_rid(RID p_multimesh) const {
ERR_FAIL_V_MSG(RID(), "GLES3 does not implement indirect multimeshes.");
}
RID MeshStorage::_multimesh_get_buffer_rd_rid(RID p_multimesh) const {
ERR_FAIL_V_MSG(RID(), "GLES3 does not contain a Rid for the multimesh buffer.");
}

View File

@ -498,7 +498,7 @@ public:
virtual RID _multimesh_allocate() override;
virtual void _multimesh_initialize(RID p_rid) 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;
@ -517,6 +517,7 @@ public:
virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
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;

View File

@ -150,7 +150,7 @@ public:
virtual void _multimesh_initialize(RID p_rid) 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 { return 0; }
virtual void _multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {}
@ -170,6 +170,7 @@ public:
virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
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 { return RID(); }
virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const override { return RID(); }
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;

View File

@ -575,7 +575,16 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
instance_count /= surf->owner->trail_steps;
}
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
//If multimesh is indirect, call the draw_list_draw_indirect instead, passing the command buffer
//offset draw count and stride should*? be all 0.
//Multimesh rid can be retrieved using surf->owner->data->base I think.
//Using that we can retrieve the cached command buffer from the mesh storage.
if (bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT)) {
RID command_buffer = mesh_storage->_multimesh_get_command_buffer(surf->owner->data->base);
RD::get_singleton()->draw_list_draw_indirect(draw_list, index_array_rd.is_valid(), command_buffer, 0, 1, 0);
} else {
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
}
}
i += element_info.repeat - 1; //skip equal elements
@ -4102,9 +4111,9 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p
ginstance->base_flags = 0;
bool store_transform = true;
if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
//Set flag here defining that a multimesh is considered indirect.
if (mesh_storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
}
@ -4114,6 +4123,9 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p
if (mesh_storage->multimesh_uses_custom_data(ginstance->data->base)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
}
if (mesh_storage->multimesh_uses_indirect(ginstance->data->base)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT;
}
ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);

View File

@ -246,6 +246,7 @@ private:
// When changing any of these enums, remember to change the corresponding enums in the shader files as well.
enum {
INSTANCE_DATA_FLAG_MULTIMESH_INDIRECT = 1 << 2,
INSTANCE_DATA_FLAGS_DYNAMIC = 1 << 3,
INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,

View File

@ -2146,6 +2146,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
pipeline_specialization.multimesh_format_2d = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D);
pipeline_specialization.multimesh_has_color = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR);
pipeline_specialization.multimesh_has_custom_data = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA);
//Check if multimesh is indirect by having a flag here for it.
SceneState::PushConstant push_constant;
push_constant.base_index = i + p_params->element_offset;
@ -2342,6 +2343,9 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
instance_count /= surf->owner->trail_steps;
}
//If multimesh is indirect, call the draw_list_draw_indirect instead, passing the command buffer
//offset draw count and stride should*? be all 0.
//Retrieve cached command buffer with something similar to index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
}
}
@ -2763,6 +2767,7 @@ void RenderForwardMobile::_geometry_instance_update(RenderGeometryInstance *p_ge
if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
//Set flag here defining that a multimesh is considered indirect.
if (mesh_storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
}

View File

@ -1418,7 +1418,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);
@ -1454,6 +1454,19 @@ 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();
if (p_use_indirect) {
Vector<uint8_t> newVector;
{
newVector.resize_zeroed(sizeof(uint8_t) * 5 * 4);
{
multimesh->command_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 5, newVector, RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
multimesh->indirect_indexed = true;
}
}
}
//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();
@ -1512,6 +1525,12 @@ void MeshStorage::_multimesh_enable_motion_vectors(MultiMesh *multimesh) {
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH);
}
RID MeshStorage::_multimesh_get_command_buffer(RID p_multimesh) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, RID());
return multimesh->command_buffer;
}
void MeshStorage::_multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
@ -1542,6 +1561,60 @@ void MeshStorage::_multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
}
multimesh->mesh = p_mesh;
if (multimesh->indirect) { //Necessitates altering the command buffer to account for the new vertex count, going to assume at this time one surface.
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_NULL(mesh);
if (mesh->surface_count > 0) {
uint32_t index_count = 0;
uint32_t vertex_count = 0;
for (uint32_t i = 0; i < mesh->surface_count; i++) {
index_count += mesh->surfaces[i]->index_count;
vertex_count += mesh->surfaces[i]->vertex_count;
}
if (index_count > 0) {
if (!multimesh->indirect_indexed) {
Vector<uint8_t> newVector;
{
newVector.resize_zeroed(sizeof(uint8_t) * 5 * 4);
{
RID newBuffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 5, newVector, RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
if (multimesh->command_buffer.is_valid()) {
RD::get_singleton()->free(multimesh->command_buffer);
}
multimesh->command_buffer = newBuffer;
}
}
multimesh->indirect_indexed = true;
}
RD::get_singleton()->buffer_update(multimesh->command_buffer, 0, sizeof(uint32_t), &index_count);
} else {
if (multimesh->indirect_indexed) {
Vector<uint8_t> newVector;
{
newVector.resize_zeroed(sizeof(uint8_t) * 4 * 4);
{
RID newBuffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, newVector, RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
if (multimesh->command_buffer.is_valid()) {
RD::get_singleton()->free(multimesh->command_buffer);
}
multimesh->command_buffer = newBuffer;
}
}
multimesh->indirect_indexed = false;
}
RD::get_singleton()->buffer_update(multimesh->command_buffer, 0, sizeof(uint32_t), &vertex_count);
}
}
}
if (multimesh->instances == 0) {
return;
}
@ -1997,6 +2070,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());
@ -2044,6 +2123,26 @@ void MeshStorage::_multimesh_set_visible_instances(RID p_multimesh, int p_visibl
multimesh->visible_instances = p_visible;
if (multimesh->indirect) { //we have to rebuild/update the command buffer if it's indirect.
Mesh *mesh = mesh_owner.get_or_null(multimesh->mesh);
if (mesh != nullptr) {
if (mesh->surface_count > 0) {
uint32_t index_count = 0;
uint32_t vertex_count = 0;
for (uint32_t i = 0; i < mesh->surface_count; i++) {
index_count += mesh->surfaces[i]->index_count;
vertex_count += mesh->surfaces[i]->vertex_count;
}
if (multimesh->indirect_indexed) {
RD::get_singleton()->buffer_update(multimesh->command_buffer, 0, sizeof(uint32_t), &index_count);
} else {
RD::get_singleton()->buffer_update(multimesh->command_buffer, 0, sizeof(uint32_t), &vertex_count);
}
}
}
}
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES);
}

View File

@ -224,6 +224,8 @@ private:
AABB custom_aabb;
bool aabb_dirty = false;
bool buffer_set = false;
bool indirect = false;
bool indirect_indexed = false; //used if the instance count changes on an indirect multimesh, to ensure the correct buffer data is pushed to the command buffer.
bool motion_vectors_enabled = false;
uint32_t motion_vectors_current_offset = 0;
uint32_t motion_vectors_previous_offset = 0;
@ -241,6 +243,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;
@ -634,7 +637,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;
@ -651,6 +654,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;
@ -665,10 +669,16 @@ public:
virtual MultiMeshInterpolator *_multimesh_get_interpolator(RID p_multimesh) const override;
void _update_dirty_multimeshes();
RID _multimesh_get_command_buffer(RID p_multimesh);
void _multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset);
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;

View File

@ -382,7 +382,7 @@ public:
FUNCRIDSPLIT(multimesh)
FUNC5(multimesh_allocate_data, RID, int, MultimeshTransformFormat, bool, bool)
FUNC6(multimesh_allocate_data, RID, int, MultimeshTransformFormat, bool, bool, bool)
FUNC1RC(int, multimesh_get_instance_count, RID)
FUNC2(multimesh_set_mesh, RID, RID)
@ -403,6 +403,7 @@ public:
FUNC2RC(Color, multimesh_instance_get_custom_data, RID, int)
FUNC2(multimesh_set_buffer, RID, const Vector<float> &)
FUNC1RC(RID, multimesh_get_command_buffer_rd_rid, RID)
FUNC1RC(RID, multimesh_get_buffer_rd_rid, RID)
FUNC1RC(Vector<float>, multimesh_get_buffer, RID)

View File

@ -48,7 +48,7 @@ void RendererMeshStorage::multimesh_free(RID p_rid) {
_multimesh_free(p_rid);
}
void RendererMeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
void RendererMeshStorage::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) {
MultiMeshInterpolator *mmi = _multimesh_get_interpolator(p_multimesh);
if (mmi) {
mmi->_transform_format = p_transform_format;
@ -68,7 +68,7 @@ void RendererMeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instanc
mmi->_data_interpolated.resize_zeroed(size_in_floats);
}
_multimesh_allocate_data(p_multimesh, p_instances, p_transform_format, p_use_colors, p_use_custom_data);
_multimesh_allocate_data(p_multimesh, p_instances, p_transform_format, p_use_colors, p_use_custom_data, p_use_indirect);
}
int RendererMeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
@ -223,6 +223,10 @@ void RendererMeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<flo
_multimesh_set_buffer(p_multimesh, p_buffer);
}
RID RendererMeshStorage::multimesh_get_command_buffer_rd_rid(RID p_multimesh) const {
return _multimesh_get_command_buffer_rd_rid(p_multimesh);
}
RID RendererMeshStorage::multimesh_get_buffer_rd_rid(RID p_multimesh) const {
return _multimesh_get_buffer_rd_rid(p_multimesh);
}

View File

@ -120,7 +120,7 @@ public:
virtual void multimesh_initialize(RID p_rid);
virtual void multimesh_free(RID p_rid);
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);
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);
virtual int multimesh_get_instance_count(RID p_multimesh) const;
@ -141,6 +141,7 @@ public:
virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const;
virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer);
virtual RID multimesh_get_command_buffer_rd_rid(RID p_multimesh) const;
virtual RID multimesh_get_buffer_rd_rid(RID p_multimesh) const;
virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const;
@ -158,7 +159,7 @@ public:
virtual void _multimesh_initialize(RID p_rid) = 0;
virtual void _multimesh_free(RID p_rid) = 0;
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) = 0;
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) = 0;
virtual int _multimesh_get_instance_count(RID p_multimesh) const = 0;
@ -179,6 +180,7 @@ public:
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
virtual RID _multimesh_get_command_buffer_rd_rid(RID p_multimesh) const = 0;
virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const = 0;
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const = 0;

View File

@ -2434,7 +2434,7 @@ void RenderingServer::_bind_methods() {
/* MULTIMESH API */
ClassDB::bind_method(D_METHOD("multimesh_create"), &RenderingServer::multimesh_create);
ClassDB::bind_method(D_METHOD("multimesh_allocate_data", "multimesh", "instances", "transform_format", "color_format", "custom_data_format"), &RenderingServer::multimesh_allocate_data, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("multimesh_allocate_data", "multimesh", "instances", "transform_format", "color_format", "custom_data_format", "use_indirect"), &RenderingServer::multimesh_allocate_data, DEFVAL(false), DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("multimesh_get_instance_count", "multimesh"), &RenderingServer::multimesh_get_instance_count);
ClassDB::bind_method(D_METHOD("multimesh_set_mesh", "multimesh", "mesh"), &RenderingServer::multimesh_set_mesh);
ClassDB::bind_method(D_METHOD("multimesh_instance_set_transform", "multimesh", "index", "transform"), &RenderingServer::multimesh_instance_set_transform);
@ -2452,6 +2452,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("multimesh_set_visible_instances", "multimesh", "visible"), &RenderingServer::multimesh_set_visible_instances);
ClassDB::bind_method(D_METHOD("multimesh_get_visible_instances", "multimesh"), &RenderingServer::multimesh_get_visible_instances);
ClassDB::bind_method(D_METHOD("multimesh_set_buffer", "multimesh", "buffer"), &RenderingServer::multimesh_set_buffer);
ClassDB::bind_method(D_METHOD("multimesh_get_command_buffer_rd_rid", "multimesh"), &RenderingServer::multimesh_get_command_buffer_rd_rid);
ClassDB::bind_method(D_METHOD("multimesh_get_buffer_rd_rid", "multimesh"), &RenderingServer::multimesh_get_buffer_rd_rid);
ClassDB::bind_method(D_METHOD("multimesh_get_buffer", "multimesh"), &RenderingServer::multimesh_get_buffer);

View File

@ -454,7 +454,7 @@ public:
MULTIMESH_INTERP_QUALITY_HIGH,
};
virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0;
virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false, bool p_use_indirect = false) = 0;
virtual int multimesh_get_instance_count(RID p_multimesh) const = 0;
virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
@ -475,6 +475,7 @@ public:
virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
virtual RID multimesh_get_command_buffer_rd_rid(RID p_multimesh) const = 0;
virtual RID multimesh_get_buffer_rd_rid(RID p_multimesh) const = 0;
virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0;