From 0f543d809de60e8a948a47675c81f23815cffd61 Mon Sep 17 00:00:00 2001 From: Lucas Dower Date: Sat, 21 Oct 2023 12:43:53 +0100 Subject: [PATCH] Optimised `OtS_VoxelMesh_Converter` --- Core/src/ots_voxel_mesh_converter.ts | 177 ++++++++++----------------- 1 file changed, 65 insertions(+), 112 deletions(-) diff --git a/Core/src/ots_voxel_mesh_converter.ts b/Core/src/ots_voxel_mesh_converter.ts index f7dd9b7..1f7f77f 100644 --- a/Core/src/ots_voxel_mesh_converter.ts +++ b/Core/src/ots_voxel_mesh_converter.ts @@ -7,8 +7,6 @@ import { Axes, Ray, rayIntersectTriangle } from './ray'; import { Bounds } from './bounds'; import { RGBA, RGBAColours, RGBAUtil } from './colour'; import { OtS_Mesh, OtS_Triangle } from './ots_mesh'; -import { ASSERT } from './util/error_util'; -import { OtS_Texture } from './ots_texture'; import { UV } from './util'; export type OtS_VoxelMesh_ConverterConfig = { @@ -20,10 +18,6 @@ export type OtS_VoxelMesh_ConverterConfig = { export class OtS_VoxelMesh_Converter { private _config: OtS_VoxelMesh_ConverterConfig; - private _rays: LinearAllocator; - - // Reused Bounds object in calculations to avoid GC - private _tmpBounds: Bounds; public constructor() { this._config = { @@ -32,13 +26,6 @@ export class OtS_VoxelMesh_Converter { multisampling: true, replaceMode: 'average', }; - - this._rays = new LinearAllocator(() => { - const ray: Ray = { origin: new Vector3(0, 0, 0), axis: Axes.x }; - return ray; - }); - - this._tmpBounds = Bounds.getEmptyBounds(); } /** @@ -64,61 +51,79 @@ export class OtS_VoxelMesh_Converter { normalisedMesh.translate(offset.x, offset.y, offset.z); for (const triangle of normalisedMesh.getTriangles()) { - this._voxeliseTri(mesh, voxelMesh, triangle); + this._handleTriangle(triangle, voxelMesh); } return voxelMesh; } - private _voxeliseTri(mesh: OtS_Mesh, voxelMesh: OtS_VoxelMesh, triangle: OtS_Triangle) { - this._rays.reset(); - this._generateRays(triangle.data.v0.position, triangle.data.v1.position, triangle.data.v2.position); + private _handleTriangle(triangle: OtS_Triangle, voxelMesh: OtS_VoxelMesh) { + const bounds = Triangle.CalcBounds(triangle.data.v0.position, triangle.data.v1.position, triangle.data.v2.position); + bounds.min.floor(); + bounds.max.ceil(); - const voxelPosition = new Vector3(0, 0, 0); - const size = this._rays.size(); - for (let i = 0; i < size; ++i) { - const ray = this._rays.get(i)!; + const ray: Ray = { axis: Axes.x, origin: new Vector3(0, 0, 0) }; - const intersection = rayIntersectTriangle(ray, triangle.data.v0.position, triangle.data.v1.position, triangle.data.v2.position); - if (intersection) { - switch (ray.axis) { - case Axes.x: - voxelPosition.x = Math.round(intersection.x); - voxelPosition.y = intersection.y; - voxelPosition.z = intersection.z; - break; - case Axes.y: - voxelPosition.x = intersection.x; - voxelPosition.y = Math.round(intersection.y); - voxelPosition.z = intersection.z; - break; - case Axes.z: - voxelPosition.x = intersection.x; - voxelPosition.y = intersection.y; - voxelPosition.z = Math.round(intersection.z); - break; - } - - let voxelColour: RGBA; - if (this._config.multisampling) { - const samples: RGBA[] = []; - for (let i = 0; i < 8; ++i) { - samples.push(this._getVoxelColour( - triangle, - Vector3.random().divScalar(2.0).add(voxelPosition), - )) - } - voxelColour = RGBAUtil.average(...samples); - } else { - voxelColour = this._getVoxelColour( - triangle, - voxelPosition, - ); - } - - voxelMesh.addVoxel(voxelPosition.x, voxelPosition.y, voxelPosition.z, voxelColour, this._config.replaceMode); + ray.origin.x = bounds.min.x - 1; + ray.axis = Axes.x; + for (let y = bounds.min.y; y <= bounds.max.y; ++y) { + ray.origin.y = y; + for (let z = bounds.min.z; z <= bounds.max.z; ++z) { + ray.origin.z = z; + this._handleRay(ray, triangle, voxelMesh); } - }; + } + + ray.origin.y = bounds.min.y - 1; + ray.axis = Axes.y; + for (let z = bounds.min.z; z <= bounds.max.z; ++z) { + ray.origin.z = z; + for (let x = bounds.min.x; x <= bounds.max.x; ++x) { + ray.origin.x = x; + this._handleRay(ray, triangle, voxelMesh); + } + } + + ray.origin.z = bounds.min.z - 1; + ray.axis = Axes.z; + for (let x = bounds.min.x; x <= bounds.max.x; ++x) { + ray.origin.x = x; + for (let y = bounds.min.y; y <= bounds.max.y; ++y) { + ray.origin.y = y; + this._handleRay(ray, triangle, voxelMesh); + } + } + } + + private _handleRay(ray: Ray, triangle: OtS_Triangle, voxelMesh: OtS_VoxelMesh) { + const intersection = rayIntersectTriangle(ray, triangle.data.v0.position, triangle.data.v1.position, triangle.data.v2.position); + + if (intersection) { + const voxelPosition = new Vector3( + intersection.x, + intersection.y, + intersection.z, + ).round(); + + let voxelColour: RGBA; + if (this._config.multisampling) { + const samples: RGBA[] = []; + for (let i = 0; i < 8; ++i) { + samples.push(this._getVoxelColour( + triangle, + Vector3.random().divScalar(2.0).add(voxelPosition), + )) + } + voxelColour = RGBAUtil.average(...samples); + } else { + voxelColour = this._getVoxelColour( + triangle, + voxelPosition, + ); + } + + voxelMesh.addVoxel(voxelPosition.x, voxelPosition.y, voxelPosition.z, voxelColour, this._config.replaceMode); + } } private _getVoxelColour(triangle: OtS_Triangle, location: Vector3): RGBA { @@ -156,58 +161,6 @@ export class OtS_VoxelMesh_Converter { return triangle.texture.sample(texcoord.u, texcoord.v); } - private _generateRays(v0: Vector3, v1: Vector3, v2: Vector3) { - this._tmpBounds.min.x = Math.floor(Math.min(v0.x, v1.x, v2.x)); - this._tmpBounds.min.y = Math.floor(Math.min(v0.y, v1.y, v2.y)); - this._tmpBounds.min.z = Math.floor(Math.min(v0.z, v1.z, v2.z)); - - this._tmpBounds.max.x = Math.floor(Math.max(v0.x, v1.x, v2.x)); - this._tmpBounds.max.y = Math.floor(Math.max(v0.y, v1.y, v2.y)); - this._tmpBounds.max.z = Math.floor(Math.max(v0.z, v1.z, v2.z)); - - //const rayList: Array = []; - this._traverseX(this._tmpBounds); - this._traverseY(this._tmpBounds); - this._traverseZ(this._tmpBounds); - //return rayList; - } - - private _traverseX(bounds: Bounds) { - for (let y = bounds.min.y; y <= bounds.max.y; ++y) { - for (let z = bounds.min.z; z <= bounds.max.z; ++z) { - const ray = this._rays.place(); - ray.origin.x = bounds.min.x - 1; - ray.origin.y = y; - ray.origin.z = z; - ray.axis = Axes.x; - } - } - } - - private _traverseY(bounds: Bounds) { - for (let x = bounds.min.x; x <= bounds.max.x; ++x) { - for (let z = bounds.min.z; z <= bounds.max.z; ++z) { - const ray = this._rays.place(); - ray.origin.x = x; - ray.origin.y = bounds.min.y - 1; - ray.origin.z = z; - ray.axis = Axes.y; - } - } - } - - private _traverseZ(bounds: Bounds) { - for (let x = bounds.min.x; x <= bounds.max.x; ++x) { - for (let y = bounds.min.y; y <= bounds.max.y; ++y) { - const ray = this._rays.place(); - ray.origin.x = x; - ray.origin.y = y; - ray.origin.z = bounds.min.z - 1; - ray.axis = Axes.z; - } - } - } - private _calcScaleOffset(mesh: OtS_Mesh) { const dimensions = mesh.calcBounds().getDimensions();