Added normal-corrected voxelisation, resolves #30

This commit is contained in:
Lucas Dower 2022-03-22 00:55:34 +00:00
parent cee9871bfa
commit 4151083ce3
3 changed files with 65 additions and 40 deletions

View File

@ -27,30 +27,30 @@ export interface Ray {
axis: Axes
}
export function generateRays(v0: Vector3, v1: Vector3, v2: Vector3): Array<Ray> {
export function generateRays(v0: Vector3, v1: Vector3, v2: Vector3, offset: Vector3): Array<Ray> {
const bounds: Bounds = new Bounds(
new Vector3(
Math.floor(Math.min(v0.x, v1.x, v2.x)),
Math.floor(Math.min(v0.y, v1.y, v2.y)),
Math.floor(Math.min(v0.z, v1.z, v2.z)),
Math.ceil(Math.min(v0.x, v1.x, v2.x)),
Math.ceil(Math.min(v0.y, v1.y, v2.y)),
Math.ceil(Math.min(v0.z, v1.z, v2.z)),
),
new Vector3(
Math.ceil(Math.max(v0.x, v1.x, v2.x)),
Math.ceil(Math.max(v0.y, v1.y, v2.y)),
Math.ceil(Math.max(v0.z, v1.z, v2.z)),
Math.floor(Math.max(v0.x, v1.x, v2.x)),
Math.floor(Math.max(v0.y, v1.y, v2.y)),
Math.floor(Math.max(v0.z, v1.z, v2.z)),
),
);
const rayList: Array<Ray> = [];
traverseX(rayList, bounds);
traverseY(rayList, bounds);
traverseZ(rayList, bounds);
traverseX(rayList, bounds, offset);
traverseY(rayList, bounds, offset);
traverseZ(rayList, bounds, offset);
return rayList;
}
function traverseX(rayList: Array<Ray>, bounds: Bounds) {
for (let y = bounds.min.y; y <= bounds.max.y; ++y) {
for (let z = bounds.min.z; z <= bounds.max.z; ++z) {
function traverseX(rayList: Array<Ray>, bounds: Bounds, offset: Vector3) {
for (let y = bounds.min.y - offset.y; y <= bounds.max.y + offset.y; ++y) {
for (let z = bounds.min.z - offset.z; z <= bounds.max.z + offset.z; ++z) {
rayList.push({
origin: new Vector3(bounds.min.x - 1, y, z),
axis: Axes.x,
@ -59,9 +59,9 @@ function traverseX(rayList: Array<Ray>, bounds: Bounds) {
}
}
function traverseY(rayList: Array<Ray>, bounds: Bounds) {
for (let x = bounds.min.x; x <= bounds.max.x; ++x) {
for (let z = bounds.min.z; z <= bounds.max.z; ++z) {
function traverseY(rayList: Array<Ray>, bounds: Bounds, offset: Vector3) {
for (let x = bounds.min.x - offset.x; x <= bounds.max.x + offset.x; ++x) {
for (let z = bounds.min.z - offset.z; z <= bounds.max.z + offset.z; ++z) {
rayList.push({
origin: new Vector3(x, bounds.min.y - 1, z),
axis: Axes.y,
@ -70,9 +70,9 @@ function traverseY(rayList: Array<Ray>, bounds: Bounds) {
}
}
function traverseZ(rayList: Array<Ray>, bounds: Bounds) {
for (let x = bounds.min.x; x <= bounds.max.x; ++x) {
for (let y = bounds.min.y; y <= bounds.max.y; ++y) {
function traverseZ(rayList: Array<Ray>, bounds: Bounds, offset: Vector3) {
for (let x = bounds.min.x - offset.x; x <= bounds.max.x + offset.x; ++x) {
for (let y = bounds.min.y - offset.y; y <= bounds.max.y + offset.y; ++y) {
rayList.push({
origin: new Vector3(x, y, bounds.min.z - 1),
axis: Axes.z,

View File

@ -82,10 +82,6 @@ export class RGB {
return new RGB(1.0, 1.0, 1.0);
}
public static get yellow(): RGB {
return new RGB(1.0, 1.0, 0.0);
}
public static get red(): RGB {
return new RGB(1.0, 0.0, 0.0);
}
@ -98,6 +94,18 @@ export class RGB {
return new RGB(0.0, 0.0, 1.0);
}
public static get yellow(): RGB {
return new RGB(1.0, 1.0, 0.0);
}
public static get cyan(): RGB {
return new RGB(0.0, 1.0, 1.0);
}
public static get magenta(): RGB {
return new RGB(1.0, 0.0, 1.0);
}
public static get black(): RGB {
return new RGB(0.0, 0.0, 0.0);
}

View File

@ -17,6 +17,7 @@ export class RayVoxeliser extends IVoxeliser {
private _voxelMesh?: VoxelMesh;
private _voxelMeshParams?: VoxelMeshParams;
private _scale!: number;
private _size!: Vector3;
private _offset!: Vector3;
public override voxelise(mesh: Mesh, voxelMeshParams: VoxelMeshParams): VoxelMesh {
@ -24,40 +25,49 @@ export class RayVoxeliser extends IVoxeliser {
this._voxelMesh = new VoxelMesh(mesh, voxelMeshParams);
this._voxelMeshParams = voxelMeshParams;
this._scale = (voxelMeshParams.desiredHeight - 1) / Mesh.desiredHeight;
this._offset = (voxelMeshParams.desiredHeight % 2 === 0) ? new Vector3(0.0, 0.5, 0.0) : new Vector3(0.0, 0.0, 0.0);
this._scale = (voxelMeshParams.desiredHeight) / Mesh.desiredHeight;
const useMesh = mesh.copy();
useMesh.scaleMesh(this._scale);
useMesh.translateMesh(this._offset);
const bounds = useMesh.getBounds();
this._size = Vector3.sub(bounds.max, bounds.min);
this._offset =new Vector3(
this._size.x % 2 < 0.001 ? 0.5 : 0.0,
this._size.y % 2 < 0.001 ? 0.5 : 0.0,
this._size.z % 2 < 0.001 ? 0.5 : 0.0,
);
for (let triIndex = 0; triIndex < useMesh.getTriangleCount(); ++triIndex) {
const uvTriangle = useMesh.getUVTriangle(triIndex);
const normals = useMesh.getNormals(triIndex);
const material = useMesh.getMaterialByTriangle(triIndex);
this._voxeliseTri(uvTriangle, material);
this._voxeliseTri(uvTriangle, material, normals);
}
return this._voxelMesh;
}
private _voxeliseTri(triangle: UVTriangle, materialName: string) {
const rayList = generateRays(triangle.v0, triangle.v1, triangle.v2);
private _voxeliseTri(triangle: UVTriangle, materialName: string, normals: { v0: Vector3, v1: Vector3, v2: Vector3}) {
const rayList = generateRays(triangle.v0, triangle.v1, triangle.v2,
this._offset,
);
rayList.forEach((ray) => {
const rayOriginWorld = Vector3.divScalar(ray.origin, this._scale).sub(this._offset);
this._voxelMesh!.debugBuffer.add(DebugGeometryTemplates.cross(
rayOriginWorld,
0.1,
ray.axis === Axes.x ? RGB.red : (ray.axis === Axes.y ? RGB.green : RGB.blue),
));
const intersection = rayIntersectTriangle(ray, triangle.v0, triangle.v1, triangle.v2);
if (intersection) {
this._voxelMesh!.debugBuffer.add(DebugGeometryTemplates.arrow(
rayOriginWorld,
Vector3.divScalar(intersection, this._scale).sub(this._offset),
ray.axis === Axes.x ? RGB.red : (ray.axis === Axes.y ? RGB.green : RGB.blue),
const intersectionWorld = Vector3.divScalar(intersection, this._scale);
this._voxelMesh!.debugBuffer.add(DebugGeometryTemplates.cross(
intersectionWorld,
0.1,
RGB.magenta,
));
// Move transition away from normal
const norm = normals.v0.normalise();
intersection.sub(Vector3.mulScalar(norm, 0.5));
// Correct size parity
intersection.add(this._offset);
let voxelPosition: Vector3;
switch (ray.axis) {
case Axes.x:
@ -70,6 +80,13 @@ export class RayVoxeliser extends IVoxeliser {
voxelPosition = new Vector3(intersection.x, intersection.y, Math.round(intersection.z));
break;
}
voxelPosition.round();
this._voxelMesh!.debugBuffer.add(DebugGeometryTemplates.arrow(
intersectionWorld,
Vector3.divScalar(voxelPosition, this._scale),
RGB.magenta,
));
let voxelColour: RGB;
if (this._voxelMeshParams!.useMultisampleColouring) {