Optimised voxelisation

This commit is contained in:
Lucas Dower 2023-10-22 17:57:44 +01:00
parent 70d4df2d2d
commit 6e81858e35
3 changed files with 131 additions and 53 deletions

View File

@ -2,7 +2,7 @@ import { OtS_ReplaceMode, OtS_VoxelMesh } from './ots_voxel_mesh';
import { TAxis } from './util/type_util';
import { Vector3 } from './vector';
import { Triangle } from './triangle';
import { Axes, Ray, rayIntersectTriangle } from './ray';
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';
@ -10,7 +10,7 @@ import { UV } from './util';
export type OtS_VoxelMesh_ConverterConfig = {
constraintAxis: TAxis,
size: number,
multisampling: boolean,
multisampling?: number,
replaceMode: OtS_ReplaceMode,
}
@ -21,7 +21,7 @@ export class OtS_VoxelMesh_Converter {
this._config = {
constraintAxis: 'y',
size: 80,
multisampling: true,
multisampling: 8,
replaceMode: 'average',
};
}
@ -60,68 +60,70 @@ export class OtS_VoxelMesh_Converter {
bounds.min.floor();
bounds.max.ceil();
const ray: Ray = { axis: Axes.x, origin: new Vector3(0, 0, 0) };
const rayOrigin = new Vector3(0, 0, 0);
ray.origin.x = bounds.min.x - 1;
ray.axis = Axes.x;
rayOrigin.x = bounds.min.x - 1;
for (let y = bounds.min.y; y <= bounds.max.y; ++y) {
ray.origin.y = y;
rayOrigin.y = y;
for (let z = bounds.min.z; z <= bounds.max.z; ++z) {
ray.origin.z = z;
this._handleRay(ray, triangle, voxelMesh);
rayOrigin.z = z;
const intersection = rayIntersectTriangleFastX(rayOrigin, triangle);
if (intersection) {
this._handleRayHit(intersection, triangle, voxelMesh);
}
}
}
ray.origin.y = bounds.min.y - 1;
ray.axis = Axes.y;
rayOrigin.y = bounds.min.y - 1;
for (let z = bounds.min.z; z <= bounds.max.z; ++z) {
ray.origin.z = z;
rayOrigin.z = z;
for (let x = bounds.min.x; x <= bounds.max.x; ++x) {
ray.origin.x = x;
this._handleRay(ray, triangle, voxelMesh);
rayOrigin.x = x;
const intersection = rayIntersectTriangleFastY(rayOrigin, triangle);
if (intersection) {
this._handleRayHit(intersection, triangle, voxelMesh);
}
}
}
ray.origin.z = bounds.min.z - 1;
ray.axis = Axes.z;
rayOrigin.z = bounds.min.z - 1;
for (let x = bounds.min.x; x <= bounds.max.x; ++x) {
ray.origin.x = x;
rayOrigin.x = x;
for (let y = bounds.min.y; y <= bounds.max.y; ++y) {
ray.origin.y = y;
this._handleRay(ray, triangle, voxelMesh);
rayOrigin.y = y;
const intersection = rayIntersectTriangleFastZ(rayOrigin, triangle);
if (intersection) {
this._handleRayHit(intersection, 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();
private _handleRayHit(intersection: Vector3, triangle: OtS_Triangle, voxelMesh: OtS_VoxelMesh) {
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(
let voxelColour: RGBA;
if (this._config.multisampling !== undefined) {
const samples: RGBA[] = [];
for (let i = 0; i < this._config.multisampling; ++i) {
samples.push(this._getVoxelColour(
triangle,
voxelPosition,
);
Vector3.random().divScalar(2.0).add(voxelPosition),
))
}
voxelMesh.addVoxel(voxelPosition.x, voxelPosition.y, voxelPosition.z, voxelColour, this._config.replaceMode);
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 {

View File

@ -1,3 +1,4 @@
import { OtS_Triangle } from './ots_mesh';
import { ASSERT } from './util/error_util';
import { Vector3 } from './vector';
@ -27,12 +28,13 @@ export interface Ray {
axis: Axes
}
export function rayIntersectTriangle(ray: Ray, v0: Vector3, v1: Vector3, v2: Vector3): (Vector3 | undefined) {
const edge1 = Vector3.sub(v1, v0);
const edge2 = Vector3.sub(v2, v0);
export type RayIntersect = (origin: Vector3, v0: Vector3, v1: Vector3, v2: Vector3) => (Vector3 | undefined);
const rayDirection = axesToDirection(ray.axis);
const h = Vector3.cross(rayDirection, edge2);
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);
const h = new Vector3(0, -edge2.z, edge2.y); // Vector3.cross(rayDirection, edge2);
const a = Vector3.dot(edge1, h);
if (a > -EPSILON && a < EPSILON) {
@ -40,7 +42,7 @@ export function rayIntersectTriangle(ray: Ray, v0: Vector3, v1: Vector3, v2: Vec
}
const f = 1.0 / a;
const s = Vector3.sub(ray.origin, v0);
const s = Vector3.sub(origin, triangle.data.v0.position);
const u = f * Vector3.dot(s, h);
if (u < 0.0 || u > 1.0) {
@ -48,7 +50,7 @@ export function rayIntersectTriangle(ray: Ray, v0: Vector3, v1: Vector3, v2: Vec
}
const q = Vector3.cross(s, edge1);
const v = f * Vector3.dot(rayDirection, q);
const v = f * q.x; // f * Vector3.dot(rayDirection, q);
if (v < 0.0 || u + v > 1.0) {
return;
@ -57,6 +59,81 @@ export function rayIntersectTriangle(ray: Ray, v0: Vector3, v1: Vector3, v2: Vec
const t = f * Vector3.dot(edge2, q);
if (t > EPSILON) {
return Vector3.add(ray.origin, Vector3.mulScalar(rayDirection, t));
const result = Vector3.copy(origin);
result.x += t;
return result;
//return Vector3.add(origin, Vector3.mulScalar(rayDirection, t));
}
}
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);
const h = new Vector3(edge2.z, 0, -edge2.x); // Vector3.cross(rayDirection, edge2);
const a = Vector3.dot(edge1, h);
if (a > -EPSILON && a < EPSILON) {
return; // Ray is parallel to triangle
}
const f = 1.0 / a;
const s = Vector3.sub(origin, triangle.data.v0.position);
const u = f * Vector3.dot(s, h);
if (u < 0.0 || u > 1.0) {
return;
}
const q = Vector3.cross(s, edge1);
const v = f * q.y; // f * Vector3.dot(rayDirection, q);
if (v < 0.0 || u + v > 1.0) {
return;
}
const t = f * Vector3.dot(edge2, q);
if (t > EPSILON) {
const result = Vector3.copy(origin);
result.y += t;
return result;
//return Vector3.add(origin, Vector3.mulScalar(rayDirection, t));
}
}
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);
const h = new Vector3(-edge2.y, edge2.x, 0); // Vector3.cross(rayDirection, edge2);
const a = Vector3.dot(edge1, h);
if (a > -EPSILON && a < EPSILON) {
return; // Ray is parallel to triangle
}
const f = 1.0 / a;
const s = Vector3.sub(origin, triangle.data.v0.position);
const u = f * Vector3.dot(s, h);
if (u < 0.0 || u > 1.0) {
return;
}
const q = Vector3.cross(s, edge1);
const v = f * q.z; // f * Vector3.dot(rayDirection, q);
if (v < 0.0 || u + v > 1.0) {
return;
}
const t = f * Vector3.dot(edge2, q);
if (t > EPSILON) {
const result = Vector3.copy(origin);
result.z += t;
return result;
//return Vector3.add(origin, Vector3.mulScalar(rayDirection, t));
}
}

View File

@ -90,7 +90,6 @@ import { OtS_Colours } from 'ots-core/src/colour';
voxelMeshConverter.setConfig({
constraintAxis: 'y',
size: 380,
multisampling: false,
replaceMode: 'keep',
});