Convert instancer MMI nodes to RS
This commit is contained in:
parent
8cade44ba9
commit
4bdb15c476
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
|
// Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
|
||||||
|
|
||||||
#include <godot_cpp/classes/resource_saver.hpp>
|
#include <godot_cpp/classes/resource_saver.hpp>
|
||||||
|
#include <godot_cpp/classes/world3d.hpp>
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "terrain_3d_instancer.h"
|
#include "terrain_3d_instancer.h"
|
||||||
|
|
@ -111,15 +111,8 @@ void Terrain3DInstancer::_update_mmi_by_region(const Terrain3DRegion *p_region,
|
||||||
Vector2i region_loc = p_region->get_location();
|
Vector2i region_loc = p_region->get_location();
|
||||||
Dictionary mesh_inst_dict = p_region->get_instances();
|
Dictionary mesh_inst_dict = p_region->get_instances();
|
||||||
|
|
||||||
// Create MMI container if needed (always, per region)
|
// Get or create mesh dict
|
||||||
String rname("Region" + Util::location_to_string(region_loc));
|
MeshMMIDict &mesh_mmi_dict = _mmi_nodes[region_loc];
|
||||||
if (_mmi_containers.count(region_loc) == 0) {
|
|
||||||
LOG(DEBUG, "Creating new region MMI container Terrain3D/MMI/", rname);
|
|
||||||
Node3D *node = memnew(Node3D);
|
|
||||||
node->set_name(rname);
|
|
||||||
_mmi_containers[region_loc] = node;
|
|
||||||
_terrain->get_mmi_parent()->add_child(node, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify mesh id is valid, enabled, and has MeshInstance3Ds
|
// Verify mesh id is valid, enabled, and has MeshInstance3Ds
|
||||||
Ref<Terrain3DMeshAsset> ma = _terrain->get_assets()->get_mesh_asset(p_mesh_id);
|
Ref<Terrain3DMeshAsset> ma = _terrain->get_assets()->get_mesh_asset(p_mesh_id);
|
||||||
|
|
@ -142,6 +135,7 @@ void Terrain3DInstancer::_update_mmi_by_region(const Terrain3DRegion *p_region,
|
||||||
// Process cells
|
// Process cells
|
||||||
Dictionary cell_inst_dict = mesh_inst_dict[p_mesh_id];
|
Dictionary cell_inst_dict = mesh_inst_dict[p_mesh_id];
|
||||||
Array cell_locations = cell_inst_dict.keys();
|
Array cell_locations = cell_inst_dict.keys();
|
||||||
|
RID shadow_impostor_source_mm;
|
||||||
|
|
||||||
for (int c = 0; c < cell_locations.size(); c++) {
|
for (int c = 0; c < cell_locations.size(); c++) {
|
||||||
Vector2i cell = cell_locations[c];
|
Vector2i cell = cell_locations[c];
|
||||||
|
|
@ -179,8 +173,7 @@ void Terrain3DInstancer::_update_mmi_by_region(const Terrain3DRegion *p_region,
|
||||||
|
|
||||||
// Get or create mesh dict (defined here as cleanup above might invalidate it)
|
// Get or create mesh dict (defined here as cleanup above might invalidate it)
|
||||||
MeshMMIDict &mesh_mmi_dict = _mmi_nodes[region_loc];
|
MeshMMIDict &mesh_mmi_dict = _mmi_nodes[region_loc];
|
||||||
Ref<MultiMesh> shadow_impostor_source_mm;
|
|
||||||
|
|
||||||
for (int lod = ma->get_last_lod(); lod >= Terrain3DMeshAsset::SHADOW_LOD_ID; lod--) {
|
for (int lod = ma->get_last_lod(); lod >= Terrain3DMeshAsset::SHADOW_LOD_ID; lod--) {
|
||||||
// Don't create shadow MMI if not needed
|
// Don't create shadow MMI if not needed
|
||||||
if (lod == Terrain3DMeshAsset::SHADOW_LOD_ID && shadow_lod_disabled) {
|
if (lod == Terrain3DMeshAsset::SHADOW_LOD_ID && shadow_lod_disabled) {
|
||||||
|
|
@ -195,38 +188,23 @@ void Terrain3DInstancer::_update_mmi_by_region(const Terrain3DRegion *p_region,
|
||||||
// Get or create MMI - [] creates key if missing
|
// Get or create MMI - [] creates key if missing
|
||||||
Vector2i mesh_key(p_mesh_id, lod);
|
Vector2i mesh_key(p_mesh_id, lod);
|
||||||
CellMMIDict &cell_mmi_dict = mesh_mmi_dict[mesh_key];
|
CellMMIDict &cell_mmi_dict = mesh_mmi_dict[mesh_key];
|
||||||
MultiMeshInstance3D *mmi = cell_mmi_dict[cell]; // null if missing
|
RID &mmi = cell_mmi_dict[cell].first; // null if missing
|
||||||
if (!mmi) {
|
if (!mmi.is_valid()) {
|
||||||
mmi = memnew(MultiMeshInstance3D);
|
mmi = RS->instance_create();
|
||||||
LOG(EXTREME, "No MMI found, Created new MultiMeshInstance3D for cell ", cell, ": ", ptr_to_str(mmi));
|
RS->instance_set_scenario(mmi, _terrain->get_world_3d()->get_scenario());
|
||||||
// Node name is MMI3D_Cell##_##_Mesh#_LOD#
|
|
||||||
String cstring = "_C" + Util::location_to_string(cell).trim_prefix("_");
|
|
||||||
String mstring = "_M" + String::num_int64(p_mesh_id);
|
|
||||||
String lstring = "_L" + ((lod == Terrain3DMeshAsset::SHADOW_LOD_ID) ? "S" : String::num_int64(lod));
|
|
||||||
mmi->set_name("MMI3D" + cstring + mstring + lstring);
|
|
||||||
cell_mmi_dict[cell] = mmi;
|
|
||||||
|
|
||||||
//Attach to tree
|
|
||||||
Node *node_container = _terrain->get_mmi_parent()->get_node_internal(rname);
|
|
||||||
if (!node_container) {
|
|
||||||
LOG(ERROR, rname, " isn't attached to the tree.");
|
|
||||||
memdelete(mmi);
|
|
||||||
cell_mmi_dict.erase(cell);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
node_container->add_child(mmi, true);
|
|
||||||
modified = true; // New MMI needs full update
|
modified = true; // New MMI needs full update
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always update MMI propertiess
|
// Always update MMI propertiess
|
||||||
if (ma->is_highlighted()) {
|
if (ma->is_highlighted()) {
|
||||||
mmi->set_material_override(ma->get_highlight_material());
|
RS->instance_geometry_set_material_override(mmi, ma->get_highlight_material().is_valid() ? ma->get_highlight_material()->get_rid() : RID());
|
||||||
mmi->set_material_overlay(Ref<Material>());
|
RS->instance_geometry_set_material_overlay(mmi, RID());
|
||||||
} else {
|
} else {
|
||||||
mmi->set_material_override(ma->get_material_override());
|
RS->instance_geometry_set_material_override(mmi, ma->get_material_override().is_valid() ? ma->get_material_override()->get_rid() : RID());
|
||||||
mmi->set_material_overlay(ma->get_material_overlay());
|
RS->instance_geometry_set_material_overlay(mmi, ma->get_material_overlay().is_valid() ? ma->get_material_overlay()->get_rid() : RID());
|
||||||
}
|
}
|
||||||
mmi->set_cast_shadows_setting(ma->get_lod_cast_shadows(lod));
|
RS->instance_geometry_set_cast_shadows_setting(mmi, ma->get_lod_cast_shadows(lod));
|
||||||
|
RS->instance_set_layer_mask(mmi, ma->get_visibility_layers());
|
||||||
_set_mmi_lod_ranges(mmi, ma, lod);
|
_set_mmi_lod_ranges(mmi, ma, lod);
|
||||||
|
|
||||||
// Reposition MMI to region location
|
// Reposition MMI to region location
|
||||||
|
|
@ -235,40 +213,37 @@ void Terrain3DInstancer::_update_mmi_by_region(const Terrain3DRegion *p_region,
|
||||||
real_t vertex_spacing = _terrain->get_vertex_spacing();
|
real_t vertex_spacing = _terrain->get_vertex_spacing();
|
||||||
t.origin.x += region_loc.x * region_size * vertex_spacing;
|
t.origin.x += region_loc.x * region_size * vertex_spacing;
|
||||||
t.origin.z += region_loc.y * region_size * vertex_spacing;
|
t.origin.z += region_loc.y * region_size * vertex_spacing;
|
||||||
mmi->set_as_top_level(true);
|
|
||||||
mmi->set_global_transform(t);
|
|
||||||
|
|
||||||
|
RS->instance_set_transform(mmi, t);
|
||||||
|
|
||||||
|
RID &mm = cell_mmi_dict[cell].second;
|
||||||
// Only recreate MultiMesh if modified/no existing (with override for shadow)
|
// Only recreate MultiMesh if modified/no existing (with override for shadow)
|
||||||
// Always update shadow MMI (source may have changed)
|
// Always update shadow MMI (source may have changed)
|
||||||
if (modified || mmi->get_multimesh().is_null() ||
|
if (modified || !mm.is_valid() ||
|
||||||
lod == Terrain3DMeshAsset::SHADOW_LOD_ID) {
|
lod == Terrain3DMeshAsset::SHADOW_LOD_ID) {
|
||||||
// Subtract previous instance count of this MMI
|
// Subtract previous instance count for this cell
|
||||||
if (lod == 0) {
|
if (mm.is_valid() && lod == ma->get_last_lod()) {
|
||||||
if (mmi->get_multimesh().is_valid()) {
|
ma->update_instance_count(-RS->multimesh_get_instance_count(mm));
|
||||||
ma->update_instance_count(-mmi->get_multimesh()->get_instance_count());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<MultiMesh> mm;
|
|
||||||
if (lod == Terrain3DMeshAsset::SHADOW_LOD_ID) {
|
if (lod == Terrain3DMeshAsset::SHADOW_LOD_ID) {
|
||||||
// Reuse impostor LOD MM as shadow impostor
|
// Reuse impostor LOD MM as shadow impostor
|
||||||
mm = shadow_impostor_source_mm;
|
mm = shadow_impostor_source_mm;
|
||||||
if (mm.is_null()) {
|
if (!mm.is_valid()) {
|
||||||
LOG(ERROR, "Shadow MM is null for cell ", cell, " lod ", lod, " xforms: ", xforms.size());
|
LOG(ERROR, "Shadow MM is null for cell ", cell, " lod ", lod, " xforms: ", xforms.size());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mm = _create_multimesh(p_mesh_id, lod, xforms, colors);
|
mm = _create_multimesh(p_mesh_id, lod, xforms, colors);
|
||||||
}
|
}
|
||||||
if (mm.is_null()) {
|
if (!mm.is_valid()) {
|
||||||
LOG(ERROR, "Null MM for cell ", cell, " lod ", lod, " xforms: ", xforms.size());
|
LOG(ERROR, "Null MM for cell ", cell, " lod ", lod, " xforms: ", xforms.size());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mmi->set_multimesh(mm);
|
RS->instance_set_base(mmi, mm);
|
||||||
|
|
||||||
// Add current instance count of this new MMI
|
// Add current instance count for this cell
|
||||||
if (lod == 0) {
|
if (lod == 0) {
|
||||||
ma->update_instance_count(mm->get_instance_count());
|
ma->update_instance_count(RS->multimesh_get_instance_count(mm));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear modified only for visible LODs
|
// Clear modified only for visible LODs
|
||||||
|
|
@ -277,40 +252,43 @@ void Terrain3DInstancer::_update_mmi_by_region(const Terrain3DRegion *p_region,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Needed to update generated mesh changes
|
// Needed to update generated mesh changes
|
||||||
mmi->get_multimesh()->set_mesh(ma->get_mesh(lod));
|
RS->multimesh_set_mesh(mm, ma->get_mesh(lod)->get_rid());
|
||||||
}
|
}
|
||||||
// Capture source MM from shadow impostor LOD
|
// Capture source MM from shadow impostor LOD
|
||||||
if (lod == ma->get_shadow_impostor()) {
|
if (lod == ma->get_shadow_impostor()) {
|
||||||
shadow_impostor_source_mm = mmi->get_multimesh();
|
shadow_impostor_source_mm = RS->multimesh_get_mesh(mm);
|
||||||
}
|
}
|
||||||
} // End for LOD loop
|
} // End for LOD loop
|
||||||
|
|
||||||
// Set all LOD mmi AABB to match LOD0 to ensure no gaps between transitions.
|
// Set all LOD mmi AABB to match LOD0 to ensure no gaps between transitions.
|
||||||
AABB mmi_custom_aabb;
|
AABB mm_custom_aabb;
|
||||||
for (int lod = 0; lod <= ma->get_last_lod(); lod++) {
|
for (int lod = 0; lod <= ma->get_last_lod(); lod++) {
|
||||||
Vector2i mesh_key(p_mesh_id, lod);
|
Vector2i mesh_key(p_mesh_id, lod);
|
||||||
CellMMIDict &cell_mmi_dict = mesh_mmi_dict[mesh_key];
|
CellMMIDict &cell_mmi_dict = mesh_mmi_dict[mesh_key];
|
||||||
MultiMeshInstance3D *mmi = cell_mmi_dict[cell];
|
RID &mmi = cell_mmi_dict[cell].first;
|
||||||
if (mmi) {
|
RID &mm = cell_mmi_dict[cell].second;
|
||||||
|
if (mm.is_valid()) {
|
||||||
if (lod == 0) {
|
if (lod == 0) {
|
||||||
mmi_custom_aabb = mmi->get_aabb();
|
mm_custom_aabb = RS->multimesh_get_aabb(mm);
|
||||||
} else {
|
} else {
|
||||||
mmi->set_custom_aabb(mmi_custom_aabb);
|
RS->multimesh_set_custom_aabb(mm, mm_custom_aabb);
|
||||||
}
|
}
|
||||||
|
RS->instance_set_custom_aabb(mmi, mm_custom_aabb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ma->get_shadow_impostor() > 0) {
|
if (ma->get_shadow_impostor() > 0) {
|
||||||
Vector2i mesh_key(p_mesh_id, Terrain3DMeshAsset::SHADOW_LOD_ID);
|
Vector2i mesh_key(p_mesh_id, Terrain3DMeshAsset::SHADOW_LOD_ID);
|
||||||
CellMMIDict &cell_mmi_dict = mesh_mmi_dict[mesh_key];
|
CellMMIDict &cell_mmi_dict = mesh_mmi_dict[mesh_key];
|
||||||
MultiMeshInstance3D *mmi = cell_mmi_dict[cell];
|
//RID &mmi = cell_mmi_dict[cell].first;
|
||||||
if (mmi) {
|
RID &mm = cell_mmi_dict[cell].second;
|
||||||
mmi->set_custom_aabb(mmi_custom_aabb);
|
if (mm.is_valid()) {
|
||||||
|
RS->multimesh_set_custom_aabb(mm, mm_custom_aabb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terrain3DInstancer::_set_mmi_lod_ranges(MultiMeshInstance3D *p_mmi, const Ref<Terrain3DMeshAsset> &p_ma, const int p_lod) {
|
void Terrain3DInstancer::_set_mmi_lod_ranges(RID p_mmi, const Ref<Terrain3DMeshAsset> &p_ma, const int p_lod) {
|
||||||
if (!p_mmi || p_ma.is_null()) {
|
if (!p_mmi || p_ma.is_null()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -326,17 +304,12 @@ void Terrain3DInstancer::_set_mmi_lod_ranges(MultiMeshInstance3D *p_mmi, const R
|
||||||
if (margin > 0.f) {
|
if (margin > 0.f) {
|
||||||
lod_begin = MAX(lod_begin < 0.001f ? 0.f : lod_begin - margin, 0.f);
|
lod_begin = MAX(lod_begin < 0.001f ? 0.f : lod_begin - margin, 0.f);
|
||||||
lod_end = MAX(lod_end < 0.001f ? 0.f : lod_end + margin, 0.f);
|
lod_end = MAX(lod_end < 0.001f ? 0.f : lod_end + margin, 0.f);
|
||||||
p_mmi->set_visibility_range_begin_margin(lod_begin < 0.001f ? 0.f : margin);
|
real_t begin_margin = lod_begin < 0.001f ? 0.f : margin;
|
||||||
p_mmi->set_visibility_range_end_margin(lod_end < 0.001f ? 0.f : margin);
|
real_t end_margin = lod_end < 0.001f ? 0.f : margin;
|
||||||
p_mmi->set_visibility_range_fade_mode(GeometryInstance3D::VISIBILITY_RANGE_FADE_SELF);
|
RS->instance_geometry_set_visibility_range(p_mmi, lod_begin, lod_end, begin_margin, end_margin, RenderingServer::VISIBILITY_RANGE_FADE_SELF);
|
||||||
} else {
|
} else {
|
||||||
// Fade mode unset (Godot default)
|
RS->instance_geometry_set_visibility_range(p_mmi, lod_begin, lod_end, 0.f, 0.f, RenderingServer::VISIBILITY_RANGE_FADE_DISABLED);
|
||||||
p_mmi->set_visibility_range_begin_margin(0.f);
|
|
||||||
p_mmi->set_visibility_range_end_margin(0.f);
|
|
||||||
p_mmi->set_visibility_range_fade_mode(GeometryInstance3D::VISIBILITY_RANGE_FADE_DISABLED);
|
|
||||||
}
|
}
|
||||||
p_mmi->set_visibility_range_begin(lod_begin);
|
|
||||||
p_mmi->set_visibility_range_end(lod_end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terrain3DInstancer::_update_vertex_spacing(const real_t p_vertex_spacing) {
|
void Terrain3DInstancer::_update_vertex_spacing(const real_t p_vertex_spacing) {
|
||||||
|
|
@ -441,37 +414,25 @@ void Terrain3DInstancer::_destroy_mmi_by_cell(const Vector2i &p_region_loc, cons
|
||||||
if (cell_mmi_dict.count(p_cell) == 0) {
|
if (cell_mmi_dict.count(p_cell) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
MultiMeshInstance3D *mmi = cell_mmi_dict[p_cell];
|
|
||||||
if (ma.is_valid() && mmi && mmi->get_multimesh().is_valid()) {
|
RID &mmi = cell_mmi_dict[p_cell].first;
|
||||||
if (lod == 0) {
|
RID &mm = cell_mmi_dict[p_cell].second;
|
||||||
ma->update_instance_count(-mmi->get_multimesh()->get_instance_count());
|
if (ma.is_valid() && mm.is_valid()) {
|
||||||
|
if (lod == ma->get_last_lod()) {
|
||||||
|
ma->update_instance_count(-RS->multimesh_get_instance_count(mm));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG(EXTREME, "Freeing ", ptr_to_str(mmi), " and erasing mmi cell ", p_cell);
|
|
||||||
remove_from_tree(mmi);
|
LOG(EXTREME, "Freeing ", mmi, " and erasing mmi cell ", p_cell);
|
||||||
memdelete_safely(mmi);
|
RS->free_rid(mmi);
|
||||||
|
RS->free_rid(mm);
|
||||||
|
|
||||||
cell_mmi_dict.erase(p_cell);
|
cell_mmi_dict.erase(p_cell);
|
||||||
if (cell_mmi_dict.empty()) {
|
if (cell_mmi_dict.empty()) {
|
||||||
LOG(EXTREME, "Removing mesh ", mesh_key, " from cell MMI dictionary");
|
LOG(EXTREME, "Removing mesh ", mesh_key, " from cell MMI dictionary");
|
||||||
mesh_mmi_dict.erase(mesh_key); // invalidates cell_mmi_dict
|
mesh_mmi_dict.erase(mesh_key); // invalidates cell_mmi_dict
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up region if we've removed the last MMI and cell
|
|
||||||
if (mesh_mmi_dict.empty()) {
|
|
||||||
LOG(EXTREME, "Removing region ", p_region_loc, " from mesh MMI dictionary");
|
|
||||||
if (_mmi_containers.count(p_region_loc) > 0) {
|
|
||||||
Node *node = _mmi_containers[p_region_loc];
|
|
||||||
if (node && node->get_child_count() == 0) {
|
|
||||||
LOG(EXTREME, "Removing ", node->get_name());
|
|
||||||
_mmi_containers.erase(p_region_loc);
|
|
||||||
remove_from_tree(node);
|
|
||||||
memdelete_safely(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This invalidates mesh_mmi_dict here and for calling functions
|
|
||||||
_mmi_nodes.erase(p_region_loc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terrain3DInstancer::_backup_region(const Ref<Terrain3DRegion> &p_region) {
|
void Terrain3DInstancer::_backup_region(const Ref<Terrain3DRegion> &p_region) {
|
||||||
|
|
@ -485,8 +446,8 @@ void Terrain3DInstancer::_backup_region(const Ref<Terrain3DRegion> &p_region) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<MultiMesh> Terrain3DInstancer::_create_multimesh(const int p_mesh_id, const int p_lod, const TypedArray<Transform3D> &p_xforms, const PackedColorArray &p_colors) const {
|
RID Terrain3DInstancer::_create_multimesh(const int p_mesh_id, const int p_lod, const TypedArray<Transform3D> &p_xforms, const PackedColorArray &p_colors) const {
|
||||||
Ref<MultiMesh> mm;
|
RID mm;
|
||||||
IS_INIT(mm);
|
IS_INIT(mm);
|
||||||
Ref<Terrain3DMeshAsset> mesh_asset = _terrain->get_assets()->get_mesh_asset(p_mesh_id);
|
Ref<Terrain3DMeshAsset> mesh_asset = _terrain->get_assets()->get_mesh_asset(p_mesh_id);
|
||||||
if (mesh_asset.is_null()) {
|
if (mesh_asset.is_null()) {
|
||||||
|
|
@ -498,17 +459,13 @@ Ref<MultiMesh> Terrain3DInstancer::_create_multimesh(const int p_mesh_id, const
|
||||||
LOG(ERROR, "No LOD ", p_lod, " for mesh id ", p_mesh_id, " found. Max: ", mesh_asset->get_lod_count());
|
LOG(ERROR, "No LOD ", p_lod, " for mesh id ", p_mesh_id, " found. Max: ", mesh_asset->get_lod_count());
|
||||||
return mm;
|
return mm;
|
||||||
}
|
}
|
||||||
mm.instantiate();
|
mm = RS->multimesh_create();
|
||||||
mm->set_transform_format(MultiMesh::TRANSFORM_3D);
|
RS->multimesh_allocate_data(mm, p_xforms.size(), RenderingServer::MULTIMESH_TRANSFORM_3D, true, false, false);
|
||||||
mm->set_use_colors(true);
|
RS->multimesh_set_mesh(mm, mesh->get_rid());
|
||||||
mm->set_mesh(mesh);
|
for (int i = 0; i < p_xforms.size(); i++) {
|
||||||
if (p_xforms.size() > 0) {
|
RS->multimesh_instance_set_transform(mm, i, p_xforms[i]);
|
||||||
mm->set_instance_count(p_xforms.size());
|
if (i < p_colors.size()) {
|
||||||
for (int i = 0; i < p_xforms.size(); i++) {
|
RS->multimesh_instance_set_color(mm, i, p_colors[i]);
|
||||||
mm->set_instance_transform(i, p_xforms[i]);
|
|
||||||
if (i < p_colors.size()) {
|
|
||||||
mm->set_instance_color(i, p_colors[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mm;
|
return mm;
|
||||||
|
|
@ -1337,20 +1294,16 @@ void Terrain3DInstancer::update_mmis(const int p_mesh_id, const Vector2i &p_regi
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terrain3DInstancer::dump_mmis() {
|
void Terrain3DInstancer::dump_mmis() {
|
||||||
LOG(WARN, "Dumping MMI tree and node containers");
|
LOG(WARN, "Dumping MMI tree");
|
||||||
LOG(MESG, "_mmi_containers size: ", int(_mmi_containers.size()));
|
|
||||||
for (auto &it : _mmi_containers) {
|
|
||||||
LOG(MESG, "_mmi_containers region: ", it.first, ", node ptr: ", ptr_to_str(it.second));
|
|
||||||
}
|
|
||||||
LOG(MESG, "_mmi tree: ");
|
LOG(MESG, "_mmi tree: ");
|
||||||
_terrain->get_mmi_parent()->print_tree();
|
_terrain->get_mmi_parent()->print_tree();
|
||||||
LOG(MESG, "_mmi_nodes size: ", int(_mmi_nodes.size()));
|
LOG(MESG, "_mmi_nodes size: ", int(_mmi_nodes.size()));
|
||||||
for (auto &i : _mmi_nodes) {
|
for (auto &i : _mmi_nodes) {
|
||||||
LOG(MESG, "_mmi_nodes region: ", i.first, ", dict ptr: ", ptr_to_str(&i.second));
|
//LOG(MESG, "_mmi_nodes region: ", i.first, ", dict ptr: ", ptr_to_str(&i.second));
|
||||||
for (auto &j : i.second) {
|
for (auto &j : i.second) {
|
||||||
LOG(MESG, "mesh_mmi_dict mesh: ", j.first, ", dict ptr: ", ptr_to_str(&j.second));
|
//LOG(MESG, "mesh_mmi_dict mesh: ", j.first, ", dict ptr: ", &j.second.first);
|
||||||
for (auto &k : j.second) {
|
for (auto &k : j.second) {
|
||||||
LOG(MESG, "cell_mmi_dict cell: ", k.first, ", mmi ptr: ", ptr_to_str(k.second));
|
//LOG(MESG, "cell_mmi_dict cell: ", k.first, ", mmi ptr: ", (k.second));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,16 +28,12 @@ private:
|
||||||
// MM Resources stored in Terrain3DRegion::_instances as
|
// MM Resources stored in Terrain3DRegion::_instances as
|
||||||
// Region::_instances{mesh_id:int} -> cell{v2i} -> [ TypedArray<Transform3D>, PackedColorArray, modified:bool ]
|
// Region::_instances{mesh_id:int} -> cell{v2i} -> [ TypedArray<Transform3D>, PackedColorArray, modified:bool ]
|
||||||
|
|
||||||
// MMI Objects attached to tree, freed in destructor, stored as
|
// MMI Objects, freed in destructor, stored as
|
||||||
// _mmi_nodes{region_loc} -> mesh{v2i(mesh_id,lod)} -> cell{v2i} -> MultiMeshInstance3D
|
// _mmi_nodes{region_loc} -> mesh{v2i(mesh_id,lod)} -> cell{v2i} -> RID
|
||||||
using CellMMIDict = std::unordered_map<Vector2i, MultiMeshInstance3D *, Vector2iHash>;
|
using CellMMIDict = std::unordered_map<Vector2i, std::pair<RID, RID>, Vector2iHash>;
|
||||||
using MeshMMIDict = std::unordered_map<Vector2i, CellMMIDict, Vector2iHash>;
|
using MeshMMIDict = std::unordered_map<Vector2i, CellMMIDict, Vector2iHash>;
|
||||||
std::unordered_map<Vector2i, MeshMMIDict, Vector2iHash> _mmi_nodes;
|
std::unordered_map<Vector2i, MeshMMIDict, Vector2iHash> _mmi_nodes;
|
||||||
|
|
||||||
// Region MMI containers named Terrain3D/MMI/Region* are stored here as
|
|
||||||
// _mmi_containers{region_loc} -> Node3D
|
|
||||||
std::unordered_map<Vector2i, Node3D *, Vector2iHash> _mmi_containers;
|
|
||||||
|
|
||||||
// MMI Updates tracked in a unique Set of <region_location, mesh_id>
|
// MMI Updates tracked in a unique Set of <region_location, mesh_id>
|
||||||
// <V2I_MAX, -2> means destroy first, then update everything
|
// <V2I_MAX, -2> means destroy first, then update everything
|
||||||
// <V2I_MAX, -1> means update everything
|
// <V2I_MAX, -1> means update everything
|
||||||
|
|
@ -51,13 +47,13 @@ private:
|
||||||
uint32_t _get_density_count(const real_t p_density);
|
uint32_t _get_density_count(const real_t p_density);
|
||||||
void _process_updates();
|
void _process_updates();
|
||||||
void _update_mmi_by_region(const Terrain3DRegion *p_region, const int p_mesh_id);
|
void _update_mmi_by_region(const Terrain3DRegion *p_region, const int p_mesh_id);
|
||||||
void _set_mmi_lod_ranges(MultiMeshInstance3D *p_mmi, const Ref<Terrain3DMeshAsset> &p_ma, const int p_lod);
|
void _set_mmi_lod_ranges(RID p_mmi, const Ref<Terrain3DMeshAsset> &p_ma, const int p_lod);
|
||||||
void _update_vertex_spacing(const real_t p_vertex_spacing);
|
void _update_vertex_spacing(const real_t p_vertex_spacing);
|
||||||
void _destroy_mmi_by_mesh(const int p_mesh_id);
|
void _destroy_mmi_by_mesh(const int p_mesh_id);
|
||||||
void _destroy_mmi_by_location(const Vector2i &p_region_loc, const int p_mesh_id);
|
void _destroy_mmi_by_location(const Vector2i &p_region_loc, const int p_mesh_id);
|
||||||
void _destroy_mmi_by_cell(const Vector2i &p_region_loc, const int p_mesh_id, const Vector2i p_cell, const int p_lod = INT32_MAX);
|
void _destroy_mmi_by_cell(const Vector2i &p_region_loc, const int p_mesh_id, const Vector2i p_cell, const int p_lod = INT32_MAX);
|
||||||
void _backup_region(const Ref<Terrain3DRegion> &p_region);
|
void _backup_region(const Ref<Terrain3DRegion> &p_region);
|
||||||
Ref<MultiMesh> _create_multimesh(const int p_mesh_id, const int p_lod, const TypedArray<Transform3D> &p_xforms = TypedArray<Transform3D>(), const PackedColorArray &p_colors = PackedColorArray()) const;
|
RID _create_multimesh(const int p_mesh_id, const int p_lod, const TypedArray<Transform3D> &p_xforms = TypedArray<Transform3D>(), const PackedColorArray &p_colors = PackedColorArray()) const;
|
||||||
Vector2i _get_cell(const Vector3 &p_global_position, const int p_region_size) const;
|
Vector2i _get_cell(const Vector3 &p_global_position, const int p_region_size) const;
|
||||||
Array _get_usable_height(const Vector3 &p_global_position, const Vector2 &p_slope_range, const bool p_on_collision, const real_t p_raycast_start) const;
|
Array _get_usable_height(const Vector3 &p_global_position, const Vector2 &p_slope_range, const bool p_on_collision, const real_t p_raycast_start) const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,7 @@ void Terrain3DMeshAsset::clear() {
|
||||||
_height_offset = 0.f;
|
_height_offset = 0.f;
|
||||||
_density = 10.f;
|
_density = 10.f;
|
||||||
_cast_shadows = SHADOWS_ON;
|
_cast_shadows = SHADOWS_ON;
|
||||||
|
_visibility_layers = 1;
|
||||||
_material_override.unref();
|
_material_override.unref();
|
||||||
_material_overlay.unref();
|
_material_overlay.unref();
|
||||||
_last_lod = MAX_LOD_COUNT - 1;
|
_last_lod = MAX_LOD_COUNT - 1;
|
||||||
|
|
@ -377,6 +378,13 @@ ShadowCasting Terrain3DMeshAsset::get_lod_cast_shadows(const int p_lod_id) const
|
||||||
return _cast_shadows;
|
return _cast_shadows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Terrain3DMeshAsset::set_visibility_layers(const int p_layers) {
|
||||||
|
LOG(INFO, _name, ": Setting visibility layers: ", p_layers);
|
||||||
|
_visibility_layers = p_layers;
|
||||||
|
LOG(DEBUG, "Emitting instancer_setting_changed, ID: ", _id);
|
||||||
|
emit_signal("instancer_setting_changed", _id);
|
||||||
|
}
|
||||||
|
|
||||||
void Terrain3DMeshAsset::set_material_override(const Ref<Material> &p_material) {
|
void Terrain3DMeshAsset::set_material_override(const Ref<Material> &p_material) {
|
||||||
SET_IF_DIFF(_material_override, p_material);
|
SET_IF_DIFF(_material_override, p_material);
|
||||||
LOG(INFO, _name, ": Setting material override: ", p_material);
|
LOG(INFO, _name, ": Setting material override: ", p_material);
|
||||||
|
|
@ -562,6 +570,8 @@ void Terrain3DMeshAsset::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_density"), &Terrain3DMeshAsset::get_density);
|
ClassDB::bind_method(D_METHOD("get_density"), &Terrain3DMeshAsset::get_density);
|
||||||
ClassDB::bind_method(D_METHOD("set_cast_shadows", "mode"), &Terrain3DMeshAsset::set_cast_shadows);
|
ClassDB::bind_method(D_METHOD("set_cast_shadows", "mode"), &Terrain3DMeshAsset::set_cast_shadows);
|
||||||
ClassDB::bind_method(D_METHOD("get_cast_shadows"), &Terrain3DMeshAsset::get_cast_shadows);
|
ClassDB::bind_method(D_METHOD("get_cast_shadows"), &Terrain3DMeshAsset::get_cast_shadows);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_visibility_layers", "layers"), &Terrain3DMeshAsset::set_visibility_layers);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_visibility_layers"), &Terrain3DMeshAsset::get_visibility_layers);
|
||||||
ClassDB::bind_method(D_METHOD("set_material_override", "material"), &Terrain3DMeshAsset::set_material_override);
|
ClassDB::bind_method(D_METHOD("set_material_override", "material"), &Terrain3DMeshAsset::set_material_override);
|
||||||
ClassDB::bind_method(D_METHOD("get_material_override"), &Terrain3DMeshAsset::get_material_override);
|
ClassDB::bind_method(D_METHOD("get_material_override"), &Terrain3DMeshAsset::get_material_override);
|
||||||
ClassDB::bind_method(D_METHOD("set_material_overlay", "material"), &Terrain3DMeshAsset::set_material_overlay);
|
ClassDB::bind_method(D_METHOD("set_material_overlay", "material"), &Terrain3DMeshAsset::set_material_overlay);
|
||||||
|
|
@ -615,6 +625,7 @@ void Terrain3DMeshAsset::_bind_methods() {
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height_offset", PROPERTY_HINT_RANGE, "-20.0,20.0,.005"), "set_height_offset", "get_height_offset");
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height_offset", PROPERTY_HINT_RANGE, "-20.0,20.0,.005"), "set_height_offset", "get_height_offset");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, ".01,10.0,.005"), "set_density", "get_density");
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, ".01,10.0,.005"), "set_density", "get_density");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadows", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows", "get_cast_shadows");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadows", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows", "get_cast_shadows");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_visibility_layers", "get_visibility_layers");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material_override", "get_material_override");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material_override", "get_material_override");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_overlay", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material_overlay", "get_material_overlay");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_overlay", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material_overlay", "get_material_overlay");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#define TERRAIN3D_MESH_ASSET_CLASS_H
|
#define TERRAIN3D_MESH_ASSET_CLASS_H
|
||||||
|
|
||||||
#include <godot_cpp/classes/array_mesh.hpp>
|
#include <godot_cpp/classes/array_mesh.hpp>
|
||||||
#include <godot_cpp/classes/geometry_instance3d.hpp>
|
//#include <godot_cpp/classes/geometry_instance3d.hpp>
|
||||||
#include <godot_cpp/classes/material.hpp>
|
#include <godot_cpp/classes/material.hpp>
|
||||||
#include <godot_cpp/classes/packed_scene.hpp>
|
#include <godot_cpp/classes/packed_scene.hpp>
|
||||||
#include <godot_cpp/classes/resource.hpp>
|
#include <godot_cpp/classes/resource.hpp>
|
||||||
|
|
@ -13,10 +13,10 @@
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "terrain_3d_asset_resource.h"
|
#include "terrain_3d_asset_resource.h"
|
||||||
|
|
||||||
using ShadowCasting = GeometryInstance3D::ShadowCastingSetting;
|
using ShadowCasting = RenderingServer::ShadowCastingSetting;
|
||||||
constexpr ShadowCasting SHADOWS_ON = GeometryInstance3D::SHADOW_CASTING_SETTING_ON;
|
constexpr ShadowCasting SHADOWS_ON = RenderingServer::SHADOW_CASTING_SETTING_ON;
|
||||||
constexpr ShadowCasting SHADOWS_OFF = GeometryInstance3D::SHADOW_CASTING_SETTING_OFF;
|
constexpr ShadowCasting SHADOWS_OFF = RenderingServer::SHADOW_CASTING_SETTING_OFF;
|
||||||
constexpr ShadowCasting SHADOWS_ONLY = GeometryInstance3D::SHADOW_CASTING_SETTING_SHADOWS_ONLY;
|
constexpr ShadowCasting SHADOWS_ONLY = RenderingServer::SHADOW_CASTING_SETTING_SHADOWS_ONLY;
|
||||||
|
|
||||||
class Terrain3DMeshAsset : public Terrain3DAssetResource {
|
class Terrain3DMeshAsset : public Terrain3DAssetResource {
|
||||||
GDCLASS(Terrain3DMeshAsset, Terrain3DAssetResource);
|
GDCLASS(Terrain3DMeshAsset, Terrain3DAssetResource);
|
||||||
|
|
@ -42,6 +42,7 @@ private:
|
||||||
real_t _height_offset = 0.f;
|
real_t _height_offset = 0.f;
|
||||||
real_t _density = 10.f;
|
real_t _density = 10.f;
|
||||||
ShadowCasting _cast_shadows = SHADOWS_ON;
|
ShadowCasting _cast_shadows = SHADOWS_ON;
|
||||||
|
int _visibility_layers = 1;
|
||||||
Ref<Material> _material_override;
|
Ref<Material> _material_override;
|
||||||
Ref<Material> _material_overlay;
|
Ref<Material> _material_overlay;
|
||||||
int _last_lod = MAX_LOD_COUNT - 1;
|
int _last_lod = MAX_LOD_COUNT - 1;
|
||||||
|
|
@ -96,6 +97,8 @@ public:
|
||||||
void set_cast_shadows(const ShadowCasting p_cast_shadows);
|
void set_cast_shadows(const ShadowCasting p_cast_shadows);
|
||||||
ShadowCasting get_cast_shadows() const { return _cast_shadows; };
|
ShadowCasting get_cast_shadows() const { return _cast_shadows; };
|
||||||
ShadowCasting get_lod_cast_shadows(const int p_lod_id) const;
|
ShadowCasting get_lod_cast_shadows(const int p_lod_id) const;
|
||||||
|
void set_visibility_layers(const int p_layers);
|
||||||
|
int get_visibility_layers() const { return _visibility_layers; }
|
||||||
void set_material_override(const Ref<Material> &p_material);
|
void set_material_override(const Ref<Material> &p_material);
|
||||||
Ref<Material> get_material_override() const { return _material_override; }
|
Ref<Material> get_material_override() const { return _material_override; }
|
||||||
void set_material_overlay(const Ref<Material> &p_material);
|
void set_material_overlay(const Ref<Material> &p_material);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue