Skip to content

Commit

Permalink
Add override to multimeshinstance3d
Browse files Browse the repository at this point in the history
  • Loading branch information
tetrapod00 committed Aug 30, 2024
1 parent db24ed4 commit 72afd12
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 1 deletion.
173 changes: 172 additions & 1 deletion scene/3d/multimesh_instance_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,66 @@ void MultiMeshInstance3D::_physics_interpolated_changed() {
_refresh_interpolated();
}

bool MultiMeshInstance3D::_set(const StringName &p_name, const Variant &p_value) {
//this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else.
//add to it that it's probably found on first call to _set anyway.

if (!get_instance().is_valid()) {
return false;
}

if (p_name.operator String().begins_with("surface_material_override/")) {
int idx = p_name.operator String().get_slicec('/', 1).to_int();

if (idx >= surface_override_materials.size() || idx < 0) {
return false;
}

set_surface_override_material(idx, p_value);
return true;
}

return false;
}

bool MultiMeshInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
if (!get_instance().is_valid()) {
return false;
}

if (p_name.operator String().begins_with("surface_material_override/")) {
int idx = p_name.operator String().get_slicec('/', 1).to_int();
if (idx >= surface_override_materials.size() || idx < 0) {
return false;
}
r_ret = surface_override_materials[idx];
return true;
}
return false;
}

void MultiMeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
if (multimesh.is_valid()) {
Ref<Mesh> mesh = multimesh->get_mesh();
if (mesh.is_valid()) {
for (int i = 0; i < mesh->get_surface_count(); i++) {
p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("%s/%d", PNAME("surface_material_override"), i), PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_DEFAULT));
}
}
}


}

void MultiMeshInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_multimesh", "multimesh"), &MultiMeshInstance3D::set_multimesh);
ClassDB::bind_method(D_METHOD("get_multimesh"), &MultiMeshInstance3D::get_multimesh);

ClassDB::bind_method(D_METHOD("get_surface_override_material_count"), &MultiMeshInstance3D::get_surface_override_material_count);
ClassDB::bind_method(D_METHOD("set_surface_override_material", "surface", "material"), &MultiMeshInstance3D::set_surface_override_material);
ClassDB::bind_method(D_METHOD("get_surface_override_material", "surface"), &MultiMeshInstance3D::get_surface_override_material);
ClassDB::bind_method(D_METHOD("get_active_material", "surface"), &MultiMeshInstance3D::get_active_material);

ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multimesh", PROPERTY_HINT_RESOURCE_TYPE, "MultiMesh"), "set_multimesh", "get_multimesh");
}

Expand All @@ -54,14 +111,86 @@ void MultiMeshInstance3D::_notification(int p_what) {
}
}

void MultiMeshInstance3D::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "multimesh") {
WARN_PRINT_ED("Multimesh validated.");
}
}

void MultiMeshInstance3D::_multimesh_changed() {

ERR_FAIL_COND(multimesh.is_null());

Ref<Mesh> mesh = multimesh->get_mesh();
WARN_PRINT_ED("Multimesh changed.");

if (mesh.is_valid()) {
surface_override_materials.resize(mesh->get_surface_count());

int surface_count = mesh->get_surface_count();
for (int surface_index = 0; surface_index < surface_count; ++surface_index) {
if (surface_override_materials[surface_index].is_valid()) {
RS::get_singleton()->multimesh_set_surface_override_material(get_instance(), surface_index, surface_override_materials[surface_index]->get_rid());
}
}
} else {
surface_override_materials.resize(0);
}

//notify_property_list_changed();
}

void MultiMeshInstance3D::set_multimesh(const Ref<MultiMesh> &p_multimesh) {
multimesh = p_multimesh;
if (multimesh == p_multimesh) {
return;
}

if (multimesh.is_valid()) {
multimesh->disconnect_changed(callable_mp(this, &MultiMeshInstance3D::_multimesh_changed));
}

multimesh = p_multimesh;

if (multimesh.is_valid()) {
set_base(multimesh->get_rid());

multimesh->connect_changed(callable_mp(this, &MultiMeshInstance3D::_multimesh_changed));
_multimesh_changed();

_refresh_interpolated();

} else {
set_base(RID());
}

notify_property_list_changed();

// multimesh = p_multimesh;

// if (multimesh.is_valid()) {
// set_base(multimesh->get_rid());

// // Adapted from MeshInstance3D::_mesh_changed() and inlined.
// Ref<Mesh> mesh = multimesh->get_mesh();
// if (mesh.is_valid()) {
// surface_override_materials.resize(mesh->get_surface_count());

// int surface_count = mesh->get_surface_count();
// for (int surface_index = 0; surface_index < surface_count; ++surface_index) {
// if (surface_override_materials[surface_index].is_valid()) {
// RS::get_singleton()->multimesh_set_surface_override_material(get_instance(), surface_index, surface_override_materials[surface_index]->get_rid());
// }
// }
// } else {
// surface_override_materials.resize(0);
// }

// _refresh_interpolated();
// } else {
// set_base(RID());
// }

// notify_property_list_changed();
}

Ref<MultiMesh> MultiMeshInstance3D::get_multimesh() const {
Expand All @@ -88,6 +217,48 @@ Array MultiMeshInstance3D::get_meshes() const {
return results;
}

int MultiMeshInstance3D::get_surface_override_material_count() const {
return surface_override_materials.size();
}

void MultiMeshInstance3D::set_surface_override_material(int p_surface, const Ref<Material> &p_material) {
ERR_FAIL_INDEX(p_surface, surface_override_materials.size());

surface_override_materials.write[p_surface] = p_material;

if (surface_override_materials[p_surface].is_valid()) {
RS::get_singleton()->multimesh_set_surface_override_material(get_instance(), p_surface, surface_override_materials[p_surface]->get_rid());
} else {
RS::get_singleton()->multimesh_set_surface_override_material(get_instance(), p_surface, RID());
}
}

Ref<Material> MultiMeshInstance3D::get_surface_override_material(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, surface_override_materials.size(), Ref<Material>());

return surface_override_materials[p_surface];
}

Ref<Material> MultiMeshInstance3D::get_active_material(int p_surface) const {
Ref<Material> mat_override = get_material_override();
if (mat_override.is_valid()) {
return mat_override;
}

Ref<Material> surface_material = get_surface_override_material(p_surface);
if (surface_material.is_valid()) {
return surface_material;
}

// Ref<Mesh> m = get_mesh();
Ref<Mesh> m = multimesh.is_valid() ? multimesh->get_mesh() : Ref<Mesh>();
if (m.is_valid()) {
return m->surface_get_material(p_surface);
}

return Ref<Material>();
}

AABB MultiMeshInstance3D::get_aabb() const {
if (multimesh.is_null()) {
return AABB();
Expand Down
14 changes: 14 additions & 0 deletions scene/3d/multimesh_instance_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,30 @@ class MultiMeshInstance3D : public GeometryInstance3D {
void _refresh_interpolated();

protected:
void _multimesh_changed();

bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;

virtual void _physics_interpolated_changed() override;
void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
void _notification(int p_what);
void _validate_property(PropertyInfo &p_property) const;

Vector<Ref<Material>> surface_override_materials;

public:
void set_multimesh(const Ref<MultiMesh> &p_multimesh);
Ref<MultiMesh> get_multimesh() const;

Array get_meshes() const;

int get_surface_override_material_count() const;
void set_surface_override_material(int p_surface, const Ref<Material> &p_material);
Ref<Material> get_surface_override_material(int p_surface) const;
Ref<Material> get_active_material(int p_surface) const;

virtual AABB get_aabb() const override;

MultiMeshInstance3D();
Expand Down
23 changes: 23 additions & 0 deletions servers/rendering/renderer_scene_cull.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1097,6 +1097,26 @@ void RendererSceneCull::instance_set_surface_override_material(RID p_instance, i
_instance_queue_update(instance, false, true);
}

void RendererSceneCull::multimesh_set_surface_override_material(RID p_instance, int p_surface, RID p_material) {
Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_NULL(instance);

if (instance->base_type == RS::INSTANCE_MULTIMESH) {
RID mesh = RSG::mesh_storage->multimesh_get_mesh(instance->base);
//if (mesh.is_valid()) {
{
//may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case
instance->materials.resize(MAX(p_surface + 1, RSG::mesh_storage->mesh_get_surface_count(mesh)));
}
}

ERR_FAIL_INDEX(p_surface, instance->materials.size());

instance->materials.write[p_surface] = p_material;

_instance_queue_update(instance, false, true);
}

void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) {
Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_NULL(instance);
Expand Down Expand Up @@ -4125,8 +4145,11 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
bool cast_shadows = false;

int sc = RSG::mesh_storage->mesh_get_surface_count(mesh);
// int mc = p_instance->materials.size();
// sc = MIN(sc,mc);
for (int i = 0; i < sc; i++) {
RID mat = RSG::mesh_storage->mesh_surface_get_material(mesh, i);
//RID mat = p_instance->materials[i].is_valid() ? p_instance->materials[i] : RSG::mesh_storage->mesh_surface_get_material(mesh, i);

if (!mat.is_valid()) {
cast_shadows = true;
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/renderer_scene_cull.h
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,8 @@ class RendererSceneCull : public RenderingMethod {
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id);
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight);
virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material);
virtual void multimesh_set_surface_override_material(RID p_instance, int p_surface, RID p_material);

virtual void instance_set_visible(RID p_instance, bool p_visible);
virtual void instance_geometry_set_transparency(RID p_instance, float p_transparency);

Expand Down
1 change: 1 addition & 0 deletions servers/rendering/rendering_method.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class RenderingMethod {
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0;
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0;
virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0;
virtual void multimesh_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0;
virtual void instance_set_visible(RID p_instance, bool p_visible) = 0;
virtual void instance_geometry_set_transparency(RID p_instance, float p_transparency) = 0;

Expand Down
4 changes: 4 additions & 0 deletions servers/rendering/rendering_server_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ class RenderingServerDefault : public RenderingServer {
FUNC1RC(int, multimesh_get_instance_count, RID)

FUNC2(multimesh_set_mesh, RID, RID)

// FUNC3(multimesh_set_surface_override_material, RID, int, RID)

FUNC3(multimesh_instance_set_transform, RID, int, const Transform3D &)
FUNC3(multimesh_instance_set_transform_2d, RID, int, const Transform2D &)
FUNC3(multimesh_instance_set_color, RID, int, const Color &)
Expand Down Expand Up @@ -814,6 +817,7 @@ class RenderingServerDefault : public RenderingServer {
FUNC2(instance_attach_object_instance_id, RID, ObjectID)
FUNC3(instance_set_blend_shape_weight, RID, int, float)
FUNC3(instance_set_surface_override_material, RID, int, RID)
FUNC3(multimesh_set_surface_override_material, RID, int, RID)
FUNC2(instance_set_visible, RID, bool)

FUNC2(instance_set_custom_aabb, RID, AABB)
Expand Down
1 change: 1 addition & 0 deletions servers/rendering_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2422,6 +2422,7 @@ void RenderingServer::_bind_methods() {
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_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_set_surface_override_material", "multimesh", "surface", "material"), &RenderingServer::multimesh_set_surface_override_material);
ClassDB::bind_method(D_METHOD("multimesh_instance_set_transform", "multimesh", "index", "transform"), &RenderingServer::multimesh_instance_set_transform);
ClassDB::bind_method(D_METHOD("multimesh_instance_set_transform_2d", "multimesh", "index", "transform"), &RenderingServer::multimesh_instance_set_transform_2d);
ClassDB::bind_method(D_METHOD("multimesh_instance_set_color", "multimesh", "index", "color"), &RenderingServer::multimesh_instance_set_color);
Expand Down
1 change: 1 addition & 0 deletions servers/rendering_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ class RenderingServer : public Object {
virtual int multimesh_get_instance_count(RID p_multimesh) const = 0;

virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
virtual void multimesh_set_surface_override_material(RID p_multimesh, int p_surface, RID p_material) = 0;
virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) = 0;
virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0;
virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
Expand Down

0 comments on commit 72afd12

Please sign in to comment.