Skip to content

Commit

Permalink
Optimised voxelisation, ~2x improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasDower committed Oct 24, 2023
1 parent 6e81858 commit 7be3b89
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 141 deletions.
59 changes: 27 additions & 32 deletions Core/src/ots_voxel_mesh_converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down
17 changes: 4 additions & 13 deletions Core/src/ray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down
18 changes: 18 additions & 0 deletions Core/src/util/array_util.ts
Original file line number Diff line number Diff line change
@@ -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;
}
94 changes: 0 additions & 94 deletions Core/tests/ray.test.ts

This file was deleted.

2 changes: 1 addition & 1 deletion Editor/src/app_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
},
Expand Down
2 changes: 1 addition & 1 deletion Editor/src/worker/worker_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export namespace VoxeliseParams {
export type Input = {
constraintAxis: TAxis,
size: number,
useMultisampleColouring: boolean,
useMultisampleColouring?: number,
enableAmbientOcclusion: boolean,
voxelOverlapRule: OtS_ReplaceMode,
}
Expand Down
2 changes: 2 additions & 0 deletions Sandbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit 7be3b89

Please sign in to comment.