mirror of
https://github.com/LucasDower/ObjToSchematic.git
synced 2025-04-12 15:00:22 +08:00
Optimised voxelisation, ~2x improvement
This commit is contained in:
parent
6e81858e35
commit
7be3b89159
@ -2,10 +2,11 @@ import { OtS_ReplaceMode, OtS_VoxelMesh } from './ots_voxel_mesh';
|
||||
import { TAxis } from './util/type_util';
|
||||
import { Vector3 } from './vector';
|
||||
import { Triangle } from './triangle';
|
||||
import { rayIntersectTriangleFastX, rayIntersectTriangleFastY, rayIntersectTriangleFastZ } from './ray';
|
||||
import { OtS_Colours, RGBA, RGBAUtil } from './colour';
|
||||
import { OtS_Mesh, OtS_Triangle } from './ots_mesh';
|
||||
import { UV } from './util';
|
||||
import { rayIntersectTriangleFastX, rayIntersectTriangleFastY, rayIntersectTriangleFastZ, RayIntersect } from './ray';
|
||||
import { findFirstTrueIndex } from './util/array_util';
|
||||
|
||||
export type OtS_VoxelMesh_ConverterConfig = {
|
||||
constraintAxis: TAxis,
|
||||
@ -62,41 +63,35 @@ export class OtS_VoxelMesh_Converter {
|
||||
|
||||
const rayOrigin = new Vector3(0, 0, 0);
|
||||
|
||||
rayOrigin.x = bounds.min.x - 1;
|
||||
for (let y = bounds.min.y; y <= bounds.max.y; ++y) {
|
||||
rayOrigin.y = y;
|
||||
for (let z = bounds.min.z; z <= bounds.max.z; ++z) {
|
||||
rayOrigin.z = z;
|
||||
const intersection = rayIntersectTriangleFastX(rayOrigin, triangle);
|
||||
if (intersection) {
|
||||
this._handleRayHit(intersection, triangle, voxelMesh);
|
||||
const edge1 = Vector3.sub(triangle.data.v1.position, triangle.data.v0.position);
|
||||
const edge2 = Vector3.sub(triangle.data.v2.position, triangle.data.v0.position);
|
||||
|
||||
const rasterisePlane = (a0: 'x' | 'y' | 'z', a1: 'x' | 'y' | 'z', a2: 'x' | 'y' | 'z', intersect: RayIntersect) => {
|
||||
rayOrigin[a0] = bounds.min[a0] - 1;
|
||||
for (let y = bounds.min[a1]; y <= bounds.max[a1]; ++y) {
|
||||
rayOrigin[a1] = y; // 2
|
||||
let hasHit = false;
|
||||
|
||||
const start = findFirstTrueIndex(bounds.max[a2] - bounds.min[a2] + 1, (index: number) => {
|
||||
rayOrigin[a2] = bounds.min[a2] + index;
|
||||
return intersect(rayOrigin, triangle, edge1, edge2) !== undefined;
|
||||
});
|
||||
|
||||
for (let z = bounds.min[a2] + start; z <= bounds.max[a2]; ++z) {
|
||||
rayOrigin[a2] = z; // 3
|
||||
const intersection = intersect(rayOrigin, triangle, edge1, edge2);
|
||||
if (intersection) {
|
||||
this._handleRayHit(intersection, triangle, voxelMesh);
|
||||
} else if (hasHit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rayOrigin.y = bounds.min.y - 1;
|
||||
for (let z = bounds.min.z; z <= bounds.max.z; ++z) {
|
||||
rayOrigin.z = z;
|
||||
for (let x = bounds.min.x; x <= bounds.max.x; ++x) {
|
||||
rayOrigin.x = x;
|
||||
const intersection = rayIntersectTriangleFastY(rayOrigin, triangle);
|
||||
if (intersection) {
|
||||
this._handleRayHit(intersection, triangle, voxelMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rayOrigin.z = bounds.min.z - 1;
|
||||
for (let x = bounds.min.x; x <= bounds.max.x; ++x) {
|
||||
rayOrigin.x = x;
|
||||
for (let y = bounds.min.y; y <= bounds.max.y; ++y) {
|
||||
rayOrigin.y = y;
|
||||
const intersection = rayIntersectTriangleFastZ(rayOrigin, triangle);
|
||||
if (intersection) {
|
||||
this._handleRayHit(intersection, triangle, voxelMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
rasterisePlane('x', 'y', 'z', rayIntersectTriangleFastX);
|
||||
rasterisePlane('y', 'z', 'x', rayIntersectTriangleFastY);
|
||||
rasterisePlane('x', 'x', 'y', rayIntersectTriangleFastZ);
|
||||
}
|
||||
|
||||
private _handleRayHit(intersection: Vector3, triangle: OtS_Triangle, voxelMesh: OtS_VoxelMesh) {
|
||||
|
@ -28,12 +28,9 @@ export interface Ray {
|
||||
axis: Axes
|
||||
}
|
||||
|
||||
export type RayIntersect = (origin: Vector3, v0: Vector3, v1: Vector3, v2: Vector3) => (Vector3 | undefined);
|
||||
|
||||
export function rayIntersectTriangleFastX(origin: Vector3, triangle: OtS_Triangle): (Vector3 | undefined) {
|
||||
const edge1 = Vector3.sub(triangle.data.v1.position, triangle.data.v0.position);
|
||||
const edge2 = Vector3.sub(triangle.data.v2.position, triangle.data.v0.position);
|
||||
export type RayIntersect = (origin: Vector3, triangle: OtS_Triangle, edge1: Vector3, edge2: Vector3) => (Vector3 | undefined);
|
||||
|
||||
export function rayIntersectTriangleFastX(origin: Vector3, triangle: OtS_Triangle, edge1: Vector3, edge2: Vector3): (Vector3 | undefined) {
|
||||
const h = new Vector3(0, -edge2.z, edge2.y); // Vector3.cross(rayDirection, edge2);
|
||||
const a = Vector3.dot(edge1, h);
|
||||
|
||||
@ -66,10 +63,7 @@ export function rayIntersectTriangleFastX(origin: Vector3, triangle: OtS_Triangl
|
||||
}
|
||||
}
|
||||
|
||||
export function rayIntersectTriangleFastY(origin: Vector3, triangle: OtS_Triangle): (Vector3 | undefined) {
|
||||
const edge1 = Vector3.sub(triangle.data.v1.position, triangle.data.v0.position);
|
||||
const edge2 = Vector3.sub(triangle.data.v2.position, triangle.data.v0.position);
|
||||
|
||||
export function rayIntersectTriangleFastY(origin: Vector3, triangle: OtS_Triangle, edge1: Vector3, edge2: Vector3): (Vector3 | undefined) {
|
||||
const h = new Vector3(edge2.z, 0, -edge2.x); // Vector3.cross(rayDirection, edge2);
|
||||
const a = Vector3.dot(edge1, h);
|
||||
|
||||
@ -102,10 +96,7 @@ export function rayIntersectTriangleFastY(origin: Vector3, triangle: OtS_Triangl
|
||||
}
|
||||
}
|
||||
|
||||
export function rayIntersectTriangleFastZ(origin: Vector3, triangle: OtS_Triangle): (Vector3 | undefined) {
|
||||
const edge1 = Vector3.sub(triangle.data.v1.position, triangle.data.v0.position);
|
||||
const edge2 = Vector3.sub(triangle.data.v2.position, triangle.data.v0.position);
|
||||
|
||||
export function rayIntersectTriangleFastZ(origin: Vector3, triangle: OtS_Triangle, edge1: Vector3, edge2: Vector3): (Vector3 | undefined) {
|
||||
const h = new Vector3(-edge2.y, edge2.x, 0); // Vector3.cross(rayDirection, edge2);
|
||||
const a = Vector3.dot(edge1, h);
|
||||
|
||||
|
18
Core/src/util/array_util.ts
Normal file
18
Core/src/util/array_util.ts
Normal file
@ -0,0 +1,18 @@
|
||||
export function findFirstTrueIndex(length: number, valueAt: (index: number) => boolean) {
|
||||
let low = 0;
|
||||
let high = length - 1;
|
||||
let result = -1;
|
||||
|
||||
while (low <= high) {
|
||||
const mid = Math.floor((low + high) / 2);
|
||||
|
||||
if (valueAt(mid) === true) {
|
||||
result = mid;
|
||||
high = mid - 1;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
import { Axes, Ray, rayIntersectTriangle } from '../src/ray';
|
||||
import { Triangle } from '../src/triangle';
|
||||
import { ASSERT } from '../src/util/error_util';
|
||||
import { Vector3 } from '../src/vector';
|
||||
|
||||
test('rayIntersectTriangle x-axis #1', () => {
|
||||
const ray: Ray = {
|
||||
origin: new Vector3(-1, 0, 0),
|
||||
axis: Axes.x,
|
||||
};
|
||||
|
||||
const v0 = new Vector3(5, -1, -1);
|
||||
const v1 = new Vector3(5, 0, 1);
|
||||
const v2 = new Vector3(5, 1, -1);
|
||||
|
||||
const intersects = rayIntersectTriangle(ray, v0, v1, v2);
|
||||
expect(intersects).toBeDefined();
|
||||
ASSERT(intersects);
|
||||
expect(intersects.equals(new Vector3(5, 0, 0))).toEqual(true);
|
||||
});
|
||||
|
||||
test('rayIntersectTriangle x-axis #2', () => {
|
||||
const ray: Ray = {
|
||||
origin: new Vector3(1, 0, 0),
|
||||
axis: Axes.x,
|
||||
};
|
||||
|
||||
const v0 = new Vector3(0, -1, -1);
|
||||
const v1 = new Vector3(0, 0, 1);
|
||||
const v2 = new Vector3(0, 1, -1);
|
||||
|
||||
const intersects = rayIntersectTriangle(ray, v0, v1, v2);
|
||||
expect(intersects).toBeUndefined();
|
||||
});
|
||||
|
||||
test('rayIntersectTriangle y-axis #1', () => {
|
||||
const ray: Ray = {
|
||||
origin: new Vector3(0, -1, 0),
|
||||
axis: Axes.y,
|
||||
};
|
||||
|
||||
const v0 = new Vector3(-1, 6, -1);
|
||||
const v1 = new Vector3(0, 6, 1);
|
||||
const v2 = new Vector3(1, 6, -1);
|
||||
|
||||
const intersects = rayIntersectTriangle(ray, v0, v1, v2);
|
||||
expect(intersects).toBeDefined();
|
||||
ASSERT(intersects);
|
||||
expect(intersects.equals(new Vector3(0, 6, 0))).toEqual(true);
|
||||
});
|
||||
|
||||
test('rayIntersectTriangle y-axis #2', () => {
|
||||
const ray: Ray = {
|
||||
origin: new Vector3(0, 1, 0),
|
||||
axis: Axes.y,
|
||||
};
|
||||
|
||||
const v0 = new Vector3(-1, 0, -1);
|
||||
const v1 = new Vector3(0, 0, 1);
|
||||
const v2 = new Vector3(1, 0, -1);
|
||||
|
||||
const intersects = rayIntersectTriangle(ray, v0, v1, v2);
|
||||
expect(intersects).toBeUndefined();
|
||||
});
|
||||
|
||||
test('rayIntersectTriangle z-axis #1', () => {
|
||||
const ray: Ray = {
|
||||
origin: new Vector3(0, 0, -1),
|
||||
axis: Axes.z,
|
||||
};
|
||||
|
||||
const v0 = new Vector3(-1, -1, 7);
|
||||
const v1 = new Vector3(0, 1, 7);
|
||||
const v2 = new Vector3(1, -1, 7);
|
||||
|
||||
const intersects = rayIntersectTriangle(ray, v0, v1, v2);
|
||||
expect(intersects).toBeDefined();
|
||||
ASSERT(intersects);
|
||||
expect(intersects.equals(new Vector3(0, 0, 7))).toEqual(true);
|
||||
});
|
||||
|
||||
test('rayIntersectTriangle z-axis #2', () => {
|
||||
const ray: Ray = {
|
||||
origin: new Vector3(0, 0, 1),
|
||||
axis: Axes.z,
|
||||
};
|
||||
|
||||
const v0 = new Vector3(-1, -1, 0);
|
||||
const v1 = new Vector3(0, 1, 0);
|
||||
const v2 = new Vector3(1, -1, 0);
|
||||
|
||||
const intersects = rayIntersectTriangle(ray, v0, v1, v2);
|
||||
expect(intersects).toBeUndefined();
|
||||
});
|
@ -197,7 +197,7 @@ export class AppContext {
|
||||
params: {
|
||||
constraintAxis: components.constraintAxis.getValue(),
|
||||
size: components.size.getValue(),
|
||||
useMultisampleColouring: components.multisampleColouring.getValue(),
|
||||
//useMultisampleColouring: components.multisampleColouring.getValue(),
|
||||
enableAmbientOcclusion: components.ambientOcclusion.getValue(),
|
||||
voxelOverlapRule: components.voxelOverlapRule.getValue(),
|
||||
},
|
||||
|
@ -68,7 +68,7 @@ export namespace VoxeliseParams {
|
||||
export type Input = {
|
||||
constraintAxis: TAxis,
|
||||
size: number,
|
||||
useMultisampleColouring: boolean,
|
||||
useMultisampleColouring?: number,
|
||||
enableAmbientOcclusion: boolean,
|
||||
voxelOverlapRule: OtS_ReplaceMode,
|
||||
}
|
||||
|
@ -96,6 +96,8 @@ import { OtS_Colours } from 'ots-core/src/colour';
|
||||
const voxelMesh = voxelMeshConverter.process(mesh);
|
||||
console.timeEnd('Voxel Mesh');
|
||||
|
||||
console.log('Voxel Count =', voxelMesh.getVoxelCount());
|
||||
|
||||
// 4. Construct a block mesh from the block
|
||||
console.time('Block Mesh');
|
||||
const blockMeshConverter = new OtS_BlockMesh_Converter();
|
||||
|
Loading…
x
Reference in New Issue
Block a user