2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
#include "voxel_mesher_smooth.h"
|
|
|
|
|
#include "transvoxel_tables.cpp"
|
|
|
|
|
#include <os/os.h>
|
|
|
|
|
|
|
|
|
|
inline float tof(int8_t v) {
|
|
|
|
|
return static_cast<float>(v) / 256.f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline int8_t tos(uint8_t v) {
|
|
|
|
|
return v - 128;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Values considered negative have a sign bit of 1
|
|
|
|
|
inline uint8_t sign(int8_t v) {
|
|
|
|
|
return (v >> 7) & 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 6-------7
|
|
|
|
|
// /| /|
|
|
|
|
|
// / | / | Corners
|
|
|
|
|
// 4-------5 |
|
|
|
|
|
// | 2----|--3
|
|
|
|
|
// | / | / z y
|
|
|
|
|
// |/ |/ |/
|
|
|
|
|
// 0-------1 o--x
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
const Vector3i g_corner_dirs[8] = {
|
|
|
|
|
Vector3i(0, 0, 0),
|
|
|
|
|
Vector3i(1, 0, 0),
|
|
|
|
|
Vector3i(0, 1, 0),
|
|
|
|
|
Vector3i(1, 1, 0),
|
|
|
|
|
Vector3i(0, 0, 1),
|
|
|
|
|
Vector3i(1, 0, 1),
|
|
|
|
|
Vector3i(0, 1, 1),
|
|
|
|
|
Vector3i(1, 1, 1)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline Vector3i dir_to_prev_vec(uint8_t dir) {
|
|
|
|
|
//return g_corner_dirs[mask] - Vector3(1,1,1);
|
|
|
|
|
return Vector3i(
|
2017-08-13 01:19:39 +02:00
|
|
|
|
-(dir & 1),
|
|
|
|
|
-((dir >> 1) & 1),
|
|
|
|
|
-((dir >> 2) & 1));
|
2017-04-06 23:44:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
template <typename T>
|
|
|
|
|
void copy_to(PoolVector<T> &to, Vector<T> &from) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
to.resize(from.size());
|
|
|
|
|
|
2017-08-15 21:37:23 +02:00
|
|
|
|
typename PoolVector<T>::Write w = to.write();
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
for (unsigned int i = 0; i < from.size(); ++i) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
w[i] = from[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VoxelMesherSmooth::ReuseCell::ReuseCell() {
|
|
|
|
|
case_index = 0;
|
2017-08-13 01:19:39 +02:00
|
|
|
|
for (unsigned int i = 0; i < 4; ++i) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
vertices[i] = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VoxelMesherSmooth::VoxelMesherSmooth() {
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-24 01:20:24 +02:00
|
|
|
|
Ref<ArrayMesh> VoxelMesherSmooth::build_ref(Ref<VoxelBuffer> voxels_ref, unsigned int channel, Ref<ArrayMesh> mesh) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
2017-06-24 01:20:24 +02:00
|
|
|
|
ERR_FAIL_COND_V(voxels_ref.is_null(), Ref<ArrayMesh>());
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
VoxelBuffer &voxels = **voxels_ref;
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
return build(voxels, channel, mesh);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
Ref<ArrayMesh> VoxelMesherSmooth::build(const VoxelBuffer &voxels, unsigned int channel, Ref<ArrayMesh> mesh) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
2017-06-24 01:20:24 +02:00
|
|
|
|
ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Ref<ArrayMesh>());
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
// Initialize dynamic memory:
|
|
|
|
|
// These vectors are re-used.
|
|
|
|
|
// We don't know in advance how much geometry we are going to produce.
|
|
|
|
|
// Once capacity is big enough, no more memory should be allocated
|
|
|
|
|
m_output_vertices.clear();
|
|
|
|
|
//m_output_vertices_secondary.clear();
|
|
|
|
|
m_output_normals.clear();
|
|
|
|
|
m_output_indices.clear();
|
|
|
|
|
|
|
|
|
|
build_mesh(voxels, channel);
|
2017-08-13 01:19:39 +02:00
|
|
|
|
// OS::get_singleton()->print("vertices: %i, normals: %i, indices: %i\n",
|
|
|
|
|
// m_output_vertices.size(),
|
|
|
|
|
// m_output_normals.size(),
|
|
|
|
|
// m_output_indices.size());
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
if (m_output_vertices.size() == 0) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
// The mesh can be empty
|
2017-06-24 01:20:24 +02:00
|
|
|
|
return Ref<ArrayMesh>();
|
2017-04-06 23:44:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PoolVector<Vector3> vertices;
|
|
|
|
|
PoolVector<Vector3> normals;
|
|
|
|
|
PoolVector<int> indices;
|
|
|
|
|
|
|
|
|
|
copy_to(vertices, m_output_vertices);
|
|
|
|
|
copy_to(normals, m_output_normals);
|
|
|
|
|
copy_to(indices, m_output_indices);
|
|
|
|
|
|
|
|
|
|
Array arrays;
|
|
|
|
|
arrays.resize(Mesh::ARRAY_MAX);
|
|
|
|
|
arrays[Mesh::ARRAY_VERTEX] = vertices;
|
2017-08-13 01:19:39 +02:00
|
|
|
|
if (m_output_normals.size() != 0) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
arrays[Mesh::ARRAY_NORMAL] = normals;
|
|
|
|
|
}
|
|
|
|
|
arrays[Mesh::ARRAY_INDEX] = indices;
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
if (mesh.is_null())
|
2017-06-24 01:20:24 +02:00
|
|
|
|
mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
|
|
|
|
|
|
|
|
|
|
return mesh;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
void VoxelMesherSmooth::build_mesh(const VoxelBuffer &voxels, unsigned int channel) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
// Each 2x2 voxel group is a "cell"
|
|
|
|
|
|
|
|
|
|
const Vector3i block_size = voxels.get_size();
|
|
|
|
|
// TODO No lod yet, but it's planned
|
|
|
|
|
const int lod_index = 0;
|
|
|
|
|
const int lod_scale = 1 << lod_index;
|
|
|
|
|
|
|
|
|
|
// Prepare vertex reuse cache
|
|
|
|
|
m_block_size = block_size;
|
|
|
|
|
unsigned int deck_area = block_size.x * block_size.y;
|
2017-08-13 01:19:39 +02:00
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
|
if (m_cache[i].size() != deck_area) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
m_cache[i].clear(); // Clear any previous data
|
|
|
|
|
m_cache[i].resize(deck_area);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Iterate all cells with padding (expected to be neighbors)
|
|
|
|
|
Vector3i pos;
|
2017-08-13 01:19:39 +02:00
|
|
|
|
for (pos.z = PAD.z; pos.z < block_size.z - 2; ++pos.z) {
|
|
|
|
|
for (pos.y = PAD.y; pos.y < block_size.y - 2; ++pos.y) {
|
|
|
|
|
for (pos.x = PAD.x; pos.x < block_size.x - 2; ++pos.x) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
// Get the value of cells.
|
|
|
|
|
// Negative values are "solid" and positive are "air".
|
|
|
|
|
// Due to raw cells being unsigned 8-bit, they get converted to signed.
|
|
|
|
|
int8_t cell_samples[8] = {
|
2017-08-13 01:19:39 +02:00
|
|
|
|
tos(voxels.get_voxel(pos.x, pos.y, pos.z, channel)),
|
|
|
|
|
tos(voxels.get_voxel(pos.x + 1, pos.y, pos.z, channel)),
|
|
|
|
|
tos(voxels.get_voxel(pos.x, pos.y + 1, pos.z, channel)),
|
|
|
|
|
tos(voxels.get_voxel(pos.x + 1, pos.y + 1, pos.z, channel)),
|
|
|
|
|
tos(voxels.get_voxel(pos.x, pos.y, pos.z + 1, channel)),
|
|
|
|
|
tos(voxels.get_voxel(pos.x + 1, pos.y, pos.z + 1, channel)),
|
|
|
|
|
tos(voxels.get_voxel(pos.x, pos.y + 1, pos.z + 1, channel)),
|
|
|
|
|
tos(voxels.get_voxel(pos.x + 1, pos.y + 1, pos.z + 1, channel))
|
2017-04-06 23:44:11 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Concatenate the sign of cell values to obtain the case code.
|
|
|
|
|
// Index 0 is the less significant bit, and index 7 is the most significant bit.
|
2017-08-13 01:19:39 +02:00
|
|
|
|
uint8_t case_code = sign(cell_samples[0]);
|
|
|
|
|
case_code |= (sign(cell_samples[1]) << 1);
|
|
|
|
|
case_code |= (sign(cell_samples[2]) << 2);
|
|
|
|
|
case_code |= (sign(cell_samples[3]) << 3);
|
|
|
|
|
case_code |= (sign(cell_samples[4]) << 4);
|
|
|
|
|
case_code |= (sign(cell_samples[5]) << 5);
|
|
|
|
|
case_code |= (sign(cell_samples[6]) << 6);
|
|
|
|
|
case_code |= (sign(cell_samples[7]) << 7);
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
{
|
2017-08-13 01:19:39 +02:00
|
|
|
|
ReuseCell &rc = get_reuse_cell(pos);
|
2017-04-06 23:44:11 +02:00
|
|
|
|
rc.case_index = case_code;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
if (case_code == 0 || case_code == 255) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
// If the case_code is 0 or 255, there is no triangulation to do
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO We might not always need all of them
|
|
|
|
|
// Compute normals
|
|
|
|
|
Vector3 corner_normals[8];
|
2017-08-13 01:19:39 +02:00
|
|
|
|
for (unsigned int i = 0; i < 8; ++i) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
Vector3i p = pos + g_corner_dirs[i];
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
float nx = tof(tos(voxels.get_voxel(p - Vector3i(1, 0, 0), channel))) - tof(tos(voxels.get_voxel(p + Vector3i(1, 0, 0), channel)));
|
|
|
|
|
float ny = tof(tos(voxels.get_voxel(p - Vector3i(0, 1, 0), channel))) - tof(tos(voxels.get_voxel(p + Vector3i(0, 1, 0), channel)));
|
|
|
|
|
float nz = tof(tos(voxels.get_voxel(p - Vector3i(0, 0, 1), channel))) - tof(tos(voxels.get_voxel(p + Vector3i(0, 0, 1), channel)));
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
corner_normals[i] = Vector3(nx, ny, nz);
|
|
|
|
|
corner_normals[i].normalize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For cells occurring along the minimal boundaries of a block,
|
|
|
|
|
// the preceding cells needed for vertex reuse may not exist.
|
|
|
|
|
// In these cases, we allow new vertex creation on additional edges of a cell.
|
|
|
|
|
// While iterating through the cells in a block, a 3-bit mask is maintained whose bits indicate
|
|
|
|
|
// whether corresponding bits in a direction code are valid
|
|
|
|
|
uint8_t direction_validity_mask =
|
2017-08-13 01:19:39 +02:00
|
|
|
|
(pos.x > 1 ? 1 : 0) | ((pos.y > 1 ? 1 : 0) << 1) | ((pos.z > 1 ? 1 : 0) << 2);
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
uint8_t regular_cell_class_index = Transvoxel::regularCellClass[case_code];
|
|
|
|
|
Transvoxel::RegularCellData regular_cell_class = Transvoxel::regularCellData[regular_cell_class_index];
|
|
|
|
|
uint8_t triangle_count = regular_cell_class.geometryCounts & 0x0f;
|
|
|
|
|
uint8_t vertex_count = (regular_cell_class.geometryCounts & 0xf0) >> 4;
|
|
|
|
|
|
|
|
|
|
int cell_mesh_indices[12];
|
|
|
|
|
|
|
|
|
|
// For each vertex in the case
|
2017-08-13 01:19:39 +02:00
|
|
|
|
for (unsigned int i = 0; i < vertex_count; ++i) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
// The case index maps to a list of 16-bit codes providing information about the edges on which the vertices lie.
|
|
|
|
|
// The low byte of each 16-bit code contains the corner indexes of the edge’s endpoints in one nibble each,
|
|
|
|
|
// and the high byte contains the mapping code shown in Figure 3.8(b)
|
|
|
|
|
unsigned short rvd = Transvoxel::regularVertexData[case_code][i];
|
|
|
|
|
unsigned short edge_code_low = rvd & 0xff;
|
|
|
|
|
unsigned short edge_code_high = (rvd >> 8) & 0xff;
|
|
|
|
|
|
|
|
|
|
// Get corner indexes in the low nibble (always ordered so the higher comes last)
|
|
|
|
|
uint8_t v0 = (edge_code_low >> 4) & 0xf;
|
|
|
|
|
uint8_t v1 = edge_code_low & 0xf;
|
|
|
|
|
|
|
|
|
|
ERR_FAIL_COND(v1 <= v0);
|
|
|
|
|
|
|
|
|
|
// Get voxel values at the corners
|
|
|
|
|
int sample0 = cell_samples[v0]; // called d0 in the paper
|
|
|
|
|
int sample1 = cell_samples[v1]; // called d1 in the paper
|
|
|
|
|
|
|
|
|
|
// TODO Zero-division is not mentionned in the paper??
|
|
|
|
|
ERR_FAIL_COND(sample1 == sample0);
|
|
|
|
|
ERR_FAIL_COND(sample1 == 0 && sample0 == 0);
|
|
|
|
|
|
|
|
|
|
// Get interpolation position
|
|
|
|
|
// We use an 8-bit fraction, allowing the new vertex to be located at one of 257 possible
|
|
|
|
|
// positions along the edge when both endpoints are included.
|
|
|
|
|
int t = (sample1 << 8) / (sample1 - sample0);
|
|
|
|
|
|
|
|
|
|
float t0 = static_cast<float>(t) / 256.f;
|
|
|
|
|
float t1 = static_cast<float>(0x0100 - t) / 256.f;
|
|
|
|
|
|
|
|
|
|
Vector3i p0 = pos + g_corner_dirs[v0];
|
|
|
|
|
Vector3i p1 = pos + g_corner_dirs[v1];
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
if (t & 0xff) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
//OS::get_singleton()->print("A");
|
|
|
|
|
// Vertex lies in the interior of the edge.
|
|
|
|
|
|
|
|
|
|
// Each edge of a cell is assigned an 8-bit code, as shown in Figure 3.8(b),
|
|
|
|
|
// that provides a mapping to a preceding cell and the coincident edge on that preceding cell
|
|
|
|
|
// for which new vertex creation was allowed.
|
|
|
|
|
// The high nibble of this code indicates which direction to go in order to reach the correct preceding cell.
|
|
|
|
|
// The bit values 1, 2, and 4 in this nibble indicate that we must subtract one
|
|
|
|
|
// from the x, y, and/or z coordinate, respectively.
|
|
|
|
|
uint8_t reuse_dir = (edge_code_high >> 4) & 0xf;
|
|
|
|
|
uint8_t reuse_vertex_index = edge_code_high & 0xf;
|
|
|
|
|
|
|
|
|
|
bool can_reuse = (reuse_dir & direction_validity_mask) == reuse_dir;
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
if (can_reuse) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
Vector3i cache_pos = pos + dir_to_prev_vec(reuse_dir);
|
2017-08-13 01:19:39 +02:00
|
|
|
|
ReuseCell &prev_cell = get_reuse_cell(cache_pos);
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
if (prev_cell.case_index == 0 || prev_cell.case_index == 255) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
// TODO I don't think this can happen for non-corner vertices.
|
|
|
|
|
cell_mesh_indices[i] = -1;
|
|
|
|
|
} else {
|
|
|
|
|
// Will reuse a previous vertice
|
|
|
|
|
cell_mesh_indices[i] = prev_cell.vertices[reuse_vertex_index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
if (!can_reuse || cell_mesh_indices[i] == -1) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
// Going to create a new vertice
|
|
|
|
|
|
|
|
|
|
cell_mesh_indices[i] = m_output_vertices.size();
|
|
|
|
|
|
|
|
|
|
Vector3 pi = p0.to_vec3() * t0 + p1.to_vec3() * t1;
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
Vector3 primary = pi; //pos.to_vec3() + pi;
|
2017-04-06 23:44:11 +02:00
|
|
|
|
Vector3 normal = corner_normals[v0] * t0 + corner_normals[v1] * t1;
|
|
|
|
|
|
|
|
|
|
emit_vertex(primary, normal);
|
|
|
|
|
|
|
|
|
|
if (reuse_dir & 8) {
|
|
|
|
|
// Store the generated vertex so that other cells can reuse it.
|
2017-08-13 01:19:39 +02:00
|
|
|
|
ReuseCell &rc = get_reuse_cell(pos);
|
2017-04-06 23:44:11 +02:00
|
|
|
|
rc.vertices[reuse_vertex_index] = cell_mesh_indices[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
} else if (t == 0 && v1 == 7) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
|
|
|
|
|
//OS::get_singleton()->print("B");
|
|
|
|
|
// This cell owns the vertex, so it should be created.
|
|
|
|
|
|
|
|
|
|
cell_mesh_indices[i] = m_output_vertices.size();
|
|
|
|
|
|
|
|
|
|
Vector3 pi = p0.to_vec3() * t0 + p1.to_vec3() * t1;
|
2017-08-13 01:19:39 +02:00
|
|
|
|
Vector3 primary = pi; //pos.to_vec3() + pi;
|
2017-04-06 23:44:11 +02:00
|
|
|
|
Vector3 normal = corner_normals[v0] * t0 + corner_normals[v1] * t1;
|
|
|
|
|
|
|
|
|
|
emit_vertex(primary, normal);
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
ReuseCell &rc = get_reuse_cell(pos);
|
2017-04-06 23:44:11 +02:00
|
|
|
|
rc.vertices[0] = cell_mesh_indices[i];
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// Always try to reuse previous vertices in these cases
|
|
|
|
|
|
|
|
|
|
//OS::get_singleton()->print("C");
|
|
|
|
|
// A 3-bit direction code leading to the proper cell can easily be obtained by
|
|
|
|
|
// inverting the 3-bit corner index (bitwise, by exclusive ORing with the number 7).
|
|
|
|
|
// The corner index depends on the value of t, t = 0 means that we're at the higher
|
|
|
|
|
// numbered endpoint.
|
|
|
|
|
uint8_t reuse_dir = (t == 0 ? v1 ^ 7 : v0 ^ 7);
|
|
|
|
|
bool can_reuse = (reuse_dir & direction_validity_mask) == reuse_dir;
|
|
|
|
|
|
|
|
|
|
// Note: the only difference with similar code above is that we take vertice 0 in the `else`
|
2017-08-13 01:19:39 +02:00
|
|
|
|
if (can_reuse) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
Vector3i cache_pos = pos + dir_to_prev_vec(reuse_dir);
|
|
|
|
|
ReuseCell prev_cell = get_reuse_cell(cache_pos);
|
|
|
|
|
|
|
|
|
|
// The previous cell might not have any geometry, and we
|
|
|
|
|
// might therefore have to create a new vertex anyway.
|
|
|
|
|
if (prev_cell.case_index == 0 || prev_cell.case_index == 255) {
|
|
|
|
|
cell_mesh_indices[i] = -1;
|
|
|
|
|
} else {
|
|
|
|
|
cell_mesh_indices[i] = prev_cell.vertices[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
if (!can_reuse || cell_mesh_indices[i] < 0) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
cell_mesh_indices[i] = m_output_vertices.size();
|
|
|
|
|
|
|
|
|
|
Vector3 pi = p0.to_vec3() * t0 + p1.to_vec3() * t1;
|
2017-08-13 01:19:39 +02:00
|
|
|
|
Vector3 primary = pi; //pos.to_vec3() + pi;
|
2017-04-06 23:44:11 +02:00
|
|
|
|
Vector3 normal = corner_normals[v0] * t0 + corner_normals[v1] * t1;
|
|
|
|
|
|
|
|
|
|
emit_vertex(primary, normal);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // for each cell vertice
|
|
|
|
|
|
|
|
|
|
//OS::get_singleton()->print("_");
|
|
|
|
|
|
|
|
|
|
for (int t = 0; t < triangle_count; ++t) {
|
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
|
int index = cell_mesh_indices[regular_cell_class.vertexIndex[t * 3 + i]];
|
|
|
|
|
m_output_indices.push_back(index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // x
|
|
|
|
|
} // y
|
|
|
|
|
} // z
|
|
|
|
|
|
|
|
|
|
//OS::get_singleton()->print("\n");
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-13 01:19:39 +02:00
|
|
|
|
VoxelMesherSmooth::ReuseCell &VoxelMesherSmooth::get_reuse_cell(Vector3i pos) {
|
2017-04-06 23:44:11 +02:00
|
|
|
|
int j = pos.z & 1;
|
|
|
|
|
int i = pos.y * m_block_size.y + pos.x;
|
|
|
|
|
return m_cache[j][i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoxelMesherSmooth::emit_vertex(Vector3 primary, Vector3 normal) {
|
|
|
|
|
m_output_vertices.push_back(primary - PAD.to_vec3());
|
|
|
|
|
m_output_normals.push_back(normal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoxelMesherSmooth::_bind_methods() {
|
|
|
|
|
|
2017-08-13 00:08:53 +02:00
|
|
|
|
ClassDB::bind_method(D_METHOD("build", "voxels", "channel", "existing_mesh"), &VoxelMesherSmooth::build_ref, DEFVAL(Variant()));
|
2017-04-06 23:44:11 +02:00
|
|
|
|
}
|