Use VisualServer directly for mesh instances

This commit is contained in:
Marc Gilleron 2017-08-20 18:37:08 +02:00
parent a371e7fc9a
commit 6419e78fc2
4 changed files with 53 additions and 45 deletions

View File

@ -1,14 +1,5 @@
#include "voxel_block.h"
MeshInstance *VoxelBlock::get_mesh_instance(const Node &root) {
if (mesh_instance_path.is_empty())
return NULL;
Node *n = root.get_node(mesh_instance_path);
if (n == NULL)
return NULL;
return n->cast_to<MeshInstance>();
}
// Helper
VoxelBlock *VoxelBlock::create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned int size) {
const int bs = size;
@ -17,6 +8,7 @@ VoxelBlock *VoxelBlock::create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned
VoxelBlock *block = memnew(VoxelBlock);
block->pos = bpos;
block->_position_in_voxels = bpos * size;
block->voxels = buffer;
//block->map = &map;
@ -25,5 +17,42 @@ VoxelBlock *VoxelBlock::create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned
VoxelBlock::VoxelBlock()
: voxels(NULL) {
VisualServer &vs = *VisualServer::get_singleton();
if (_mesh_instance.is_valid()) {
vs.free(_mesh_instance);
_mesh_instance = RID();
}
}
void VoxelBlock::set_mesh(Ref<Mesh> mesh, Ref<World> world) {
VisualServer &vs = *VisualServer::get_singleton();
if(mesh.is_valid()) {
if(_mesh_instance.is_valid() == false) {
// Create instance if it doesn't exist
ERR_FAIL_COND(world.is_null());
_mesh_instance = vs.instance_create();
vs.instance_set_scenario(_mesh_instance, world->get_scenario());
}
vs.instance_set_base(_mesh_instance, mesh.is_valid() ? mesh->get_rid() : RID());
Transform local_transform(Basis(), _position_in_voxels.to_vec3());
vs.instance_set_transform(_mesh_instance, local_transform);
// TODO The day VoxelTerrain becomes a Spatial, this transform will need to be updatable separately
} else {
if(_mesh_instance.is_valid()) {
// Delete instance if it exists
vs.free(_mesh_instance);
_mesh_instance = RID();
}
}
_mesh = mesh;
}

View File

@ -12,14 +12,18 @@ class VoxelBlock {
public:
Ref<VoxelBuffer> voxels; // SIZE*SIZE*SIZE voxels
Vector3i pos;
NodePath mesh_instance_path;
static VoxelBlock *create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned int size);
MeshInstance *get_mesh_instance(const Node &root);
void set_mesh(Ref<Mesh> mesh, Ref<World> world);
private:
VoxelBlock();
Vector3i _position_in_voxels;
Ref<Mesh> _mesh;
RID _mesh_instance;
};
#endif // VOXEL_BLOCK_H

View File

@ -6,7 +6,7 @@
VoxelTerrain::VoxelTerrain()
: Node(), _generate_collisions(true) {
: Spatial(), _generate_collisions(true) {
_map = Ref<VoxelMap>(memnew(VoxelMap));
_mesher = Ref<VoxelMesher>(memnew(VoxelMesher));
@ -306,6 +306,8 @@ void VoxelTerrain::_notification(int p_what) {
make_all_view_dirty();
break;
// TODO Listen for transform changes
default:
break;
}
@ -440,8 +442,6 @@ void VoxelTerrain::update_block_mesh(Vector3i block_pos) {
_map->get_buffer_copy(_map->block_to_voxel(block_pos) - Vector3i(1, 1, 1), nbuffer, 0x3);
VOXEL_PROFILE_END("block_extraction")
Vector3 block_node_pos = _map->block_to_voxel(block_pos).to_vec3();
// TODO Re-use existing meshes to optimize memory cost
// Build cubic parts of the mesh
@ -449,36 +449,11 @@ void VoxelTerrain::update_block_mesh(Vector3i block_pos) {
// Build smooth parts of the mesh
_mesher_smooth->build(nbuffer, Voxel::CHANNEL_ISOLEVEL, mesh);
MeshInstance *mesh_instance = block->get_mesh_instance(*this);
if(is_mesh_empty(mesh))
mesh = Ref<Mesh>();
if (is_mesh_empty(mesh)) {
if (mesh_instance) {
mesh_instance->set_mesh(Ref<Mesh>());
}
} else {
// The mesh exist and it has vertices
// TODO Don't use nodes! Use servers directly, it's faster
if (mesh_instance == NULL) {
// Create and spawn mesh
mesh_instance = memnew(MeshInstance);
mesh_instance->set_mesh(mesh);
mesh_instance->set_translation(block_node_pos);
add_child(mesh_instance);
block->mesh_instance_path = mesh_instance->get_path();
} else {
// Update mesh
VOXEL_PROFILE_BEGIN("mesh_instance_set_mesh")
mesh_instance->set_mesh(mesh);
VOXEL_PROFILE_END("mesh_instance_set_mesh")
}
if (Engine::get_singleton()->is_editor_hint() == false && _generate_collisions) {
// TODO Generate collisions using PhysicsServer
// TODO Need to select only specific surfaces because some may not have collisions
}
}
Ref<World> world = get_world();
block->set_mesh(mesh, world);
}
//void VoxelTerrain::block_removed(VoxelBlock & block) {

View File

@ -10,8 +10,8 @@
// Infinite static terrain made of voxels.
// It is loaded around VoxelTerrainStreamers.
class VoxelTerrain : public Node /*, public IVoxelMapObserver*/ {
GDCLASS(VoxelTerrain, Node)
class VoxelTerrain : public Spatial /*, public IVoxelMapObserver*/ {
GDCLASS(VoxelTerrain, Spatial)
public:
VoxelTerrain();