Added x-based greedy voxel meshing

This commit is contained in:
Lucas Dower 2021-07-05 16:11:16 +01:00
parent 69affc8a8b
commit d304993362
6 changed files with 174 additions and 11 deletions

View File

@ -17,12 +17,18 @@
<button id="objBtn" class="btn btn-primary" type="button" id="inputGroupFileAddon04">Load</button>
</div>
<div class="input-group w-25 mx-auto">
<label class="input-group-text" for="inputGroupFileAddon03">Options</label>
<input type="number" min="0.1" step="0.1" value="1.0" class="form-control" id="voxelInput" aria-describedby="inputGroupFileAddon03" aria-label="Voxel size" disabled>
<label class="input-group-text" for="inputGroupFileAddon03">Voxel size</label>
<input type="number" min="0.1" step="0.1" value="0.1" class="form-control" id="voxelInput" aria-describedby="inputGroupFileAddon03" aria-label="Voxel size" disabled>
<button id="voxelBtn" class="btn btn-primary" type="button" id="inputGroupFileAddon03" disabled>Voxelise</button>
</div>
</nav>
<div class="progress" style="height: 1px;">
<div class="progress-bar" role="progressbar" style="width: 25%;" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<canvas id="c"></canvas>
</body>

View File

@ -3,7 +3,8 @@ const { Mesh } = require('./src/mesh.js');
const { VoxelManager } = require('./src/voxel_manager.js');
const { Vector3 } = require('./src/vector.js');
const voxelSize = 0.5;
//const voxelSize = document.querySelector("#voxelInput").value;
const voxelSize = 0.05;
let renderer = new Renderer(voxelSize);
const voxelManager = new VoxelManager(voxelSize);
@ -63,6 +64,29 @@ document.querySelector("#voxelBtn").addEventListener('click', () => {
renderer.compileRegister();
});
loadedMesh = new Mesh("./resources/suzanne.obj");
voxelManager.voxeliseMesh(loadedMesh);
const useNew = true;
const useDebug = true;
if (useNew) {
const mesh = voxelManager.buildMesh();
for (const box of mesh) {
renderer.registerBox(box.centre, box.size, useDebug);
}
} else {
renderer.registerVoxels(voxelManager.voxels, useDebug);
}
//console.log(voxelManager.voxels.length, "->", k.length, voxelManager.voxels.length/k.length);
//renderer.setStroke(new Vector3(1.0, 0.0, 0.0));
//renderer.registerVoxels(voxelManager.voxels, true);
renderer.compileRegister();
function render(time) {
resizeCanvas();

View File

@ -14,7 +14,6 @@ class HashMap {
add(key, value) {
const binIndex = this._getBin(key);
console.log(binIndex);
if (!this.bins[binIndex]) {
this.bins[binIndex] = [ {key: key, value: value} ];
@ -39,6 +38,46 @@ class HashMap {
}
}
class HashSet {
constructor(numBins) {
this.numBins = numBins;
this.bins = new Array(numBins);
}
_getBin(key) {
const hash = key.hash(); // A bit naughty
return Math.abs(hash) % this.numBins;
}
add(key) {
const binIndex = this._getBin(key);
if (!this.bins[binIndex]) {
this.bins[binIndex] = [ key ];
} else {
this.bins[binIndex].push(key);
}
}
contains(key) {
const binIndex = this._getBin(key);
if (!this.bins[binIndex]) {
return false;
}
const list = this.bins[binIndex];
for (const item of list) {
if (item.equals(key)) {
return true;
}
}
return false;
}
}
/*
const hashMap = new HashMap(4);
const v = new Vector3(2.0, 2.0, 3.0);
const v2 = new Vector3(2.0, 2.0, 5.0);
@ -57,4 +96,8 @@ console.log(hashMap.bins[3]);
console.log(hashMap.get(v));
console.log(hashMap.get(v2));
console.log(hashMap.get(v3));
console.log(hashMap.get(v4));
console.log(hashMap.get(v4));
*/
module.exports.HashMap = HashMap;
module.exports.HashSet = HashSet;

View File

@ -32,7 +32,7 @@ class Renderer {
this._voxelSize = voxelSize;
this._voxelSizeVector = new Vector3(voxelSize, voxelSize, voxelSize);
this._cube = twgl.primitives.createCubeVertices(this._voxelSize);
this._cube = twgl.primitives.createCubeVertices(1.0);
this._registersOpen = true;
}
@ -139,7 +139,6 @@ class Renderer {
setVoxelSize(voxelSize) {
this._voxelSize = voxelSize;
this._voxelSizeVector = new Vector3(voxelSize, voxelSize, voxelSize);
this._cube = twgl.primitives.createCubeVertices(this._voxelSize);
}
_drawDebugRegisters() {
@ -195,6 +194,7 @@ class Renderer {
]
};
} else {
let cube = {
position: new Float32Array(72),
normal: new Float32Array(72),
@ -206,9 +206,9 @@ class Renderer {
cube.indices.set(this._cube.indices);
for (let i = 0; i < 72; i += 3) {
cube.position[i + 0] += centre.x;
cube.position[i + 1] += centre.y;
cube.position[i + 2] += centre.z;
cube.position[i + 0] = (cube.position[i + 0] * size.x) + centre.x;
cube.position[i + 1] = (cube.position[i + 1] * size.y) + centre.y;
cube.position[i + 2] = (cube.position[i + 2] * size.z) + centre.z;
}
return cube;
@ -272,6 +272,7 @@ class Renderer {
// Use when drawing the same thing each frame
registerBox(centre, size, debug) {
const data = this._getBoxData(centre, size, debug);
//console.log(data);
this._addDataToRegister(data, debug);
}
@ -299,9 +300,16 @@ class Renderer {
}
registerVoxels(voxelCentres, debug) {
/*
for (let i = 0; i < voxelCentres.length; ++i) {
console.log(i / voxelCentres.length);
this.registerVoxel(voxelCentres[i], debug);
}
*/
for (const voxelCentre of voxelCentres) {
this.registerVoxel(voxelCentre, debug);
}
}
_cycleDebugRegister() {
@ -317,6 +325,10 @@ class Renderer {
//console.log("Cycling Registers");
}
_willDataOverflowBuffer(data) {
}
_addDataToRegister(data, debug) {
if (!this._registersOpen) {
console.error("Trying to register object when register is closed. Register before calling compileRegister()");

View File

@ -26,6 +26,14 @@ class Vector3 {
);
}
static subScalar(vec, scalar) {
return new Vector3(
vec.x - scalar,
vec.y - scalar,
vec.z - scalar
);
}
static dot(vecA, vecB) {
return vecA.x * vecB.x + vecA.y * vecB.y + vecA.z * vecB.z;
}

View File

@ -1,5 +1,6 @@
const { AABB, CubeAABB } = require("./aabb.js");
const { Vector3 } = require("./vector.js");
const { HashSet } = require('./hash_map.js');
class VoxelManager {
@ -7,6 +8,14 @@ class VoxelManager {
this._voxelSize = voxelSize;
this.voxels = [];
this.failedAABBs = [];
this.minX = Infinity; // JavaScript crack
this.minY = Infinity;
this.minZ = Infinity;
this.maxX = -Infinity;
this.maxY = -Infinity;
this.maxZ = -Infinity;
this.voxelsHash = new HashSet(512);
}
setVoxelSize(voxelSize) {
@ -35,6 +44,66 @@ class VoxelManager {
return cubeAABB;
}
_voxelCentreToPosition(vec) {
//Vector3.round(Vector3.subScalar(Vector3.divScalar(vec, this._voxelSize), 0.5));
return new Vector3(
Math.round((vec.x / this._voxelSize) - 0.5),
Math.round((vec.y / this._voxelSize) - 0.5),
Math.round((vec.z / this._voxelSize) - 0.5)
);
}
addVoxel(vec) {
this.voxels.push(vec);
const pos = this._voxelCentreToPosition(vec);
this.voxelsHash.add(pos, true);
this.minX = Math.min(this.minX, vec.x);
this.minY = Math.min(this.minY, vec.y);
this.minZ = Math.min(this.minZ, vec.z);
this.maxX = Math.max(this.maxX, vec.x);
this.maxY = Math.max(this.maxY, vec.y);
this.maxZ = Math.max(this.maxZ, vec.z);
}
buildMesh() {
let mesh = [];
//const minPos = this._voxelCentreToPosition(new Vector3(this.minX, this.minY, this.minZ));
//const maxPos = this._voxelCentreToPosition(new Vector3(this.maxX, this.maxY, this.maxZ));
for (let y = this.minY; y <= this.maxY; y += this._voxelSize) {
for (let z = this.minZ; z <= this.maxZ; z += this._voxelSize) {
let penDown = false;
let begin = null;
for (let x = this.minX; x < this.maxX + 2 * this._voxelSize; x += this._voxelSize) {
const vec = new Vector3(x, y, z);
const pos = this._voxelCentreToPosition(vec);
const voxelHere = this.voxelsHash.contains(pos);
if (!penDown && voxelHere) {
penDown = true;
begin = vec;
}
else if (penDown && !voxelHere) {
penDown = false;
let end = new Vector3(x - this._voxelSize, y, z);
let centre = Vector3.divScalar(Vector3.add(begin, end), 2);
let size = new Vector3(end.x - begin.x + this._voxelSize, this._voxelSize, this._voxelSize);
mesh.push({centre: centre, size: size});
}
}
}
}
return mesh;
}
voxeliseTriangle(triangle) {
const cubeAABB = this._getTriangleCubeAABB(triangle);
@ -51,7 +120,8 @@ class VoxelManager {
} else {
// We've reached the voxel level, stop
//renderer.registerBox(aabb.centre, aabb.size);
this.voxels.push(aabb.centre);
//this.voxels.push(aabb.centre);
this.addVoxel(aabb.centre);
}
} else {
this.failedAABBs.push(aabb);