UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

132 lines (121 loc) 4.66 kB
/** * creates rules used by the WFCSolver * * */ import {TypedSopNode} from './_Base'; import {NodeParamsConfig} from '../utils/params/ParamsConfig'; import {CoreGroup} from '../../../core/geometry/Group'; import {SopType} from '../../poly/registers/nodes/types/Sop'; import {InputCloneMode} from '../../poly/InputCloneMode'; import {Object3D, Quaternion} from 'three'; import {WFCTileSide, rotatedSide, tileSideUnrotated, neighbourTileSideUnrotated} from '../../../core/wfc/WFCCommon'; import {CoreWFCTileAttribute} from '../../../core/wfc/WFCAttributes'; import {createRuleObject} from '../../../core/wfc/WFCRule'; const identityQuaternion = new Quaternion(); const _q = new Quaternion(); // const EPS = 0.001; function _angleIncrement(object: Object3D) { // when a tile rotation is 2 rotations ( 2x90 = 180 ), // the rotation.y is not 180, but 0, // and we therefore check the quaternion angle intead. if (Math.abs(object.rotation.y) > 0.1) { return object.rotation.y / (Math.PI / 2); } _q.setFromRotationMatrix(object.matrix); return _q.angleTo(identityQuaternion) / (Math.PI / 2); } class WFCRuleFromProximitySopParamsConfig extends NodeParamsConfig {} const ParamsConfig = new WFCRuleFromProximitySopParamsConfig(); export class WFCRuleFromProximitySopNode extends TypedSopNode<WFCRuleFromProximitySopParamsConfig> { override paramsConfig = ParamsConfig; static override type() { return SopType.WFC_RULE_FROM_PROXIMITY; } override initializeNode() { this.io.inputs.setCount(2); this.io.inputs.initInputsClonedState([InputCloneMode.NEVER]); } override async cook(inputCoreGroups: CoreGroup[]) { const coreGroup0 = inputCoreGroups[0]; const coreGroup1 = inputCoreGroups[1]; const inputObjects = coreGroup0.threejsObjects(); const tileObjects = coreGroup1.threejsObjects(); const outputObjects: Object3D[] = [...inputObjects]; const tileObjectsInGrid: Object3D[][][] = []; // x/y/z const _addTileObject = (tileObject: Object3D) => { const x = Math.round(tileObject.position.x); const y = Math.round(tileObject.position.y); const z = Math.round(tileObject.position.z); tileObjectsInGrid[x] = tileObjectsInGrid[x] || []; tileObjectsInGrid[x][y] = tileObjectsInGrid[x][y] || []; tileObjectsInGrid[x][y][z] = tileObject; }; const _getTileObject = (x: number, y: number, z: number): Object3D | undefined => { x = Math.round(x); y = Math.round(y); z = Math.round(z); const xs = tileObjectsInGrid[x]; if (!xs) { return; } const yz = tileObjectsInGrid[x][y]; if (!yz) { return; } return tileObjectsInGrid[x][y][z]; }; const _addConnectionIfNeighbourFound = ( currentObject: Object3D, xOffset: number, yOffset: number, zOffset: number ) => { const x = Math.round(currentObject.position.x); const y = Math.round(currentObject.position.y); const z = Math.round(currentObject.position.z); const neighbour = _getTileObject(x + xOffset, y + yOffset, z + zOffset); if (!neighbour) { return; } const id0 = CoreWFCTileAttribute.getTileId(currentObject); const id1 = CoreWFCTileAttribute.getTileId(neighbour); const currentObjectSideUnrotated: WFCTileSide = tileSideUnrotated(xOffset, yOffset, zOffset); //xOffset < 0 ? 's' : xOffset > 0 ? 'n' : zOffset < 0 ? 'w' : zOffset > 0 ? 'e' : yOffset < 0 ? 'b' : 't'; const currentObjectSide = rotatedSide( currentObjectSideUnrotated, Math.round(_angleIncrement(currentObject)) ); const neighbourSideUnrotated: WFCTileSide = neighbourTileSideUnrotated(xOffset, yOffset, zOffset); // xOffset < 0 ? 'n' : xOffset > 0 ? 's' : zOffset < 0 ? 'e' : zOffset > 0 ? 'w' : yOffset < 0 ? 't' : 'b'; const neighbourSide = rotatedSide(neighbourSideUnrotated, Math.round(_angleIncrement(neighbour))); const ruleObject = createRuleObject({ id0, id1, side0: currentObjectSide, side1: neighbourSide, }); outputObjects.push(ruleObject); }; for (const tileObject of tileObjects) { const isTile = CoreWFCTileAttribute.getIsTile(tileObject); if (!isTile) { continue; } _addTileObject(tileObject); } for (const tileObject of tileObjects) { const isTile = CoreWFCTileAttribute.getIsTile(tileObject); if (!isTile) { continue; } _addConnectionIfNeighbourFound(tileObject, -1, 0, 0); _addConnectionIfNeighbourFound(tileObject, +1, 0, 0); _addConnectionIfNeighbourFound(tileObject, 0, -1, 0); _addConnectionIfNeighbourFound(tileObject, 0, +1, 0); _addConnectionIfNeighbourFound(tileObject, 0, 0, -1); _addConnectionIfNeighbourFound(tileObject, 0, 0, +1); } this.setObjects(outputObjects); } }