Block size is no longer a constant

This commit is contained in:
Marc Gilleron 2017-08-20 15:17:54 +02:00
parent cb6de49b96
commit cb548234fc
6 changed files with 77 additions and 36 deletions

View File

@ -121,6 +121,10 @@ _FORCE_INLINE_ Vector3i operator-(const Vector3i &a, const Vector3i &b) {
return Vector3i(a.x - b.x, a.y - b.y, a.z - b.z);
}
_FORCE_INLINE_ Vector3i operator*(const Vector3i &a, const Vector3i &b) {
return Vector3i(a.x * b.x, a.y * b.y, a.z * b.z);
}
_FORCE_INLINE_ Vector3i operator*(const Vector3i &a, int n) {
return Vector3i(a.x * n, a.y * n, a.z * n);
}

View File

@ -15,8 +15,8 @@ MeshInstance *VoxelBlock::get_mesh_instance(const Node &root) {
}
// Helper
VoxelBlock *VoxelBlock::create(Vector3i bpos, Ref<VoxelBuffer> buffer) {
const int bs = VoxelBlock::SIZE;
VoxelBlock *VoxelBlock::create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned int size) {
const int bs = size;
ERR_FAIL_COND_V(buffer.is_null(), NULL);
ERR_FAIL_COND_V(buffer->get_size() != Vector3i(bs, bs, bs), NULL);
@ -38,6 +38,10 @@ VoxelBlock::VoxelBlock()
VoxelMap::VoxelMap()
: _last_accessed_block(NULL) {
// TODO Make it configurable in editor (with all necessary notifications and updatings!)
set_block_size_pow2(4);
for (unsigned int i = 0; i < VoxelBuffer::MAX_CHANNELS; ++i) {
_default_voxel[i] = 0;
}
@ -47,6 +51,16 @@ VoxelMap::~VoxelMap() {
clear();
}
void VoxelMap::set_block_size_pow2(unsigned int p) {
// Limit to 8, 16, 32
ERR_FAIL_COND(p < 3 || p > 5);
_block_size_pow2 = p;
_block_size = 1 << _block_size_pow2;
_block_size_mask = _block_size_pow2 - 1;
}
int VoxelMap::get_voxel(Vector3i pos, unsigned int c) {
Vector3i bpos = voxel_to_block(pos);
VoxelBlock *block = get_block(bpos);
@ -64,10 +78,10 @@ void VoxelMap::set_voxel(int value, Vector3i pos, unsigned int c) {
if (block == NULL) {
Ref<VoxelBuffer> buffer(memnew(VoxelBuffer));
buffer->create(VoxelBlock::SIZE, VoxelBlock::SIZE, VoxelBlock::SIZE);
buffer->create(_block_size, _block_size, _block_size);
buffer->set_default_values(_default_voxel);
block = VoxelBlock::create(bpos, buffer);
block = VoxelBlock::create(bpos, buffer, _block_size);
set_block(bpos, block);
}
@ -109,7 +123,7 @@ void VoxelMap::set_block_buffer(Vector3i bpos, Ref<VoxelBuffer> buffer) {
ERR_FAIL_COND(buffer.is_null());
VoxelBlock *block = get_block(bpos);
if (block == NULL) {
block = VoxelBlock::create(bpos, *buffer);
block = VoxelBlock::create(bpos, *buffer, _block_size);
set_block(bpos, block);
} else {
block->voxels = buffer;
@ -170,6 +184,8 @@ void VoxelMap::get_buffer_copy(Vector3i min_pos, VoxelBuffer &dst_buffer, unsign
Vector3i max_block_pos = voxel_to_block(max_pos - Vector3i(1, 1, 1)) + Vector3i(1, 1, 1);
ERR_FAIL_COND((max_block_pos - min_block_pos) != Vector3(3, 3, 3));
const Vector3i block_size_v(_block_size, _block_size, _block_size);
for (unsigned int channel = 0; channel < VoxelBuffer::MAX_CHANNELS; ++channel) {
if (((1 << channel) & channels_mask) == 0) {
@ -188,12 +204,13 @@ void VoxelMap::get_buffer_copy(Vector3i min_pos, VoxelBuffer &dst_buffer, unsign
Vector3i offset = block_to_voxel(bpos);
// Note: copy_from takes care of clamping the area if it's on an edge
dst_buffer.copy_from(src_buffer, min_pos - offset, max_pos - offset, offset - min_pos, channel);
} else {
Vector3i offset = block_to_voxel(bpos);
dst_buffer.fill_area(
_default_voxel[channel],
offset - min_pos,
offset - min_pos + Vector3i(VoxelBlock::SIZE, VoxelBlock::SIZE, VoxelBlock::SIZE));
offset - min_pos + block_size_v);
}
}
}

View File

@ -10,15 +10,11 @@
// Fixed-size voxel container used in VoxelMap. Used internally.
class VoxelBlock {
public:
static const int SIZE_POW2 = 4; // 3=>8, 4=>16, 5=>32...
static const int SIZE = 1 << SIZE_POW2;
static const int SIZE_MASK = 0xf;
Ref<VoxelBuffer> voxels; // SIZE*SIZE*SIZE voxels
Vector3i pos;
NodePath mesh_instance_path;
static VoxelBlock *create(Vector3i bpos, Ref<VoxelBuffer> buffer);
static VoxelBlock *create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned int size);
MeshInstance *get_mesh_instance(const Node &root);
@ -31,28 +27,32 @@ class VoxelMap : public Reference {
GDCLASS(VoxelMap, Reference)
public:
// Converts voxel coodinates into block coordinates
static _FORCE_INLINE_ Vector3i voxel_to_block(Vector3i pos) {
_FORCE_INLINE_ Vector3i voxel_to_block(Vector3i pos) const {
return Vector3i(
pos.x >> VoxelBlock::SIZE_POW2,
pos.y >> VoxelBlock::SIZE_POW2,
pos.z >> VoxelBlock::SIZE_POW2);
pos.x >> _block_size_pow2,
pos.y >> _block_size_pow2,
pos.z >> _block_size_pow2);
}
static _FORCE_INLINE_ Vector3i to_local(Vector3i pos) {
_FORCE_INLINE_ Vector3i to_local(Vector3i pos) const {
return Vector3i(
pos.x & VoxelBlock::SIZE_MASK,
pos.y & VoxelBlock::SIZE_MASK,
pos.z & VoxelBlock::SIZE_MASK);
pos.x & _block_size_mask,
pos.y & _block_size_mask,
pos.z & _block_size_mask);
}
// Converts block coodinates into voxel coordinates
static _FORCE_INLINE_ Vector3i block_to_voxel(Vector3i bpos) {
return bpos * VoxelBlock::SIZE;
_FORCE_INLINE_ Vector3i block_to_voxel(Vector3i bpos) const {
return bpos * _block_size;
}
VoxelMap();
~VoxelMap();
_FORCE_INLINE_ unsigned int get_block_size() const { return _block_size; }
_FORCE_INLINE_ unsigned int get_block_size_pow2() const { return _block_size_pow2; }
_FORCE_INLINE_ unsigned int get_block_size_mask() const { return _block_size_mask; }
int get_voxel(Vector3i pos, unsigned int c = 0);
void set_voxel(int value, Vector3i pos, unsigned int c = 0);
@ -77,7 +77,7 @@ public:
private:
void set_block(Vector3i bpos, VoxelBlock *block);
_FORCE_INLINE_ int get_block_size() const { return VoxelBlock::SIZE; }
void set_block_size_pow2(unsigned int p);
static void _bind_methods();
@ -102,6 +102,10 @@ private:
// Voxel access will most frequently be in contiguous areas, so the same blocks are accessed.
// To prevent too much hashing, this reference is checked before.
VoxelBlock *_last_accessed_block;
unsigned int _block_size;
unsigned int _block_size_pow2;
unsigned int _block_size_mask;
};
#endif // VOXEL_MAP_H

View File

@ -49,7 +49,7 @@ void VoxelProviderTest::generate_block_flat(VoxelBuffer &out_buffer, Vector3i bl
// TODO Don't expect a block pos, but a voxel pos!
Vector3i size = out_buffer.get_size();
Vector3i origin = VoxelMap::block_to_voxel(block_pos);
Vector3i origin = size * block_pos;
int rh = _pattern_offset.y - origin.y;
if (rh > size.y)
@ -66,8 +66,10 @@ void VoxelProviderTest::generate_block_flat(VoxelBuffer &out_buffer, Vector3i bl
void VoxelProviderTest::generate_block_waves(VoxelBuffer &out_buffer, Vector3i block_pos) {
// TODO Don't expect a block pos, but a voxel pos!
Vector3i size = out_buffer.get_size();
Vector3i origin = VoxelMap::block_to_voxel(block_pos) + _pattern_offset;
Vector3i origin = size * block_pos + _pattern_offset;
float amplitude = static_cast<float>(_pattern_size.y);
float period_x = 1.f / static_cast<float>(_pattern_size.x);
float period_z = 1.f / static_cast<float>(_pattern_size.z);

View File

@ -3,6 +3,7 @@
#include <os/os.h>
#include <scene/3d/mesh_instance.h>
VoxelTerrain::VoxelTerrain()
: Node(), _generate_collisions(true) {
@ -90,12 +91,12 @@ void VoxelTerrain::set_generate_collisions(bool enabled) {
}
int VoxelTerrain::get_view_distance() const {
return _view_distance_blocks * VoxelBlock::SIZE;
return _view_distance_blocks * _map->get_block_size();
}
void VoxelTerrain::set_view_distance(int distance_in_voxels) {
ERR_FAIL_COND(distance_in_voxels < 0)
int d = distance_in_voxels / VoxelBlock::SIZE;
int d = distance_in_voxels / _map->get_block_size();
if(d != _view_distance_blocks) {
_view_distance_blocks = d;
make_all_view_dirty();
@ -174,17 +175,17 @@ inline int get_border_index(int x, int max) {
void VoxelTerrain::make_voxel_dirty(Vector3i pos) {
// Update the block in which the voxel is
Vector3i bpos = VoxelMap::voxel_to_block(pos);
Vector3i bpos = _map->voxel_to_block(pos);
make_block_dirty(bpos);
//OS::get_singleton()->print("Dirty (%i, %i, %i)\n", bpos.x, bpos.y, bpos.z);
// Update neighbor blocks if the voxel is touching a boundary
Vector3i rpos = VoxelMap::to_local(pos);
Vector3i rpos = _map->to_local(pos);
bool check_corners = _mesher->get_occlusion_enabled();
const int max = VoxelBlock::SIZE - 1;
const int max = _map->get_block_size() - 1;
if (rpos.x == 0)
make_block_dirty(bpos - Vector3i(1, 0, 0));
@ -316,10 +317,12 @@ void VoxelTerrain::_process() {
void VoxelTerrain::update_blocks() {
OS &os = *OS::get_singleton();
ERR_FAIL_COND(_map.is_null());
// Get viewer location
Spatial *viewer = get_viewer(_viewer_path);
if (viewer)
g_viewer_block_pos = VoxelMap::voxel_to_block(viewer->get_translation());
g_viewer_block_pos = _map->voxel_to_block(viewer->get_translation());
else
g_viewer_block_pos = Vector3i();
@ -331,6 +334,9 @@ void VoxelTerrain::update_blocks() {
uint32_t time_before = os.get_ticks_msec();
uint32_t max_time = 1000 / 120;
const unsigned int bs = _map->get_block_size();
const Vector3i block_size(bs, bs, bs);
// Update a bunch of blocks until none are left or too much time elapsed
while (!_block_update_queue.empty() && (os.get_ticks_msec() - time_before) < max_time) {
@ -352,7 +358,6 @@ void VoxelTerrain::update_blocks() {
VOXEL_PROFILE_BEGIN("voxel_buffer_creation_gen")
Ref<VoxelBuffer> buffer_ref = Ref<VoxelBuffer>(memnew(VoxelBuffer));
const Vector3i block_size(VoxelBlock::SIZE, VoxelBlock::SIZE, VoxelBlock::SIZE);
buffer_ref->create(block_size.x, block_size.y, block_size.z);
VOXEL_PROFILE_END("voxel_buffer_creation_gen")
@ -426,14 +431,15 @@ void VoxelTerrain::update_block_mesh(Vector3i block_pos) {
// TODO Make the buffer re-usable
// TODO Padding set to 3 at the moment because Transvoxel works on 2x2 cells.
// It should change for a smarter padding (if smooth isn't used for example).
nbuffer.create(VoxelBlock::SIZE + 3, VoxelBlock::SIZE + 3, VoxelBlock::SIZE + 3);
unsigned int block_size = _map->get_block_size();
nbuffer.create(block_size + 3, block_size + 3, block_size + 3);
VOXEL_PROFILE_END("voxel_buffer_creation_extract")
VOXEL_PROFILE_BEGIN("block_extraction")
_map->get_buffer_copy(VoxelMap::block_to_voxel(block_pos) - Vector3i(1, 1, 1), nbuffer, 0x3);
_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 = VoxelMap::block_to_voxel(block_pos).to_vec3();
Vector3 block_node_pos = _map->block_to_voxel(block_pos).to_vec3();
// TODO Re-use existing meshes to optimize memory cost
@ -533,6 +539,14 @@ Variant VoxelTerrain::_raycast_binding(Vector3 origin, Vector3 direction, real_t
}
}
Vector3 VoxelTerrain::_voxel_to_block_binding(Vector3 pos) {
return Vector3i(_map->voxel_to_block(pos)).to_vec3();
}
Vector3 VoxelTerrain::_block_to_voxel_binding(Vector3 pos) {
return Vector3i(_map->block_to_voxel(pos)).to_vec3();
}
void VoxelTerrain::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_provider", "provider"), &VoxelTerrain::set_provider);

View File

@ -67,8 +67,8 @@ private:
static void _bind_methods();
// Convenience
Vector3 _voxel_to_block_binding(Vector3 pos) { return Vector3i(VoxelMap::voxel_to_block(pos)).to_vec3(); }
Vector3 _block_to_voxel_binding(Vector3 pos) { return Vector3i(VoxelMap::block_to_voxel(pos)).to_vec3(); }
Vector3 _voxel_to_block_binding(Vector3 pos);
Vector3 _block_to_voxel_binding(Vector3 pos);
void _force_load_blocks_binding(Vector3 center, Vector3 extents) { force_load_blocks(center, extents); }
void _make_block_dirty_binding(Vector3 bpos) { make_block_dirty(bpos); }
void _make_blocks_dirty_binding(Vector3 min, Vector3 size) { make_blocks_dirty(min, size); }