Add instancer_mode

This commit is contained in:
Cory Petkovsek 2025-11-25 01:46:03 +07:00
parent 25d581d79a
commit 0503cb1b27
4 changed files with 59 additions and 22 deletions

View File

@ -1118,7 +1118,7 @@ void Terrain3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_physics_material", "material"), &Terrain3D::set_physics_material);
ClassDB::bind_method(D_METHOD("get_physics_material"), &Terrain3D::get_physics_material);
// Meshes
// Mesh
ClassDB::bind_method(D_METHOD("set_mesh_lods", "count"), &Terrain3D::set_mesh_lods);
ClassDB::bind_method(D_METHOD("get_mesh_lods"), &Terrain3D::get_mesh_lods);
ClassDB::bind_method(D_METHOD("set_mesh_size", "size"), &Terrain3D::set_mesh_size);
@ -1139,8 +1139,8 @@ void Terrain3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_cull_margin"), &Terrain3D::get_cull_margin);
ClassDB::bind_method(D_METHOD("set_free_editor_textures"), &Terrain3D::set_free_editor_textures);
ClassDB::bind_method(D_METHOD("get_free_editor_textures"), &Terrain3D::get_free_editor_textures);
ClassDB::bind_method(D_METHOD("set_show_instances", "visible"), &Terrain3D::set_show_instances);
ClassDB::bind_method(D_METHOD("get_show_instances"), &Terrain3D::get_show_instances);
ClassDB::bind_method(D_METHOD("set_instancer_mode", "mode"), &Terrain3D::set_instancer_mode);
ClassDB::bind_method(D_METHOD("get_instancer_mode"), &Terrain3D::get_instancer_mode);
// Overlays
ClassDB::bind_method(D_METHOD("set_show_region_grid", "enabled"), &Terrain3D::set_show_region_grid);
@ -1219,7 +1219,7 @@ void Terrain3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material", "get_physics_material");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collision_target", PROPERTY_HINT_NODE_TYPE, "Node3D", PROPERTY_USAGE_DEFAULT, "Node3D"), "set_collision_target", "get_collision_target");
ADD_GROUP("Mesh", "");
ADD_GROUP("Clipmap Mesh", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mesh_lods", PROPERTY_HINT_RANGE, "1,10,1"), "set_mesh_lods", "get_mesh_lods");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mesh_size", PROPERTY_HINT_RANGE, "8,256,2"), "set_mesh_size", "get_mesh_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vertex_spacing", PROPERTY_HINT_RANGE, "0.25,10.0,0.05,or_greater"), "set_vertex_spacing", "get_vertex_spacing");
@ -1232,7 +1232,7 @@ void Terrain3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Static,Dynamic"), "set_gi_mode", "get_gi_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cull_margin", PROPERTY_HINT_RANGE, "0.0,10000.0,.5,or_greater"), "set_cull_margin", "get_cull_margin");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "free_editor_textures"), "set_free_editor_textures", "get_free_editor_textures");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_instances"), "set_show_instances", "get_show_instances");
ADD_PROPERTY(PropertyInfo(Variant::INT, "instancer_mode", PROPERTY_HINT_ENUM, "Disabled,Normal"), "set_instancer_mode", "get_instancer_mode");
ADD_GROUP("Overlays", "show_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_region_grid"), "set_show_region_grid", "get_show_region_grid");

View File

@ -165,7 +165,7 @@ public:
int get_label_size() const { return _label_size; }
void update_region_labels();
// Meshes
// Mesh
void set_mesh_lods(const int p_count);
int get_mesh_lods() const { return _mesh_lods; }
void set_mesh_size(const int p_size);
@ -186,8 +186,6 @@ public:
real_t get_cull_margin() const { return _cull_margin; };
void set_free_editor_textures(const bool p_free_textures) { _free_editor_textures = p_free_textures; }
bool get_free_editor_textures() const { return _free_editor_textures; };
void set_show_instances(const bool p_visible) { _instancer ? _instancer->set_show_instances(p_visible) : void(); }
bool get_show_instances() const { return _instancer ? _instancer->get_show_instances() : true; }
// Utility
Vector3 get_intersection(const Vector3 &p_src_pos, const Vector3 &p_direction, const bool p_gpu_mode = false);
@ -216,6 +214,10 @@ public:
void set_physics_material(const Ref<PhysicsMaterial> &p_mat) { _collision ? _collision->set_physics_material(p_mat) : void(); }
Ref<PhysicsMaterial> get_physics_material() const { return _collision ? _collision->get_physics_material() : Ref<PhysicsMaterial>(); }
// Instancer Aliases
void set_instancer_mode(const InstancerMode p_mode) { _instancer ? _instancer->set_mode(p_mode) : void(); }
InstancerMode get_instancer_mode() const { return _instancer ? _instancer->get_mode() : InstancerMode::NORMAL; }
// Overlay Aliases
void set_show_region_grid(const bool p_enabled) { _material.is_valid() ? _material->set_show_region_grid(p_enabled) : void(); }
bool get_show_region_grid() const { return _material.is_valid() ? _material->get_show_region_grid() : false; }

View File

@ -34,9 +34,9 @@ void Terrain3DInstancer::_process_updates() {
bool update_all = false;
if (_queued_updates.find({ V2I_MAX, -2 }) != _queued_updates.end()) {
destroy();
update_all = _show_instances;
update_all = true;
} else if (_queued_updates.find({ V2I_MAX, -1 }) != _queued_updates.end()) {
update_all = _show_instances;
update_all = true;
}
if (update_all) {
@ -437,7 +437,6 @@ void Terrain3DInstancer::_destroy_mmi_by_cell(const Vector2i &p_region_loc, cons
ma->update_instance_count(-RS->multimesh_get_instance_count(mm));
}
}
LOG(EXTREME, "Freeing mmi:", mmi, ", mm:", mm, " and erasing mmi cell ", p_cell);
if (mmi.is_valid()) {
RS->free_rid(mmi);
@ -479,6 +478,9 @@ void Terrain3DInstancer::_backup_region(const Ref<Terrain3DRegion> &p_region) {
RID Terrain3DInstancer::_create_multimesh(const int p_mesh_id, const int p_lod, const TypedArray<Transform3D> &p_xforms, const PackedColorArray &p_colors) const {
RID mm;
IS_INIT(mm);
if (p_xforms.size() == 0) {
return mm;
}
Ref<Terrain3DMeshAsset> mesh_asset = _terrain->get_assets()->get_mesh_asset(p_mesh_id);
if (mesh_asset.is_null()) {
LOG(ERROR, "No mesh id ", p_mesh_id, " found");
@ -606,6 +608,23 @@ void Terrain3DInstancer::clear_by_region(const Ref<Terrain3DRegion> &p_region, c
_destroy_mmi_by_location(region_loc, p_mesh_id);
}
void Terrain3DInstancer::set_mode(const InstancerMode p_mode) {
LOG(INFO, "Setting instancer mode: ", p_mode);
if (p_mode != _mode) {
_mode = p_mode;
switch (_mode) {
case NORMAL:
update_mmis(-1, V2I_MAX, true);
break;
//case PLACEHOLDER:
// break;
default:
destroy();
break;
}
}
}
void Terrain3DInstancer::add_instances(const Vector3 &p_global_position, const Dictionary &p_params) {
IS_DATA_INIT_MESG("Instancer isn't initialized.", VOID);
int mesh_id = p_params.get("asset_id", 0);
@ -1276,6 +1295,10 @@ void Terrain3DInstancer::swap_ids(const int p_src_id, const int p_dst_id) {
// If mesh_id < 0, will do all meshes in the specified region
// You safely can call multiple times per frame, and select any combo of options without fillling up the queue.
void Terrain3DInstancer::update_mmis(const int p_mesh_id, const Vector2i &p_region_loc, const bool p_rebuild) {
if (_mode == DISABLED) {
LOG(INFO, "Instancer is disabled");
return;
}
LOG(INFO, "Queueing MMI update for mesh id: ", p_mesh_id < 0 ? "all" : String::num_int64(p_mesh_id),
", region: ", p_region_loc == V2I_MAX ? "all" : String(p_region_loc),
p_rebuild ? ", destroying first" : "");
@ -1314,20 +1337,21 @@ void Terrain3DInstancer::update_mmis(const int p_mesh_id, const Vector2i &p_regi
}
}
void Terrain3DInstancer::set_show_instances(const bool p_visible) {
SET_IF_DIFF(_show_instances, p_visible);
LOG(INFO, "Setting instancer visibility to: ", p_visible);
update_mmis(-1, V2I_MAX, true);
}
///////////////////////////
// Protected Functions
///////////////////////////
void Terrain3DInstancer::_bind_methods() {
BIND_ENUM_CONSTANT(NORMAL);
//BIND_ENUM_CONSTANT(PLACEHOLDER);
BIND_ENUM_CONSTANT(DISABLED);
ClassDB::bind_method(D_METHOD("clear_by_mesh", "mesh_id"), &Terrain3DInstancer::clear_by_mesh);
ClassDB::bind_method(D_METHOD("clear_by_location", "region_location", "mesh_id"), &Terrain3DInstancer::clear_by_location);
ClassDB::bind_method(D_METHOD("clear_by_region", "region", "mesh_id"), &Terrain3DInstancer::clear_by_region);
ClassDB::bind_method(D_METHOD("set_mode", "mode"), &Terrain3DInstancer::set_mode);
ClassDB::bind_method(D_METHOD("get_mode"), &Terrain3DInstancer::get_mode);
ClassDB::bind_method(D_METHOD("is_enabled"), &Terrain3DInstancer::is_enabled);
ClassDB::bind_method(D_METHOD("add_instances", "global_position", "params"), &Terrain3DInstancer::add_instances);
ClassDB::bind_method(D_METHOD("remove_instances", "global_position", "params"), &Terrain3DInstancer::remove_instances);
ClassDB::bind_method(D_METHOD("add_multimesh", "mesh_id", "multimesh", "transform", "update"), &Terrain3DInstancer::add_multimesh, DEFVAL(Transform3D()), DEFVAL(true));
@ -1338,6 +1362,6 @@ void Terrain3DInstancer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_closest_mesh_id", "global_position"), &Terrain3DInstancer::get_closest_mesh_id);
ClassDB::bind_method(D_METHOD("update_mmis", "mesh_id", "region_location", "rebuild_all"), &Terrain3DInstancer::update_mmis, DEFVAL(-1), DEFVAL(V2I_MAX), DEFVAL(false));
ClassDB::bind_method(D_METHOD("swap_ids", "src_id", "dest_id"), &Terrain3DInstancer::swap_ids);
ClassDB::bind_method(D_METHOD("set_show_instances", "p_visible"), &Terrain3DInstancer::set_show_instances);
ClassDB::bind_method(D_METHOD("get_show_instances"), &Terrain3DInstancer::get_show_instances);
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Disabled,Normal"), "set_mode", "get_mode");
}

View File

@ -22,6 +22,12 @@ class Terrain3DInstancer : public Object {
public: // Constants
static inline const int CELL_SIZE = 32;
enum InstancerMode {
DISABLED,
//PLACEHOLDER,
NORMAL,
};
private:
Terrain3D *_terrain = nullptr;
@ -43,8 +49,8 @@ private:
using V2IIntPair = std::unordered_set<std::pair<Vector2i, int>, PairVector2iIntHash>;
V2IIntPair _queued_updates;
InstancerMode _mode = NORMAL;
uint32_t _density_counter = 0;
bool _show_instances = true;
uint32_t _get_density_count(const real_t p_density);
int _get_master_lod(const Ref<Terrain3DMeshAsset> &p_ma);
@ -71,6 +77,10 @@ public:
void clear_by_location(const Vector2i &p_region_loc, const int p_mesh_id);
void clear_by_region(const Ref<Terrain3DRegion> &p_region, const int p_mesh_id);
void set_mode(const InstancerMode p_mode);
InstancerMode get_mode() const { return _mode; }
bool is_enabled() const { return _mode != DISABLED; }
void add_instances(const Vector3 &p_global_position, const Dictionary &p_params);
void remove_instances(const Vector3 &p_global_position, const Dictionary &p_params);
void add_multimesh(const int p_mesh_id, const Ref<MultiMesh> &p_multimesh, const Transform3D &p_xform = Transform3D(), const bool p_update = true);
@ -87,13 +97,14 @@ public:
void update_mmis(const int p_mesh_id = -1, const Vector2i &p_region_loc = V2I_MAX, const bool p_rebuild = false);
void reset_density_counter() { _density_counter = 0; }
void set_show_instances(const bool p_visible);
bool get_show_instances() const { return _show_instances; }
protected:
static void _bind_methods();
};
using InstancerMode = Terrain3DInstancer::InstancerMode;
VARIANT_ENUM_CAST(Terrain3DInstancer::InstancerMode);
// Allows us to instance every X function calls for sparse placement
// Modifies _density_counter, not const!
inline uint32_t Terrain3DInstancer::_get_density_count(const real_t p_density) {