forked from mirror/ObjToSchematic
Optimised voxelisation
This commit is contained in:
parent
70d4df2d2d
commit
6e81858e35
@ -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 {
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -90,7 +90,6 @@ import { OtS_Colours } from 'ots-core/src/colour';
|
||||
voxelMeshConverter.setConfig({
|
||||
constraintAxis: 'y',
|
||||
size: 380,
|
||||
multisampling: false,
|
||||
replaceMode: 'keep',
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user