Working naive voxel mesher.

This commit is contained in:
Joshua Bemenderfer
2020-10-06 22:11:14 -04:00
parent 0c64ddb7c6
commit c2df101161
31 changed files with 1634 additions and 6 deletions

View File

@@ -0,0 +1,197 @@
use gdnative::prelude::*;
// ```
// 0 1
// +-----+
// | / |
// | / |
// | / |
// +-----+
// 3 2
// ```
const FACES: [[usize; 4]; 6] = [
[5, 4, 0, 1],
[7, 6, 2, 3],
[6, 5, 1, 2],
[4, 7, 3, 0],
[6, 7, 4, 5],
[1, 0, 3, 2],
];
const FACE_ORDER: [usize; 6] = [2, 3, 1, 1, 3, 0];
const VERTICES: [[f32; 3]; 8] = [
[0., 0., 0.],
[1., 0., 0.],
[1., 0., 1.],
[0., 0., 1.],
[0., 1., 0.],
[1., 1., 0.],
[1., 1., 1.],
[0., 1., 1.],
];
const NORMALS: [[f32; 3]; 6] = [
[0., 0., -1.],
[0., 0., 1.],
[1., 0., 0.],
[-1., 0., 0.],
[0., 1., 0.],
[0., -1., 0.],
];
const UVS: [[f32; 2]; 4] = [
[0., 0.],
[1., 0.],
[1., 1.],
[0., 1.]
];
#[derive(Clone)]
struct MeshData {
voxels: i32,
vertices: TypedArray<Vector3>,
uvs: TypedArray<Vector2>,
normals: TypedArray<Vector3>
}
impl MeshData {
fn new() -> MeshData {
MeshData {
voxels: 0,
vertices: TypedArray::<Vector3>::new(),
uvs: TypedArray::<Vector2>::new(),
normals: TypedArray::<Vector3>::new()
}
}
fn resize (&mut self) {
self.vertices.resize(self.voxels * 36);
self.normals.resize(self.voxels * 36);
self.uvs.resize(self.voxels * 36);
}
fn to_dict (self) -> Dictionary<Unique> {
let dict = Dictionary::<Unique>::new();
dict.insert("vertices", self.vertices);
dict.insert("uvs", self.uvs);
dict.insert("normals", self.normals);
dict
}
}
struct SurfaceData {
surfaces: Vec<MeshData>
}
impl SurfaceData {
fn new(size: i32) -> SurfaceData {
let mut surfaces = Vec::<MeshData>::new();
surfaces.resize(size as usize, MeshData::new());
SurfaceData {
surfaces
}
}
fn get(&mut self, idx: usize) -> &mut MeshData {
&mut self.surfaces[idx]
}
fn to_array(self) -> VariantArray<Unique> {
let array = VariantArray::<Unique>::new();
for mesh_data in self.surfaces.into_iter() {
array.push(mesh_data.to_dict());
}
array
}
}
#[derive(NativeClass)]
#[inherit(Node)]
struct VoxelMesher;
#[gdnative::methods]
impl VoxelMesher {
fn new(_owner: &Node) -> Self {
VoxelMesher
}
#[export]
fn mesh(
&self,
_owner: &Node,
voxel_name_index: TypedArray<GodotString>,
chunk_dimensions: Vector3,
chunk_data: TypedArray<i32>
) -> VariantArray<Unique> {
let mut surface_data = SurfaceData::new(voxel_name_index.len());
let max_x = chunk_dimensions.x as i32;
let max_y = chunk_dimensions.y as i32;
for i in 0..chunk_data.len() {
let voxel_id = chunk_data.get(i);
if voxel_id == 0 { continue; }
let mut mesh_data = surface_data.get(voxel_id as usize);
mesh_data.voxels += 1;
}
for mesh_data in &mut surface_data.surfaces {
mesh_data.resize();
mesh_data.voxels = 0;
}
for i in 0..chunk_data.len() {
let voxel_id = chunk_data.get(i);
if voxel_id == 0 {
continue;
}
let mut mesh_data = surface_data.get(voxel_id as usize);
let z = i / (max_x * max_y);
let i2 = i - (z * max_x * max_y);
let y = i2 / max_x;
let x = i2 % max_x;
let pos: [i32; 3] = [x, y, z];
self.mesh_voxel(&mut mesh_data, pos);
mesh_data.voxels += 1;
}
surface_data.to_array()
}
fn mesh_voxel(
&self,
mesh_data: &mut MeshData,
position: [i32; 3]
) {
let voxel_offset = mesh_data.voxels * 36 as i32;
for i in 0..36 {
let idx = voxel_offset + i as i32;
let idx_vertex = i % 6;
let idx_face = (i - idx_vertex) / 6;
let idx_side = FACES[idx_face];
let idx_vertex_coords = FACE_ORDER[idx_vertex];
let mut vertices = VERTICES[idx_side[idx_vertex_coords]];
for j in 0..3 { vertices[j] += position[j] as f32; }
let normals = NORMALS[idx_face];
let uvs = UVS[idx_vertex_coords];
mesh_data.vertices.set(idx, Vector3::new(vertices[0], vertices[1], vertices[2]));
mesh_data.normals.set(idx, Vector3::new(normals[0], normals[1], normals[2]));
mesh_data.uvs.set(idx, Vector2::new(uvs[0], uvs[1]))
}
}
}
fn init(handle: InitHandle) {
handle.add_class::<VoxelMesher>();
}
godot_init!(init);