Marc Gilleron 2020-05-08 17:57:10 +01:00
commit 182352e903
4 changed files with 45 additions and 39 deletions

View File

@ -7,28 +7,45 @@
// Faster version of Mesh::create_trimesh_shape()
// See https://github.com/Zylann/godot_voxel/issues/54
//
static Ref<ConcavePolygonShape> create_concave_polygon_shape(Array surface_arrays) {
PoolVector<Vector3> positions = surface_arrays[Mesh::ARRAY_VERTEX];
PoolVector<int> indices = surface_arrays[Mesh::ARRAY_INDEX];
ERR_FAIL_COND_V(positions.size() < 3, Ref<ConcavePolygonShape>());
ERR_FAIL_COND_V(indices.size() < 3, Ref<ConcavePolygonShape>());
ERR_FAIL_COND_V(indices.size() % 3 != 0, Ref<ConcavePolygonShape>());
int face_points_count = indices.size();
static Ref<ConcavePolygonShape> create_concave_polygon_shape(Vector<Array> surfaces) {
PoolVector<Vector3> face_points;
face_points.resize(face_points_count);
int face_points_size = 0;
{
PoolVector<Vector3>::Write w = face_points.write();
PoolVector<int>::Read index_r = indices.read();
PoolVector<Vector3>::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<int> 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<Vector3> positions = surface_arrays[Mesh::ARRAY_VERTEX];
PoolVector<int> indices = surface_arrays[Mesh::ARRAY_INDEX];
ERR_FAIL_COND_V(positions.size() < 3, Ref<ConcavePolygonShape>());
ERR_FAIL_COND_V(indices.size() < 3, Ref<ConcavePolygonShape>());
ERR_FAIL_COND_V(indices.size() % 3 != 0, Ref<ConcavePolygonShape>());
int face_points_count = face_points_offset + indices.size();
{
PoolVector<Vector3>::Write w = face_points.write();
PoolVector<int>::Read index_r = indices.read();
PoolVector<Vector3>::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<ConcavePolygonShape> shape = memnew(ConcavePolygonShape);
@ -85,7 +102,7 @@ void VoxelBlock::set_world(Ref<World> p_world) {
}
}
void VoxelBlock::set_mesh(Ref<Mesh> mesh, Spatial *node, bool generate_collision, Array surface_arrays, bool debug_collision) {
void VoxelBlock::set_mesh(Ref<Mesh> mesh, Spatial *node, bool generate_collision, Vector<Array> 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)

View File

@ -34,7 +34,7 @@ public:
// Visuals and physics
void set_world(Ref<World> p_world);
void set_mesh(Ref<Mesh> mesh, Spatial *node, bool generate_collision, Array surface_arrays, bool debug_collision);
void set_mesh(Ref<Mesh> mesh, Spatial *node, bool generate_collision, Vector<Array> surface_arrays, bool debug_collision);
void set_transition_mesh(Ref<Mesh> mesh, int side);
bool has_mesh() const;

View File

@ -14,7 +14,7 @@ const uint32_t MAIN_THREAD_MESHING_BUDGET_MS = 8;
namespace {
Ref<ArrayMesh> build_mesh(const Vector<Array> surfaces, Mesh::PrimitiveType primitive, int compression_flags,
Ref<Material> material, Array *collidable_surface) {
Ref<Material> material) {
Ref<ArrayMesh> mesh;
mesh.instance();
@ -32,10 +32,6 @@ Ref<ArrayMesh> build_mesh(const Vector<Array> 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<ArrayMesh> 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);
}

View File

@ -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<Mesh>(), this, _generate_collisions, Array(), get_tree()->is_debugging_collisions_hint());
block->set_mesh(Ref<Mesh>(), this, _generate_collisions, Vector<Array>(), 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<ArrayMesh> mesh;
mesh.instance();
// TODO Allow multiple collision surfaces
Array collidable_surface;
Vector<Array> 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<Mesh>();
}
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());
}