abysmal hacking for nominal results

This commit is contained in:
Evert Prants 2024-02-21 20:13:08 +02:00
parent 3be6493f3d
commit b959cea254
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
4 changed files with 235 additions and 39 deletions

View File

@ -100,6 +100,14 @@ export interface MsonCompound extends MsonBaseComponent {
}
export type MsonFace = 'up' | 'down' | 'east' | 'west' | 'south' | 'north';
export const MsonFaces: MsonFace[] = [
'up',
'down',
'east',
'west',
'south',
'north',
];
export type MsonPlanarXYZWH = [
MsonVariable,

View File

@ -2,19 +2,19 @@ import { resolve } from 'path';
import { ModelStore, MsonEvaluate } from '.';
import { fillStoreFromFilesystem, saveGeometry } from './util/node';
import { ThreeBuilder } from './three';
import { MeshBasicMaterial } from 'three';
import { MeshBasicMaterial, MeshLambertMaterial } from 'three';
async function init() {
const store = new ModelStore();
const evaluate = new MsonEvaluate(store);
const mat = new MeshBasicMaterial();
const mat = new MeshLambertMaterial();
const builder = new ThreeBuilder(mat);
await fillStoreFromFilesystem(store, resolve(process.cwd(), 'inputs'));
// mson:steve
// minelittlepony:steve_pony
const final = evaluate.evaluateModel('mson:biped');
const final = evaluate.evaluateModel('minelittlepony:races/steve/alicorn');
// console.log(final.texture);
console.dir(final._dataEvaluated, {
depth: 20,

View File

@ -5,6 +5,8 @@ import {
MathUtils,
Mesh,
Object3D,
PlaneGeometry,
Vector2,
Vector3,
} from 'three';
import {
@ -14,11 +16,53 @@ import {
MsonComponentType,
MsonCompound,
MsonCompoundComponent,
MsonData,
MsonEvaluatedModel,
MsonFace,
MsonFaces,
MsonPlanar,
MsonPlanarPlane,
MsonPlanarXYZWHUVXY,
MsonPlane,
MsonSlot,
Vec3,
} from '../mson';
import { isArrayOfArrays } from '../util/array-of-array';
export class ThreeBuilder {
static normals: Record<MsonFace, Vector3> = {
up: new Vector3(0, -1, 0),
down: new Vector3(0, 1, 0),
east: new Vector3(1, 0, 0),
west: new Vector3(-1, 0, 0),
south: new Vector3(0, 0, 1),
north: new Vector3(0, 0, -1),
};
static pocConvert: 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);
},
};
constructor(private readonly material: Material) {}
/**
@ -55,15 +99,56 @@ export class ThreeBuilder {
parent: Object3D,
parentComponent?: MsonComponent,
) {
const wrapper = this.createWrapper(
name,
component.type || 'mson:compound',
component,
);
parent.add(wrapper);
// Compound objects
if (!component.type || component.type === 'mson:compound') {
return this.makeMsonCompound(
this.makeMsonCompound(
name,
component as MsonCompound,
parent,
wrapper,
parentComponent,
);
}
if (component.type === 'mson:slot') {
for (const [childName, child] of Object.entries(component.data)) {
this.makeGeometry(childName, child, wrapper, component);
}
}
if (component.type === 'mson:planar') {
this.makeMsonPlanar(name, component, wrapper, parentComponent);
}
if (component.type === 'mson:plane') {
this.makeMsonPlane(name, component, wrapper, parentComponent);
}
(component as MsonCompound).cubes?.forEach(
(part: MsonCompoundComponent) => {
if (!part.type || part.type === 'mson:box') {
this.makeMsonBox(name, part as MsonBox, wrapper, component);
return;
}
if (part.type === 'mson:plane') {
this.makeMsonPlane(name, part as MsonPlane, wrapper, component);
return;
}
},
);
if (component.children) {
for (const [childName, child] of Object.entries(component.children)) {
this.makeGeometry(childName, child, wrapper, component);
}
}
}
protected makeMsonCompound(
@ -71,17 +156,7 @@ export class ThreeBuilder {
component: MsonCompound,
parent: Object3D,
parentComponent?: MsonComponent,
) {
const wrapper = this.createWrapper(name, component);
parent.add(wrapper);
component.cubes?.forEach((part: MsonCompoundComponent) => {
if (!part.type || part.type === 'mson:box') {
this.makeMsonBox(name, part as MsonBox, wrapper, component);
return;
}
});
}
) {}
protected makeMsonBox(
name: string,
@ -97,23 +172,7 @@ export class ThreeBuilder {
else dilate.set(component.dilate, component.dilate, component.dilate);
}
const rotate = new Vector3();
if (parentComponent?.rotate) {
rotate.fromArray(
(parentComponent.rotate as Vec3).map((entry) =>
MathUtils.degToRad(entry),
),
);
}
const pos = new Vector3();
if (parentComponent?.pivot) {
pos.fromArray(parentComponent.pivot as Vec3);
}
pos.setY(pos.y * -1);
const offset = new Vector3().fromArray(component.from as Vec3);
const halfOffset = offset.clone().divideScalar(2);
const halfSize = size.clone().divideScalar(2);
offset.setY(offset.y * -1);
@ -133,30 +192,157 @@ export class ThreeBuilder {
adjustedTranslate.y - size.y,
adjustedTranslate.z,
);
geometry.rotateX(rotate.x);
geometry.rotateY(rotate.y);
geometry.rotateZ(rotate.z);
// FIXME: hack toJSON
(geometry as any).type = 'BufferGeometry';
delete (geometry as any).parameters;
// TODO: apply UVs
// pos.add(halfOffset).add(halfSize);
const mesh = new Mesh(geometry, this.material);
mesh.name = `${name}__mesh`;
mesh.position.copy(pos);
mesh.updateMatrix();
parent.add(mesh);
}
protected createWrapper(name: string, component: MsonBaseComponent) {
protected makeMsonPlaneFace(
face: MsonFace,
parent: Object3D,
pos: Vector3,
size: Vector2,
uv: Vector2,
mirror?: boolean | [boolean, boolean],
invertY = false,
) {
const planeGeom = new PlaneGeometry(size.x, size.y);
let axisNormal = ThreeBuilder.normals[face];
if (invertY) {
axisNormal = axisNormal.clone().setY(axisNormal.y * -1);
pos.setY(pos.y * -1);
if (['east', 'west', 'south', 'north'].includes(face))
size.setY(size.y * -1);
}
const adjustedTranslate = ThreeBuilder.pocConvert[face](pos, size);
planeGeom.lookAt(axisNormal);
planeGeom.translate(
adjustedTranslate.x,
adjustedTranslate.y,
adjustedTranslate.z,
);
// TODO: apply UVs
// FIXME: hack toJSON
(planeGeom as any).type = 'BufferGeometry';
delete (planeGeom as any).parameters;
const mesh = new Mesh(planeGeom, this.material);
// mesh.position.copy(pos);
mesh.name = face;
parent.add(mesh);
}
protected makeMsonPlanar(
name: string,
component: MsonPlanar,
parent: Object3D,
parentComponent?: MsonComponent,
) {
const wrapper = new Object3D();
wrapper.name = name;
wrapper.userData.type = component.type;
parent.add(wrapper);
for (const face of MsonFaces) {
if (!component[face]) continue;
const toMake = (
isArrayOfArrays(component[face]) ? component[face] : [component[face]]
) as MsonPlanarXYZWHUVXY[];
for (const faceinfo of toMake) {
const planePos = new Vector3();
const size = new Vector2();
const uv = new Vector2();
let mirror: [boolean, boolean] = [false, false];
planePos.fromArray(faceinfo as number[]);
// planePos.setY(planePos.y * -1);
size.fromArray(faceinfo as number[], 3);
if (faceinfo.length > 5) {
uv.fromArray(faceinfo as number[], 5);
}
if (faceinfo.length > 7) {
mirror = [faceinfo[7] as boolean, faceinfo[8] as boolean];
}
this.makeMsonPlaneFace(face, wrapper, planePos, size, uv, mirror, true);
}
}
wrapper.updateMatrix();
}
protected makeMsonPlane(
name: string,
component: MsonPlane,
parent: Object3D,
parentComponent?: MsonComponent,
) {
const wrapper = new Object3D();
wrapper.name = name;
wrapper.userData.type = component.type;
parent.add(wrapper);
const planePos = new Vector3();
const size = new Vector2();
const uv = new Vector2();
let mirror: [boolean, boolean] = [false, false];
if (component.position) planePos.fromArray(component.position as number[]);
if (component.size) size.fromArray(component.size as number[]);
uv.set(component.texture?.u ?? 0, component.texture?.v ?? 0);
if (component.mirror) mirror = component.mirror;
this.makeMsonPlaneFace(
component.face as MsonFace,
wrapper,
planePos,
size,
uv,
mirror,
true,
);
}
protected createWrapper(
name: string,
typeName: string,
component: MsonBaseComponent,
) {
let wrapper = new Object3D();
wrapper.name = name;
wrapper.userData.type = 'mson:compound';
wrapper.userData.type = typeName;
wrapper.visible = component.visible ?? true;
const rotate = new Vector3();
if (component?.rotate) {
rotate.fromArray(
(component.rotate as Vec3).map((entry, index) =>
MathUtils.degToRad(index !== 1 ? entry * -1 : entry),
),
);
}
wrapper.rotation.setFromVector3(rotate, 'XYZ');
const pos = new Vector3();
if (component?.pivot) {
pos.fromArray(component.pivot as Vec3);
}
pos.setY(pos.y * -1);
wrapper.position.copy(pos);
wrapper.updateMatrix();
return wrapper;
}
}

View File

@ -0,0 +1,2 @@
export const isArrayOfArrays = (input: any) =>
Array.isArray(input) && input.every((item) => Array.isArray(item));