diff --git a/terrain/voxel_block.cpp b/terrain/voxel_block.cpp index fdeb4db7..a639a117 100644 --- a/terrain/voxel_block.cpp +++ b/terrain/voxel_block.cpp @@ -7,28 +7,45 @@ // Faster version of Mesh::create_trimesh_shape() // See https://github.com/Zylann/godot_voxel/issues/54 // -static Ref create_concave_polygon_shape(Array surface_arrays) { - - PoolVector positions = surface_arrays[Mesh::ARRAY_VERTEX]; - PoolVector indices = surface_arrays[Mesh::ARRAY_INDEX]; - - ERR_FAIL_COND_V(positions.size() < 3, Ref()); - ERR_FAIL_COND_V(indices.size() < 3, Ref()); - ERR_FAIL_COND_V(indices.size() % 3 != 0, Ref()); - - int face_points_count = indices.size(); +static Ref create_concave_polygon_shape(Vector surfaces) { PoolVector face_points; - face_points.resize(face_points_count); + int face_points_size = 0; - { - PoolVector::Write w = face_points.write(); - PoolVector::Read index_r = indices.read(); - PoolVector::Read position_r = positions.read(); + //find the correct size for face_points + for(int i = 0; i < surfaces.size(); i++) { + const Array &surface_arrays = surfaces[i]; + PoolVector indices = surface_arrays[Mesh::ARRAY_INDEX]; - for (int i = 0; i < face_points_count; ++i) { - w[i] = position_r[index_r[i]]; + face_points_size += indices.size(); + } + face_points.resize(face_points_size); + + //copy the points into it + int face_points_offset = 0; + for(int i = 0; i < surfaces.size(); i++) { + const Array &surface_arrays = surfaces[i]; + + PoolVector positions = surface_arrays[Mesh::ARRAY_VERTEX]; + PoolVector indices = surface_arrays[Mesh::ARRAY_INDEX]; + + ERR_FAIL_COND_V(positions.size() < 3, Ref()); + ERR_FAIL_COND_V(indices.size() < 3, Ref()); + ERR_FAIL_COND_V(indices.size() % 3 != 0, Ref()); + + int face_points_count = face_points_offset + indices.size(); + + { + PoolVector::Write w = face_points.write(); + PoolVector::Read index_r = indices.read(); + PoolVector::Read position_r = positions.read(); + + for (int p = face_points_offset; p < face_points_count; ++p) { + w[p] = position_r[index_r[p - face_points_offset]]; + } } + + face_points_offset += indices.size(); } Ref shape = memnew(ConcavePolygonShape); @@ -85,7 +102,7 @@ void VoxelBlock::set_world(Ref p_world) { } } -void VoxelBlock::set_mesh(Ref mesh, Spatial *node, bool generate_collision, Array surface_arrays, bool debug_collision) { +void VoxelBlock::set_mesh(Ref mesh, Spatial *node, bool generate_collision, Vector surface_arrays, bool debug_collision) { // TODO Don't add mesh instance to the world if it's not visible. // I suspect Godot is trying to include invisible mesh instances into the culling process, // which is killing performance when LOD is used (i.e many meshes are in pool but hidden) diff --git a/terrain/voxel_block.h b/terrain/voxel_block.h index 2e653a0b..8b804605 100644 --- a/terrain/voxel_block.h +++ b/terrain/voxel_block.h @@ -34,7 +34,7 @@ public: // Visuals and physics void set_world(Ref p_world); - void set_mesh(Ref mesh, Spatial *node, bool generate_collision, Array surface_arrays, bool debug_collision); + void set_mesh(Ref mesh, Spatial *node, bool generate_collision, Vector surface_arrays, bool debug_collision); void set_transition_mesh(Ref mesh, int side); bool has_mesh() const; diff --git a/terrain/voxel_lod_terrain.cpp b/terrain/voxel_lod_terrain.cpp index e85e7cdb..d6a81452 100644 --- a/terrain/voxel_lod_terrain.cpp +++ b/terrain/voxel_lod_terrain.cpp @@ -14,7 +14,7 @@ const uint32_t MAIN_THREAD_MESHING_BUDGET_MS = 8; namespace { Ref build_mesh(const Vector surfaces, Mesh::PrimitiveType primitive, int compression_flags, - Ref material, Array *collidable_surface) { + Ref material) { Ref mesh; mesh.instance(); @@ -32,10 +32,6 @@ Ref build_mesh(const Vector surfaces, Mesh::PrimitiveType prim continue; } - if (collidable_surface != nullptr && collidable_surface->empty()) { - *collidable_surface = surface; - } - mesh->add_surface_from_arrays(primitive, surface, Array(), compression_flags); mesh->surface_set_material(surface_index, material); // No multi-material supported yet @@ -1197,20 +1193,18 @@ void VoxelLodTerrain::_process() { const VoxelMesher::Output mesh_data = ob.data.smooth_surfaces; - // TODO Allow multiple collision surfaces - Array collidable_surface; Ref mesh = build_mesh( mesh_data.surfaces, mesh_data.primitive_type, mesh_data.compression_flags, - _material, &collidable_surface); + _material); bool has_collision = _generate_collisions; if (has_collision && _collision_lod_count != -1) { has_collision = ob.lod < _collision_lod_count; } - block->set_mesh(mesh, this, has_collision, collidable_surface, get_tree()->is_debugging_collisions_hint()); + block->set_mesh(mesh, this, has_collision, mesh_data.surfaces, get_tree()->is_debugging_collisions_hint()); { VOXEL_PROFILE_SCOPE(profile_process_receive_mesh_updates_block_update_transitions); @@ -1220,7 +1214,7 @@ void VoxelLodTerrain::_process() { mesh_data.transition_surfaces[dir], mesh_data.primitive_type, mesh_data.compression_flags, - _material, nullptr); + _material); block->set_transition_mesh(transition_mesh, dir); } diff --git a/terrain/voxel_terrain.cpp b/terrain/voxel_terrain.cpp index 52626408..45b09bf3 100644 --- a/terrain/voxel_terrain.cpp +++ b/terrain/voxel_terrain.cpp @@ -928,7 +928,7 @@ void VoxelTerrain::_process() { CRASH_COND(block->get_mesh_state() != VoxelBlock::MESH_UPDATE_NOT_SENT); // The block contains empty voxels - block->set_mesh(Ref(), this, _generate_collisions, Array(), get_tree()->is_debugging_collisions_hint()); + block->set_mesh(Ref(), this, _generate_collisions, Vector(), get_tree()->is_debugging_collisions_hint()); block->set_mesh_state(VoxelBlock::MESH_UP_TO_DATE); // Optional, but I guess it might spare some memory @@ -1013,8 +1013,7 @@ void VoxelTerrain::_process() { Ref mesh; mesh.instance(); - // TODO Allow multiple collision surfaces - Array collidable_surface; + Vector collidable_surfaces; //need to put both blocky and smooth surfaces into one list int surface_index = 0; const VoxelMeshUpdater::OutputBlockData &data = ob.data; @@ -1030,9 +1029,7 @@ void VoxelTerrain::_process() { continue; } - if (collidable_surface.empty()) { - collidable_surface = surface; - } + collidable_surfaces.push_back(surface); mesh->add_surface_from_arrays(data.blocky_surfaces.primitive_type, surface, Array(), data.blocky_surfaces.compression_flags); mesh->surface_set_material(surface_index, _materials[i]); @@ -1051,9 +1048,7 @@ void VoxelTerrain::_process() { continue; } - if (collidable_surface.empty()) { - collidable_surface = surface; - } + collidable_surfaces.push_back(surface); mesh->add_surface_from_arrays(data.smooth_surfaces.primitive_type, surface, Array(), data.smooth_surfaces.compression_flags); mesh->surface_set_material(surface_index, _materials[i]); @@ -1064,7 +1059,7 @@ void VoxelTerrain::_process() { mesh = Ref(); } - block->set_mesh(mesh, this, _generate_collisions, collidable_surface, get_tree()->is_debugging_collisions_hint()); + block->set_mesh(mesh, this, _generate_collisions, collidable_surfaces, get_tree()->is_debugging_collisions_hint()); block->set_parent_visible(is_visible()); }