diff --git a/src/test-node.ts b/src/test-node.ts index f4c7a04..fcadedb 100644 --- a/src/test-node.ts +++ b/src/test-node.ts @@ -2,12 +2,13 @@ import { resolve } from 'path'; import { ModelStore, MsonEvaluate } from '.'; import { fillStoreFromFilesystem, saveGeometry, saveModel } from './util/node'; import { ThreeBuilder } from './three'; -import { MeshLambertMaterial } from 'three'; +import { DoubleSide, MeshLambertMaterial } from 'three'; async function init() { const store = new ModelStore(); const evaluate = new MsonEvaluate(store); const mat = new MeshLambertMaterial(); + // mat.side = DoubleSide; const builder = new ThreeBuilder(mat); await fillStoreFromFilesystem(store, resolve(process.cwd(), 'inputs')); diff --git a/src/three/builder.ts b/src/three/builder.ts index 3e19c22..b11e783 100644 --- a/src/three/builder.ts +++ b/src/three/builder.ts @@ -27,10 +27,13 @@ import { Vec3, } from '../mson'; import { isArrayOfArrays } from '../util/array-of-array'; -import { UVMapper } from './uv'; +import { UVMapper } from './uv-mapper'; export class ThreeBuilder { - static normals: Record = { + /** + * This is used to rotate the plane to face the right direction. + */ + static planeFaceNormals: Record = { up: new Vector3(0, 1, 0), down: new Vector3(0, -1, 0), east: new Vector3(1, 0, 0), @@ -39,28 +42,26 @@ export class ThreeBuilder { north: new Vector3(0, 0, -1), }; - static pocConvert: Record< + /** + * This is used to correctly calculate the translation offset for the plane + * in each axis. + */ + static planeFaceOffsetConversions: Record< MsonFace, (pos: Vector3, size: Vector2) => Vector3 > = { - up: function (pos: Vector3, size: Vector2): Vector3 { - return new Vector3(pos.x + size.x / 2, pos.y, pos.z + size.y / 2); - }, - down: function (pos: Vector3, size: Vector2): Vector3 { - return new Vector3(pos.x + size.x / 2, pos.y, pos.z + size.y / 2); - }, - east: function (pos: Vector3, size: Vector2): Vector3 { - return new Vector3(pos.x, pos.y - size.y / 2, pos.z + size.x / 2); - }, - west: function (pos: Vector3, size: Vector2): Vector3 { - return new Vector3(pos.x, pos.y - size.y / 2, pos.z + size.x / 2); - }, - south: function (pos: Vector3, size: Vector2): Vector3 { - return new Vector3(pos.x + size.x / 2, pos.y - size.y / 2, pos.z); - }, - north: function (pos: Vector3, size: Vector2): Vector3 { - return new Vector3(pos.x + size.x / 2, pos.y - size.y / 2, pos.z); - }, + up: (pos: Vector3, size: Vector2): Vector3 => + new Vector3(pos.x + size.x / 2, pos.y, pos.z + size.y / 2), + down: (pos: Vector3, size: Vector2): Vector3 => + new Vector3(pos.x + size.x / 2, pos.y, pos.z + size.y / 2), + east: (pos: Vector3, size: Vector2): Vector3 => + new Vector3(pos.x, pos.y - size.y / 2, pos.z + size.x / 2), + west: (pos: Vector3, size: Vector2): Vector3 => + new Vector3(pos.x, pos.y - size.y / 2, pos.z + size.x / 2), + south: (pos: Vector3, size: Vector2): Vector3 => + new Vector3(pos.x + size.x / 2, pos.y - size.y / 2, pos.z), + north: (pos: Vector3, size: Vector2): Vector3 => + new Vector3(pos.x + size.x / 2, pos.y - size.y / 2, pos.z), }; constructor(private readonly material: Material) {} @@ -105,7 +106,7 @@ export class ThreeBuilder { // Compound objects if (!component.type || component.type === 'mson:compound') { - // mhm, go on ahead + // mhm, go on ahead, nothing to see here } if ( @@ -201,7 +202,9 @@ export class ThreeBuilder { else dilate.set(component.dilate, component.dilate, component.dilate); } - const offset = new Vector3().fromArray(component.from as Vec3); + const offset = new Vector3().fromArray( + (component.from as Vec3) || [0, 0, 0], + ); const halfSize = size.clone().divideScalar(2); offset.setY(offset.y * -1); @@ -222,7 +225,8 @@ export class ThreeBuilder { adjustedTranslate.z, ); - // FIXME: hack toJSON + // TODO: FIXME: this crap is to hack .toJSON() into including the entire geometry + // instead of just the properties used to initialize it. (geometry as any).type = 'BufferGeometry'; delete (geometry as any).parameters; @@ -284,7 +288,8 @@ export class ThreeBuilder { geometry = geometry.toNonIndexed() as CylinderGeometry; geometry.computeVertexNormals(); - // FIXME: hack toJSON + // TODO: FIXME: this crap is to hack .toJSON() into including the entire geometry + // instead of just the properties used to initialize it. (geometry as any).type = 'BufferGeometry'; delete (geometry as any).parameters; @@ -304,9 +309,12 @@ export class ThreeBuilder { mirror?: boolean | [boolean, boolean], ) { const planeGeom = new PlaneGeometry(size.x, size.y); - let axisNormal = ThreeBuilder.normals[face]; + let axisNormal = ThreeBuilder.planeFaceNormals[face]; pos.setY(pos.y * -1); - const adjustedTranslate = ThreeBuilder.pocConvert[face](pos, size); + const adjustedTranslate = ThreeBuilder.planeFaceOffsetConversions[face]( + pos, + size, + ); planeGeom.lookAt(axisNormal); planeGeom.translate( adjustedTranslate.x, @@ -314,14 +322,14 @@ export class ThreeBuilder { adjustedTranslate.z, ); - // FIXME: hack toJSON + // TODO: FIXME: this crap is to hack .toJSON() into including the entire geometry + // instead of just the properties used to initialize it. (planeGeom as any).type = 'BufferGeometry'; delete (planeGeom as any).parameters; UVMapper.mapPlanarUvs(face, size, planeGeom, texture, mirror); const mesh = new Mesh(planeGeom, this.material); - // mesh.position.copy(pos); mesh.name = face; parent.add(mesh); } diff --git a/src/three/uv.ts b/src/three/uv-mapper.ts similarity index 96% rename from src/three/uv.ts rename to src/three/uv-mapper.ts index 55f9b10..c0854a6 100644 --- a/src/three/uv.ts +++ b/src/three/uv-mapper.ts @@ -49,6 +49,7 @@ export class UVMapper { }; /** + * Convert coordinates relative to the texture to UVs. * @param sizeU Size of quad U * @param sizeV Size of quad V * @param txU Texture width @@ -104,6 +105,11 @@ export class UVMapper { ); } + /** + * Return instructions on which UV offsets to use when unwrapping a box. + * @param size Object size + * @returns Box unwrap instructions + */ static unwrapBox(size: Vector3) { const widths = UVMapper.boxFaceOrder.map( (item) => size[UVMapper.boxWidthSide[item]], @@ -112,14 +118,16 @@ export class UVMapper { (item) => size[UVMapper.boxHeightSide[item]], ); const layout: any = { + // top row up: { x: 'west', y: 0 }, down: { x: 'up', y: 0 }, - + // bottom row west: { x: 0, y: 'up' }, south: { x: 'west', y: 'up' }, east: { x: 'south', y: 'down' }, north: { x: 'east', y: 'down' }, }; + Object.keys(layout).forEach((key) => { const entry = layout[key]; if (typeof entry.x === 'string') { @@ -132,6 +140,7 @@ export class UVMapper { entry.y = prev.y + heights[UVMapper.boxFaceOrder.indexOf(entry.y)]; } }); + return layout; } @@ -239,8 +248,10 @@ export class UVMapper { const triIndex = Math.ceil((i / 6) % 1); const sizeU = size[UVMapper.planeWidthSide[face]]; const sizeV = size[UVMapper.planeHeightSide[face]]; + let finalU = textureOffsetU; let finalV = textureOffsetV; + const faceCoords = UVMapper.uvOffsetConvert( sizeU, sizeV, @@ -248,7 +259,7 @@ export class UVMapper { textureHeight, finalU, finalV, - !mirroring[0], + mirroring[0], mirroring[1], );