mirror of
https://github.com/Relintai/godot_voxel.git
synced 2024-11-11 20:35:08 +01:00
Block size is no longer a constant
This commit is contained in:
parent
cb6de49b96
commit
cb548234fc
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
voxel_map.h
36
voxel_map.h
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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); }
|
||||
|
Loading…
Reference in New Issue
Block a user