Added quadtree voxelisation

This commit is contained in:
Lucas Dower 2021-07-03 14:22:23 +01:00
parent 6758bae6a4
commit d1adcd8909
7 changed files with 258 additions and 19 deletions

31
src/aabb.js Normal file
View File

@ -0,0 +1,31 @@
const { Vector3 } = require('./vector.js');
class AABB {
constructor(centre, size) {
this.centre = centre;
this.size = size;
this.a = Vector3.sub(centre, Vector3.mulScalar(size, 0.5));
this.b = Vector3.add(centre, Vector3.mulScalar(size, 0.5));
}
subdivide() {
const newSize = Vector3.divScalar(this.size, 2);
const offset = Vector3.divScalar(this.size, 4);
return [
new AABB(Vector3.add(this.centre, new Vector3(-offset.x, -offset.y, -offset.z)), newSize),
new AABB(Vector3.add(this.centre, new Vector3( offset.x, -offset.y, -offset.z)), newSize),
new AABB(Vector3.add(this.centre, new Vector3(-offset.x, offset.y, -offset.z)), newSize),
new AABB(Vector3.add(this.centre, new Vector3( offset.x, offset.y, -offset.z)), newSize),
new AABB(Vector3.add(this.centre, new Vector3(-offset.x, -offset.y, offset.z)), newSize),
new AABB(Vector3.add(this.centre, new Vector3( offset.x, -offset.y, offset.z)), newSize),
new AABB(Vector3.add(this.centre, new Vector3(-offset.x, offset.y, offset.z)), newSize),
new AABB(Vector3.add(this.centre, new Vector3( offset.x, offset.y, offset.z)), newSize),
];
}
}
module.exports.AABB = AABB;

View File

@ -1,27 +1,22 @@
const { Renderer } = require('./src/renderer.js');
const { Vector3 } = require('./src/vector.js');
const { Triangle } = require('./src/triangle.js');
const { VoxelManager } = require('./src/voxel_manager.js');
const renderer = new Renderer();
const voxelManager = new VoxelManager(0.25);
const triangle = new Triangle(new Vector3(0, 0, 0), new Vector3(4, 3, 1), new Vector3(2, -3, -2));
renderer.registerTriangle(new Vector3(0, 0, 0), new Vector3(1, 0, 1), new Vector3(2, -3, -1));
renderer.registerTriangle(new Vector3(0, 1, 0), new Vector3(1, 1, 1), new Vector3(2, -2, -1));
renderer.setStroke(new Vector3(1.0, 0.0, 0.0));
renderer.registerBox(new Vector3(0, 0, 0), new Vector3(1, 1, 1));
renderer.registerBox(new Vector3(0, 1, 0), new Vector3(1, 1, 1));
renderer.registerTriangle(triangle.v0, triangle.v1, triangle.v2);
voxelManager.voxeliseTriangle(triangle, renderer);
renderer.compileRegister();
function render(time) {
renderer.begin();
//renderer.setStroke(new Vector3(1.0, 0.0, 0.0));
//renderer.drawBox(new Vector3(0, 0, 0), new Vector3(1, 1, 1));
//renderer.setStroke(new Vector3(0.0, 1.0, 0.0));
//renderer.drawBox(new Vector3(0, 1, 0), new Vector3(1, 1, 1));
//renderer.drawTriangle(new Vector3(0, 1, 0), new Vector3(1, 1, 1), new Vector3(2, -2, -1));
renderer.end();

View File

@ -1,6 +1,7 @@
// Not apart of rendering, SIMD optimisation not necessary
const { v3: Vector3 } = require('twgl.js');
const { Vector3 } = require('./vector.js');
/*
function roundTo(value, base) {
return Math.round(value / base) * base;
}
@ -54,9 +55,10 @@ module.exports.fastCrossZAxis = fastCrossZAxis;
module.exports.fastDotXAxis = fastDotXAxis;
module.exports.fastDotYAxis = fastDotYAxis;
module.exports.fastDotZAxis = fastDotZAxis;
*/
module.exports.xAxis = Vector3.create(1.0, 0.0, 0.0);
module.exports.yAxis = Vector3.create(0.0, 1.0, 0.0);
module.exports.zAxis = Vector3.create(0.0, 0.0, 1.0);
module.exports.xAxis = new Vector3(1.0, 0.0, 0.0);
module.exports.yAxis = new Vector3(0.0, 1.0, 0.0);
module.exports.zAxis = new Vector3(0.0, 0.0, 1.0);
module.exports.roundVector3To = roundVector3To;
//module.exports.roundVector3To = roundVector3To;

View File

@ -14,7 +14,7 @@ class Renderer {
this._backgroundColour = new Vector3(0.1, 0.15, 0.2);
this._strokeColour = new Vector3(1.0, 1.0, 1.0);
this._camera = new ArcballCamera(this._fov, this._gl.canvas.clientWidth / this._gl.canvas.clientHeight, 0.5, 30.0);
this._camera = new ArcballCamera(this._fov, this._gl.canvas.clientWidth / this._gl.canvas.clientHeight, 0.5, 100.0);
this._registerEvents();
@ -50,7 +50,7 @@ class Renderer {
begin() {
twgl.resizeCanvasToDisplaySize(this._gl.canvas);
this._gl.viewport(0, 0, this._gl.canvas.width, this._gl.canvas.height);
//this._camera.aspect = this._gl.canvas.width / this._gl.canvas.height;
this._camera.aspect = this._gl.canvas.width / this._gl.canvas.height;
this._gl.blendFuncSeparate(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
this._gl.enable(this._gl.DEPTH_TEST);

88
src/triangle.js Normal file
View File

@ -0,0 +1,88 @@
const { Vector3 } = require('./vector.js');
const { AABB } = require('./aabb.js');
const { xAxis, yAxis, zAxis } = require('./math.js');
class Triangle {
constructor(v0, v1, v2) {
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
this._calculateBoundingBox();
}
_calculateBoundingBox() {
const a = new Vector3(
Math.min(this.v0.x, this.v1.x, this.v2.x),
Math.min(this.v0.y, this.v1.y, this.v2.y),
Math.min(this.v0.z, this.v1.z, this.v2.z)
);
const b = new Vector3(
Math.max(this.v0.x, this.v1.x, this.v2.x),
Math.max(this.v0.y, this.v1.y, this.v2.y),
Math.max(this.v0.z, this.v1.z, this.v2.z)
);
const centre = Vector3.mulScalar(Vector3.add(a, b), 0.5);
const size = Vector3.abs(Vector3.sub(a, b));
this.aabb = new AABB(centre, size);
}
insideAABB(aabb) {
return Vector3.lessThanEqualTo(aabb.a, this.aabb.a) && Vector3.lessThanEqualTo(this.aabb.b, aabb.b);
}
intersectAABB(aabb) {
const extents = Vector3.mulScalar(aabb.size, 0.5);
const v0 = Vector3.sub(this.v0, aabb.centre);
const v1 = Vector3.sub(this.v1, aabb.centre);
const v2 = Vector3.sub(this.v2, aabb.centre);
const f0 = Vector3.sub(v1, v0);
const f1 = Vector3.sub(v2, v1);
const f2 = Vector3.sub(v0, v2);
const axis = [
Vector3.cross(xAxis, f0),
Vector3.cross(xAxis, f1),
Vector3.cross(xAxis, f2),
Vector3.cross(yAxis, f0),
Vector3.cross(yAxis, f1),
Vector3.cross(yAxis, f2),
Vector3.cross(zAxis, f0),
Vector3.cross(zAxis, f1),
Vector3.cross(zAxis, f2),
xAxis,
yAxis,
zAxis,
Vector3.cross(f0, f2)
];
for (const ax of axis) {
if (this._testAxis(v0, v1, v2, ax, extents)) {
return false;
}
}
return true;
}
_testAxis(v0, v1, v2, axis, extents) {
let p0 = Vector3.dot(v0, axis);
let p1 = Vector3.dot(v1, axis);
let p2 = Vector3.dot(v2, axis);
let r = extents.x * Math.abs(Vector3.dot(xAxis, axis)) +
extents.y * Math.abs(Vector3.dot(yAxis, axis)) +
extents.z * Math.abs(Vector3.dot(zAxis, axis));
return (Math.min(p0, p1, p2) > r || Math.max(p0, p1, p2) < -r);
}
}
module.exports.Triangle = Triangle;

View File

@ -1,3 +1,5 @@
const { isVoidExpression, textChangeRangeIsUnchanged } = require("typescript");
class Vector3 {
constructor(x, y, z) {
@ -46,6 +48,42 @@ class Vector3 {
);
}
static divScalar(vec, scalar) {
return new Vector3(
vec.x / scalar,
vec.y / scalar,
vec.z / scalar
);
}
static lessThanEqualTo(vecA, vecB) {
return vecA.x <= vecB.x && vecA.y <= vecB.y && vecA.z <= vecB.z;
}
static round(vec) {
return new Vector3(
Math.round(vec.x),
Math.round(vec.y),
Math.round(vec.z)
);
}
static abs(vec) {
return new Vector3(
Math.abs(vec.x),
Math.abs(vec.y),
Math.abs(vec.z)
);
}
static cross(vecA, vecB) {
return new Vector3(
vecA.y * vecB.z - vecA.z * vecB.y,
vecA.z * vecB.x - vecA.x * vecB.z,
vecA.x * vecB.y - vecA.y * vecB.x
);
}
}
module.exports.Vector3 = Vector3;

85
src/voxel_manager.js Normal file
View File

@ -0,0 +1,85 @@
const { AABB } = require("./aabb.js");
const { Vector3 } = require("./vector.js");
class VoxelManager {
constructor(voxelSize) {
this._voxelSize = voxelSize;
}
cubeifyAABB(aabb, gridSnap) {
const size = aabb.size;
const maxDimension = Math.max(size.x, size.y, size.z);
let newSize = new Vector3(maxDimension, maxDimension, maxDimension);
if (gridSnap) {
let newCentre = Vector3.divScalar(aabb.centre, this._voxelSize);
newCentre = Vector3.round(newCentre);
newCentre = Vector3.mulScalar(newCentre, this._voxelSize);
const offset = Vector3.sub(aabb.centre, newCentre);
console.log(offset);
//let newSize
return new AABB(newCentre, newSize);
}
return new AABB(aabb.centre, newSize);
}
_getTriangleCubeAABB(triangle) {
let gridSnappedCentre = Vector3.divScalar(triangle.aabb.centre, this._voxelSize);
gridSnappedCentre = Vector3.round(gridSnappedCentre);
gridSnappedCentre = Vector3.mulScalar(gridSnappedCentre, this._voxelSize);
let size = this._voxelSize;
let cubeAABB = new AABB(gridSnappedCentre, new Vector3(size, size, size));
while (!triangle.insideAABB(cubeAABB)) {
cubeAABB = new AABB(cubeAABB.centre, Vector3.mulScalar(cubeAABB.size, 2.0));
}
return cubeAABB;
}
voxeliseTriangle(triangle, renderer) {
const cubeAABB = this._getTriangleCubeAABB(triangle);
renderer.setStroke(new Vector3(1.0, 1.0, 1.0));
let queue = [cubeAABB];
while (queue.length > 0) {
const aabb = queue.shift();
if (triangle.intersectAABB(aabb)) {
if (aabb.size.x > this._voxelSize) {
// Continue to subdivicde
queue.push(...aabb.subdivide());
} else {
// We've reached the voxel level, stop
renderer.registerBox(aabb.centre, aabb.size);
}
}
}
//console.log("Main AABB: ", cubeAABB);
/*
const subAABBs = cubeAABB.subdivide();
renderer.setStroke(new Vector3(1.0, 1.0, 0.0));
for (const subAABB of subAABBs) {
if (triangle.intersectAABB(subAABB)) {
renderer.registerBox(subAABB.centre, subAABB.size);
}
}
*/
//const subAABB = subAABBs[0];
//console.log("Sub AABB: ", subAABB);
//console.log(triangle.intersectAABB(subAABB));
//renderer.registerBox(subAABB.centre, subAABB.size);
}
}
module.exports.VoxelManager = VoxelManager;