Working naive voxel mesher.
This commit is contained in:
197
packages/voxel_mesher/src/lib.rs
Normal file
197
packages/voxel_mesher/src/lib.rs
Normal 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);
|
||||
Reference in New Issue
Block a user