mirror of
https://github.com/LucasDower/ObjToSchematic.git
synced 2025-03-07 14:06:41 +08:00
Added quadtree voxelisation
This commit is contained in:
parent
6758bae6a4
commit
d1adcd8909
31
src/aabb.js
Normal file
31
src/aabb.js
Normal 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;
|
@ -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();
|
||||
|
||||
|
12
src/math.js
12
src/math.js
@ -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;
|
@ -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
88
src/triangle.js
Normal 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;
|
@ -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
85
src/voxel_manager.js
Normal 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;
|
Loading…
Reference in New Issue
Block a user