forked from mirror/ObjToSchematic
Added per-axis constraint options
This commit is contained in:
parent
05a756a3b7
commit
e36535f2a0
@ -244,8 +244,9 @@ export class AppContext {
|
||||
const payload: TToWorkerMessage = {
|
||||
action: 'Voxelise',
|
||||
params: {
|
||||
constraintAxis: uiElements.constraintAxis.getCachedValue(),
|
||||
voxeliser: uiElements.voxeliser.getCachedValue(),
|
||||
desiredHeight: uiElements.desiredHeight.getCachedValue(),
|
||||
size: uiElements.size.getCachedValue(),
|
||||
useMultisampleColouring: uiElements.multisampleColouring.getCachedValue() === 'on',
|
||||
textureFiltering: uiElements.textureFiltering.getCachedValue() === 'linear' ? TextureFiltering.Linear : TextureFiltering.Nearest,
|
||||
enableAmbientOcclusion: uiElements.ambientOcclusion.getCachedValue() === 'on',
|
||||
@ -273,7 +274,7 @@ export class AppContext {
|
||||
action: 'RenderNextVoxelMeshChunk',
|
||||
params: {
|
||||
enableAmbientOcclusion: uiElements.ambientOcclusion.getCachedValue() === 'on',
|
||||
desiredHeight: uiElements.desiredHeight.getCachedValue(),
|
||||
desiredHeight: uiElements.size.getCachedValue(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,7 @@ import { EAction } from '../util';
|
||||
import { ASSERT } from '../util/error_util';
|
||||
import { LOG } from '../util/log_util';
|
||||
import { AppPaths } from '../util/path_util';
|
||||
import { TAxis } from '../util/type_util';
|
||||
import { TVoxelOverlapRule } from '../voxel_mesh';
|
||||
import { TVoxelisers } from '../voxelisers/voxelisers';
|
||||
import { BaseUIElement } from './elements/base';
|
||||
@ -52,7 +53,21 @@ export class UI {
|
||||
'voxelise': {
|
||||
label: 'Voxelise',
|
||||
elements: {
|
||||
'desiredHeight': new SliderElement('Desired height', 3, 380, 0, 80, 1),
|
||||
'constraintAxis': new ComboBoxElement<TAxis>('Constraint axis', [
|
||||
{
|
||||
id: 'y',
|
||||
displayText: 'Y (height) (green)',
|
||||
},
|
||||
{
|
||||
id: 'x',
|
||||
displayText: 'X (width) (red)',
|
||||
},
|
||||
{
|
||||
id: 'z',
|
||||
displayText: 'Z (depth) (blue)',
|
||||
},
|
||||
]),
|
||||
'size': new SliderElement('Size', 3, 380, 0, 80, 1),
|
||||
'voxeliser': new ComboBoxElement<TVoxelisers>('Algorithm', [
|
||||
{
|
||||
id: 'bvh-ray',
|
||||
@ -114,7 +129,7 @@ export class UI {
|
||||
},
|
||||
]),
|
||||
},
|
||||
elementsOrder: ['desiredHeight', 'voxeliser', 'ambientOcclusion', 'multisampleColouring', 'textureFiltering', 'voxelOverlapRule'],
|
||||
elementsOrder: ['constraintAxis', 'size', 'voxeliser', 'ambientOcclusion', 'multisampleColouring', 'textureFiltering', 'voxelOverlapRule'],
|
||||
submitButton: new ButtonElement('Voxelise mesh', () => {
|
||||
this._appContext.do(EAction.Voxelise);
|
||||
}),
|
||||
|
1
src/util/type_util.ts
Normal file
1
src/util/type_util.ts
Normal file
@ -0,0 +1 @@
|
||||
export type TAxis = 'x' | 'y' | 'z';
|
@ -17,8 +17,24 @@ const bvhtree = require('bvh-tree');
|
||||
export class BVHRayVoxeliserPlusThickness extends IVoxeliser {
|
||||
protected override _voxelise(mesh: Mesh, voxeliseParams: VoxeliseParams.Input): VoxelMesh {
|
||||
const voxelMesh = new VoxelMesh(voxeliseParams);
|
||||
const scale = (voxeliseParams.desiredHeight - 1) / Mesh.desiredHeight;
|
||||
const offset = (voxeliseParams.desiredHeight % 2 === 0) ? new Vector3(0.0, 0.5, 0.0) : new Vector3(0.0, 0.0, 0.0);
|
||||
|
||||
const meshDimensions = mesh.getBounds().getDimensions();
|
||||
let scale: number;
|
||||
let offset = new Vector3(0.0, 0.0, 0.0);
|
||||
switch (voxeliseParams.constraintAxis) {
|
||||
case 'x':
|
||||
scale = (voxeliseParams.size - 1) / meshDimensions.x;
|
||||
offset = (voxeliseParams.size % 2 === 0) ? new Vector3(0.5, 0.0, 0.0) : new Vector3(0.0, 0.0, 0.0);
|
||||
break;
|
||||
case 'y':
|
||||
scale = (voxeliseParams.size - 1) / meshDimensions.y;
|
||||
offset = (voxeliseParams.size % 2 === 0) ? new Vector3(0.0, 0.5, 0.0) : new Vector3(0.0, 0.0, 0.0);
|
||||
break;
|
||||
case 'z':
|
||||
scale = (voxeliseParams.size - 1) / meshDimensions.z;
|
||||
offset = (voxeliseParams.size % 2 === 0) ? new Vector3(0.0, 0.0, 0.5) : new Vector3(0.0, 0.0, 0.0);
|
||||
break;
|
||||
}
|
||||
|
||||
mesh.setTransform((vertex: Vector3) => {
|
||||
return vertex.copy().mulScalar(scale).add(offset);
|
||||
@ -87,7 +103,7 @@ export class BVHRayVoxeliserPlusThickness extends IVoxeliser {
|
||||
for (const intersection of intersections) {
|
||||
const point = intersection.intersectionPoint;
|
||||
const position = new Vector3(point.x, point.y, point.z);
|
||||
|
||||
|
||||
// Shrinking towards the perpendicular vector
|
||||
const triangle = mesh.getUVTriangle(intersection.triangleIndex);
|
||||
const v0 = Vector3.sub(triangle.v1, triangle.v0);
|
||||
|
@ -2,7 +2,7 @@ import { Mesh } from '../mesh';
|
||||
import { ProgressManager } from '../progress';
|
||||
import { Axes, axesToDirection, Ray } from '../ray';
|
||||
import { ASSERT } from '../util/error_util';
|
||||
import { LOG } from '../util/log_util';
|
||||
import { LOG, LOGF } from '../util/log_util';
|
||||
import { Vector3 } from '../vector';
|
||||
import { VoxelMesh } from '../voxel_mesh';
|
||||
import { VoxeliseParams } from '../worker_types';
|
||||
@ -17,8 +17,24 @@ const bvhtree = require('bvh-tree');
|
||||
export class BVHRayVoxeliser extends IVoxeliser {
|
||||
protected override _voxelise(mesh: Mesh, voxeliseParams: VoxeliseParams.Input): VoxelMesh {
|
||||
const voxelMesh = new VoxelMesh(voxeliseParams);
|
||||
const scale = (voxeliseParams.desiredHeight - 1) / Mesh.desiredHeight;
|
||||
const offset = (voxeliseParams.desiredHeight % 2 === 0) ? new Vector3(0.0, 0.5, 0.0) : new Vector3(0.0, 0.0, 0.0);
|
||||
|
||||
const meshDimensions = mesh.getBounds().getDimensions();
|
||||
let scale: number;
|
||||
let offset = new Vector3(0.0, 0.0, 0.0);
|
||||
switch (voxeliseParams.constraintAxis) {
|
||||
case 'x':
|
||||
scale = (voxeliseParams.size - 1) / meshDimensions.x;
|
||||
offset = (voxeliseParams.size % 2 === 0) ? new Vector3(0.5, 0.0, 0.0) : new Vector3(0.0, 0.0, 0.0);
|
||||
break;
|
||||
case 'y':
|
||||
scale = (voxeliseParams.size - 1) / meshDimensions.y;
|
||||
offset = (voxeliseParams.size % 2 === 0) ? new Vector3(0.0, 0.5, 0.0) : new Vector3(0.0, 0.0, 0.0);
|
||||
break;
|
||||
case 'z':
|
||||
scale = (voxeliseParams.size - 1) / meshDimensions.z;
|
||||
offset = (voxeliseParams.size % 2 === 0) ? new Vector3(0.0, 0.0, 0.5) : new Vector3(0.0, 0.0, 0.0);
|
||||
break;
|
||||
}
|
||||
|
||||
mesh.setTransform((vertex: Vector3) => {
|
||||
return vertex.copy().mulScalar(scale).add(offset);
|
||||
|
@ -27,17 +27,30 @@ export class NormalCorrectedRayVoxeliser extends IVoxeliser {
|
||||
this._voxelMesh = new VoxelMesh(voxeliseParams);
|
||||
this._voxeliseParams = voxeliseParams;
|
||||
|
||||
const scale = (voxeliseParams.desiredHeight) / Mesh.desiredHeight;
|
||||
const meshDimensions = mesh.getBounds().getDimensions();
|
||||
let scale: number;
|
||||
switch (voxeliseParams.constraintAxis) {
|
||||
case 'x':
|
||||
scale = voxeliseParams.size / meshDimensions.x;
|
||||
break;
|
||||
case 'y':
|
||||
scale = voxeliseParams.size / meshDimensions.y;
|
||||
break;
|
||||
case 'z':
|
||||
scale = voxeliseParams.size / meshDimensions.z;
|
||||
break;
|
||||
}
|
||||
|
||||
mesh.setTransform((vertex: Vector3) => {
|
||||
return vertex.copy().mulScalar(scale);
|
||||
});
|
||||
|
||||
const bounds = mesh.getBounds();
|
||||
this._size = Vector3.sub(bounds.max, bounds.min);
|
||||
this._size = Vector3.sub(bounds.max.copy().ceil(), bounds.min.copy().floor());
|
||||
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,
|
||||
this._size.x % 2 === 0 ? 0.5 : 0.0,
|
||||
this._size.y % 2 === 0 ? 0.5 : 0.0,
|
||||
this._size.z % 2 === 0 ? 0.5 : 0.0,
|
||||
);
|
||||
|
||||
const numTris = mesh.getTriangleCount();
|
||||
|
@ -25,8 +25,23 @@ export class RayVoxeliser extends IVoxeliser {
|
||||
this._voxelMesh = new VoxelMesh(voxeliseParams);
|
||||
this._voxeliseParams = voxeliseParams;
|
||||
|
||||
const scale = (voxeliseParams.desiredHeight - 1) / Mesh.desiredHeight;
|
||||
const offset = (voxeliseParams.desiredHeight % 2 === 0) ? new Vector3(0.0, 0.5, 0.0) : new Vector3(0.0, 0.0, 0.0);
|
||||
const meshDimensions = mesh.getBounds().getDimensions();
|
||||
let scale: number;
|
||||
let offset = new Vector3(0.0, 0.0, 0.0);
|
||||
switch (voxeliseParams.constraintAxis) {
|
||||
case 'x':
|
||||
scale = (voxeliseParams.size - 1) / meshDimensions.x;
|
||||
offset = (voxeliseParams.size % 2 === 0) ? new Vector3(0.5, 0.0, 0.0) : new Vector3(0.0, 0.0, 0.0);
|
||||
break;
|
||||
case 'y':
|
||||
scale = (voxeliseParams.size - 1) / meshDimensions.y;
|
||||
offset = (voxeliseParams.size % 2 === 0) ? new Vector3(0.0, 0.5, 0.0) : new Vector3(0.0, 0.0, 0.0);
|
||||
break;
|
||||
case 'z':
|
||||
scale = (voxeliseParams.size - 1) / meshDimensions.z;
|
||||
offset = (voxeliseParams.size % 2 === 0) ? new Vector3(0.0, 0.0, 0.5) : new Vector3(0.0, 0.0, 0.0);
|
||||
break;
|
||||
}
|
||||
|
||||
mesh.setTransform((vertex: Vector3) => {
|
||||
return vertex.copy().mulScalar(scale).add(offset);
|
||||
|
@ -7,6 +7,7 @@ import { StatusMessage } from './status';
|
||||
import { TextureFiltering } from './texture';
|
||||
import { ColourSpace } from './util';
|
||||
import { AppError } from './util/error_util';
|
||||
import { TAxis } from './util/type_util';
|
||||
import { Vector3 } from './vector';
|
||||
import { TVoxelOverlapRule } from './voxel_mesh';
|
||||
import { TVoxelisers } from './voxelisers/voxelisers';
|
||||
@ -42,8 +43,9 @@ export namespace RenderMeshParams {
|
||||
|
||||
export namespace VoxeliseParams {
|
||||
export type Input = {
|
||||
constraintAxis: TAxis,
|
||||
voxeliser: TVoxelisers,
|
||||
desiredHeight: number,
|
||||
size: number,
|
||||
useMultisampleColouring: boolean,
|
||||
textureFiltering: TextureFiltering,
|
||||
enableAmbientOcclusion: boolean,
|
||||
|
@ -98,6 +98,7 @@ canvas {
|
||||
align-items: center;
|
||||
/*border: 1px solid yellow;*/
|
||||
height: var(--property-height);
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
.item-body-sunken {
|
||||
|
@ -18,7 +18,8 @@ test('Voxelise solid 2x2 cube', () => {
|
||||
|
||||
const voxeliser = new NormalCorrectedRayVoxeliser();
|
||||
const voxelMesh = voxeliser.voxelise(mesh, {
|
||||
desiredHeight: 2,
|
||||
constraintAxis: 'y',
|
||||
size: 2,
|
||||
useMultisampleColouring: false,
|
||||
textureFiltering: TextureFiltering.Nearest,
|
||||
enableAmbientOcclusion: false,
|
||||
|
@ -10,7 +10,8 @@ const baseConfig: THeadlessConfig = {
|
||||
},
|
||||
voxelise: {
|
||||
voxeliser: 'bvh-ray',
|
||||
desiredHeight: 80,
|
||||
constraintAxis: 'y',
|
||||
size: 80,
|
||||
useMultisampleColouring: false,
|
||||
textureFiltering: TextureFiltering.Linear,
|
||||
voxelOverlapRule: 'average',
|
||||
|
@ -10,7 +10,8 @@ const baseConfig: THeadlessConfig = {
|
||||
},
|
||||
voxelise: {
|
||||
voxeliser: 'bvh-ray',
|
||||
desiredHeight: 80,
|
||||
constraintAxis: 'y',
|
||||
size: 80,
|
||||
useMultisampleColouring: false,
|
||||
textureFiltering: TextureFiltering.Linear,
|
||||
voxelOverlapRule: 'average',
|
||||
|
@ -10,7 +10,8 @@ const baseConfig: THeadlessConfig = {
|
||||
},
|
||||
voxelise: {
|
||||
voxeliser: 'bvh-ray',
|
||||
desiredHeight: 80,
|
||||
constraintAxis: 'y',
|
||||
size: 80,
|
||||
useMultisampleColouring: false,
|
||||
textureFiltering: TextureFiltering.Linear,
|
||||
voxelOverlapRule: 'average',
|
||||
|
@ -10,7 +10,8 @@ const baseConfig: THeadlessConfig = {
|
||||
},
|
||||
voxelise: {
|
||||
voxeliser: 'bvh-ray',
|
||||
desiredHeight: 80,
|
||||
constraintAxis: 'y',
|
||||
size: 80,
|
||||
useMultisampleColouring: false,
|
||||
textureFiltering: TextureFiltering.Linear,
|
||||
voxelOverlapRule: 'average',
|
||||
|
@ -7,8 +7,9 @@ export const headlessConfig: THeadlessConfig = {
|
||||
filepath: '/Users/lucasdower/ObjToSchematic/res/samples/skull.obj', // Must be an absolute path
|
||||
},
|
||||
voxelise: {
|
||||
constraintAxis: 'y',
|
||||
voxeliser: 'bvh-ray',
|
||||
desiredHeight: 80,
|
||||
size: 80,
|
||||
useMultisampleColouring: false,
|
||||
textureFiltering: TextureFiltering.Linear,
|
||||
voxelOverlapRule: 'average',
|
||||
|
@ -51,7 +51,7 @@ export function runHeadless(headlessConfig: THeadlessConfig) {
|
||||
{
|
||||
TIME_START('[TIMER] Exporter');
|
||||
LOG_MAJOR('\nExporting...');
|
||||
|
||||
|
||||
/**
|
||||
* The OBJExporter is unique in that it uses the actual render buffer used by WebGL
|
||||
* to create its data, in headless mode this render buffer is not created so we must
|
||||
@ -62,7 +62,7 @@ export function runHeadless(headlessConfig: THeadlessConfig) {
|
||||
do {
|
||||
result = worker.renderChunkedVoxelMesh({
|
||||
enableAmbientOcclusion: headlessConfig.voxelise.enableAmbientOcclusion,
|
||||
desiredHeight: headlessConfig.voxelise.desiredHeight,
|
||||
desiredHeight: headlessConfig.voxelise.size,
|
||||
});
|
||||
} while (result.moreVoxelsToBuffer);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user