refactoring meshUtils, added sceneScale, #74

This commit is contained in:
2026-03-24 20:25:50 +02:00
parent 0928ef8999
commit 008cc428d4
19 changed files with 199 additions and 189 deletions
@@ -22,7 +22,6 @@
<script> <script>
import { GameEngine } from '@/lib/GameEngine.js'; import { GameEngine } from '@/lib/GameEngine.js';
import { autoScale } from '@/lib/MeshUtils';
let engine = null; let engine = null;
export default{ export default{
@@ -81,7 +80,7 @@ export default{
this.animations = gltf.animations.map(a => ({ this.animations = gltf.animations.map(a => ({
name: a.name, id: a.uuid name: a.name, id: a.uuid
})); }));
autoScale(gltf.scene); engine.meshUtils.autoScale(gltf.scene);
let bb = new engine.$.Box3().setFromObject(gltf.scene); let bb = new engine.$.Box3().setFromObject(gltf.scene);
engine.camera.position.set(bb.max.x, bb.max.y, bb.max.z*3); engine.camera.position.set(bb.max.x, bb.max.y, bb.max.z*3);
engine.orbitControls.target.set((bb.max.x + bb.min.x) / 2, (bb.max.y + bb.min.y) / 2, (bb.max.z + bb.min.z) / 2) engine.orbitControls.target.set((bb.max.x + bb.min.x) / 2, (bb.max.y + bb.min.y) / 2, (bb.max.z + bb.min.z) / 2)
@@ -1,9 +1,8 @@
import { bottomOrigin } from "@/lib/MeshUtils";
class CharacterObject{ class CharacterObject{
constructor(engine, data){ constructor(engine, data){
return new Promise(async(resolve, reject)=>{ return new Promise(async(resolve, reject)=>{
this.source = await engine.load(data.$go.asset.name); this.source = await engine.load(data.$go.asset.name);
this.object = bottomOrigin(this.source.scene); this.object = engine.meshUtils.bottomOrigin(this.source.scene);
resolve(this); resolve(this);
}) })
} }
@@ -1,6 +1,5 @@
import { Color, Group, DoubleSide, RepeatWrapping, MeshStandardMaterial, VideoTexture } from "three" import { Color, Group, DoubleSide, RepeatWrapping, MeshStandardMaterial, VideoTexture } from "three"
import { EventManager } from '@/lib/EventManager'; import { EventManager } from '@/lib/EventManager';
import { centerOrigin, clearMaterial, clearObject } from "@/lib/MeshUtils";
import Utils from "#/app/Utils"; import Utils from "#/app/Utils";
class ClassicPuzzle extends EventManager { class ClassicPuzzle extends EventManager {
@@ -100,11 +99,11 @@ class ClassicPuzzle extends EventManager {
done0.position.set(0,0,0); done0.position.set(0,0,0);
engine.draggable.remove(done0) engine.draggable.remove(done0)
container.add(dragZone); container.add(dragZone);
this.object = centerOrigin(container); this.object = engine.meshUtils.centerOrigin(container);
this.dispose = () => { this.dispose = () => {
//console.log('disposing!!!!!!!') //console.log('disposing!!!!!!!')
clearMaterial(defaultMaterial); engine.meshUtils.clearMaterial(defaultMaterial);
clearObject(gltf.scene); engine.meshUtils.clearObject(gltf.scene);
super.dispose(); super.dispose();
} }
resolve(this); resolve(this);
@@ -1,4 +1,3 @@
import { getBoundingBox, getBoundingBoxCenterPoint, getBoundingBoxMaxLength, centerOrigin } from "@/lib/MeshUtils";
import { EventManager } from '@/lib/EventManager'; import { EventManager } from '@/lib/EventManager';
class GenericObject extends EventManager{ class GenericObject extends EventManager{
@@ -7,7 +6,7 @@ class GenericObject extends EventManager{
super(); super();
return new Promise(async(resolve, reject)=>{ return new Promise(async(resolve, reject)=>{
this.source = await engine.load(data.$go.asset.name); this.source = await engine.load(data.$go.asset.name);
this.object = centerOrigin(this.source.scene) this.object = engine.meshUtils.bottomOrigin(this.source.scene)
if (!data.exclude){ if (!data.exclude){
engine.clickable.add(this.object, async e=>{ engine.clickable.add(this.object, async e=>{
@@ -17,9 +16,9 @@ class GenericObject extends EventManager{
if (this.object._hud ){ if (this.object._hud ){
engine.dashboard.detach(this.object); engine.dashboard.detach(this.object);
}else{ }else{
let bb = getBoundingBox(this.object); let bb = engine.meshUtils.getBoundingBox(this.object);
let scale = 0.5 * engine.dashboard.height/getBoundingBoxMaxLength(bb); let scale = 0.5 * engine.dashboard.height/engine.meshUtils.getBoundingBoxMaxLength(bb);
let position = getBoundingBoxCenterPoint(bb, this.object.position).multiplyScalar(scale).negate() let position = engine.meshUtils.getBoundingBoxCenterPoint(bb, this.object.position).multiplyScalar(scale).negate()
let placement = { let placement = {
quaternion: { x:0, y:0, z:0, w:0 }, quaternion: { x:0, y:0, z:0, w:0 },
@@ -1,5 +1,4 @@
import { Vector3, AnimationMixer } from "three"; import { AnimationMixer } from "three";
import { assignMaterial } from "@/lib/MeshUtils";
class GltfObject { class GltfObject {
constructor(engine, obj) { constructor(engine, obj) {
@@ -13,7 +12,7 @@ class GltfObject {
} }
}); });
assignMaterial(gltfObj, obj); engine.meshUtils.assignMaterial(gltfObj, obj);
if (gltf.animations && gltf.animations.length) { if (gltf.animations && gltf.animations.length) {
let mixer = new AnimationMixer(gltfObj); let mixer = new AnimationMixer(gltfObj);
engine.mixers.push(mixer); engine.mixers.push(mixer);
@@ -19,7 +19,6 @@ import { SingleQuestion } from "./SingleQuestion";
import { MazeQuizGame } from "./MazeQuizGame/MazeQuizGame"; import { MazeQuizGame } from "./MazeQuizGame/MazeQuizGame";
import { Particles } from "./Particles"; import { Particles } from "./Particles";
import { SceneSwitcher } from "./SceneSwitcher"; import { SceneSwitcher } from "./SceneSwitcher";
import { assignParams, wrapInGroup, getBoundingBoxMaxLength } from "@/lib/MeshUtils";
import { GameEngine } from "@/lib/GameEngine"; import { GameEngine } from "@/lib/GameEngine";
const InteractiveObjectsImports = { const InteractiveObjectsImports = {
@@ -79,11 +78,11 @@ class InteractiveObject extends EventManager{
break; break;
} }
if (obj.shouldBeLocked){ if (obj.shouldBeLocked){
this.object = wrapInGroup(this.object) this.object = engine.meshUtils.wrapInGroup(this.object)
this.activator = new (obj.activationType == 'unlock' ? LockActivator : VisibilityActivator)(engine, this.object); this.activator = new (obj.activationType == 'unlock' ? LockActivator : VisibilityActivator)(engine, this.object);
this.activator.deactivate(); this.activator.deactivate();
} }
assignParams(this.object, obj); engine.meshUtils.assignParams(this.object, obj);
if (obj.motion){ if (obj.motion){
engine.motionQueue.add({ engine.motionQueue.add({
o: this.object, ...obj.motion o: this.object, ...obj.motion
@@ -124,7 +123,7 @@ class LockActivator{
transparent: true, opacity:1, color: 0xaaaaaa transparent: true, opacity:1, color: 0xaaaaaa
}) })
constructor(engine, group){ constructor(engine, group){
const bckGeometry = new SphereGeometry(getBoundingBoxMaxLength(group.userData.bbox)/2,8,8) const bckGeometry = new SphereGeometry(engine.meshUtils.getBoundingBoxMaxLength(group.userData.bbox)/2,8,8)
const bckMesh = new Mesh(bckGeometry, LockActivator.materialLocked); const bckMesh = new Mesh(bckGeometry, LockActivator.materialLocked);
bckMesh.visible = false; bckMesh.visible = false;
group.add(bckMesh) group.add(bckMesh)
@@ -1,6 +1,5 @@
import { Group, Vector3, Matrix4, Quaternion, RepeatWrapping, Vector2} from 'three'; import { Group, Vector3, Matrix4, Quaternion, RepeatWrapping, Vector2} from 'three';
import { InteractiveObject } from '../InteractiveObject'; import { InteractiveObject } from '../InteractiveObject';
import { getBoundingBox, getBoundingBoxSize } from '@/lib/MeshUtils';
class MazeObject { class MazeObject {
constructor(engine, def, params){ constructor(engine, def, params){
@@ -157,8 +156,8 @@ class MazeObject {
o[e] = mazeAsset.scene.getObjectByName(e); o[e] = mazeAsset.scene.getObjectByName(e);
if (o[e]){ if (o[e]){
o[e].scale.setScalar(scale); o[e].scale.setScalar(scale);
let bb = getBoundingBox(o[e]); let bb = engine.meshUtils.getBoundingBox(o[e]);
o[e].userData.size = getBoundingBoxSize(bb); o[e].userData.size = engine.meshUtils.getBoundingBoxSize(bb);
} }
}); });
this.mazeObject(def, room); this.mazeObject(def, room);
@@ -1,6 +1,5 @@
import { BoxGeometry, Mesh, MeshStandardMaterial, Group, Vector3, CatmullRomCurve3, Color } from 'three'; import { BoxGeometry, Mesh, MeshStandardMaterial, Group, Vector3, CatmullRomCurve3} from 'three';
import { LineMaterial, LineGeometry, Line2 } from 'three/examples/jsm/Addons.js'; import { LineMaterial, LineGeometry, Line2 } from 'three/examples/jsm/Addons.js';
import { centerOrigin, clearMaterial } from '@/lib/MeshUtils';
import { EventManager } from '@/lib/EventManager'; import { EventManager } from '@/lib/EventManager';
import Utils from '#/app/Utils'; import Utils from '#/app/Utils';
@@ -109,10 +108,10 @@ class PairMatchingGame extends EventManager {
}; };
this.object = centerOrigin(container); this.object = engine.meshUtils.centerOrigin(container);
this.dispose = () => { this.dispose = () => {
clearMaterial(material); engine.meshUtils.clearMaterial(material);
bm.dispose(); bm.dispose();
super.dispose(); super.dispose();
} }
@@ -1,5 +1,4 @@
import { BoxGeometry, Mesh, MeshBasicMaterial, Group, VideoTexture } from 'three'; import { BoxGeometry, Mesh, MeshBasicMaterial, Group, VideoTexture } from 'three';
import { centerOrigin, clearMaterial } from '@/lib/MeshUtils';
import { EventManager } from '@/lib/EventManager'; import { EventManager } from '@/lib/EventManager';
class PuzzleGame1 extends EventManager { class PuzzleGame1 extends EventManager {
@@ -123,11 +122,11 @@ class PuzzleGame1 extends EventManager {
engine.addEventListener('beforeRender', this.update) engine.addEventListener('beforeRender', this.update)
this.object = centerOrigin(container); this.object = engine.meshUtils.centerOrigin(container);
this.dispose = () => { this.dispose = () => {
//console.log('disposing PG1') //console.log('disposing PG1')
clearMaterial(material); engine.meshUtils.clearMaterial(material);
bm.dispose(); bm.dispose();
super.dispose(); super.dispose();
} }
@@ -1,5 +1,4 @@
import { BoxGeometry, Mesh, MeshBasicMaterial, Group, VideoTexture } from 'three'; import { BoxGeometry, Mesh, MeshBasicMaterial, Group, VideoTexture } from 'three';
import { centerOrigin } from '@/lib/MeshUtils';
import { EventManager } from '@/lib/EventManager'; import { EventManager } from '@/lib/EventManager';
class PuzzleGame2 extends EventManager { class PuzzleGame2 extends EventManager {
@@ -166,7 +165,7 @@ class PuzzleGame2 extends EventManager {
}; };
engine.addEventListener('beforeRender', this.update) engine.addEventListener('beforeRender', this.update)
this.object = centerOrigin(container) this.object = engine.meshUtils.centerOrigin(container)
resolve(this) resolve(this)
}); });
} }
@@ -1,5 +1,4 @@
import { Group, Color } from 'three'; import { Group, Color } from 'three';
import { centerOrigin } from '@/lib/MeshUtils';
import { EventManager } from '@/lib/EventManager'; import { EventManager } from '@/lib/EventManager';
import { TextObject } from './TextObject'; import { TextObject } from './TextObject';
import Utils from '#/app/Utils'; import Utils from '#/app/Utils';
@@ -38,7 +37,7 @@ class SingleQuestion extends EventManager {
} }
container.add(question.object); container.add(question.object);
container.add(answers); container.add(answers);
this.object = centerOrigin(container); this.object = engine.meshUtils.centerOrigin(container);
resolve(this); resolve(this);
}) })
} }
@@ -1,6 +1,5 @@
import { MeshBasicMaterial, Color, DoubleSide } from "three"; import { MeshBasicMaterial, Color, DoubleSide } from "three";
import { Text } from "troika-three-text"; import { Text } from "troika-three-text";
import { assignParams } from "@/lib/MeshUtils";
class TextObject { class TextObject {
constructor(engine, obj) { constructor(engine, obj) {
@@ -21,7 +20,7 @@ class TextObject {
txt.depthOffset = 0.1; txt.depthOffset = 0.1;
//txt.outlineBlur = '50%'; //txt.outlineBlur = '50%';
txt.color = new Color(0x0); txt.color = new Color(0x0);
assignParams(txt, obj) engine.meshUtils.assignParams(txt, obj)
let m = new MeshBasicMaterial({ let m = new MeshBasicMaterial({
// roughness: .73, // roughness: .73,
// metalness: .37, // metalness: .37,
+3 -2
View File
@@ -4,7 +4,7 @@ class Clickable {
constructor(engine, defaultDistance) { constructor(engine, defaultDistance) {
const objects = []; const objects = [];
const raycaster = new Raycaster(); const raycaster = new Raycaster();
let v = new Vector3; let v = new Vector3(), cv = new Vector3();
this.add = function (object, fn, distance) { this.add = function (object, fn, distance) {
objects.push(object); objects.push(object);
@@ -33,6 +33,7 @@ class Clickable {
this.handle = function(){ this.handle = function(){
let forExecute = []; let forExecute = [];
engine.cameraWorld.getWorldPosition(cv);
objects.filter(o=>{ objects.filter(o=>{
do { do {
if (o.__active === false || o.visible === false) return false; if (o.__active === false || o.visible === false) return false;
@@ -41,7 +42,7 @@ class Clickable {
return true; return true;
}).forEach(o => { }).forEach(o => {
o.getWorldPosition(v); o.getWorldPosition(v);
if (engine.cameraWorld.position.distanceTo(v) <= o._clickable.distance) { if (cv.distanceTo(v) <= o._clickable.distance / engine.scale) {
const intersects = raycaster.intersectObject(o); const intersects = raycaster.intersectObject(o);
if (intersects[0]) { if (intersects[0]) {
forExecute.push({ o, i: intersects[0] }); forExecute.push({ o, i: intersects[0] });
+2 -3
View File
@@ -18,7 +18,6 @@ class DashBoard extends EventManager {
this.object = dash; this.object = dash;
hud.visible = false; hud.visible = false;
let hudAnimation, hudPlane, textPlane, sceneHeader; let hudAnimation, hudPlane, textPlane, sceneHeader;
this.group = dash;
dash.add(hud); dash.add(hud);
hud.add(hudTarget) hud.add(hudTarget)
hudTarget.position.set(0,0,0.52); hudTarget.position.set(0,0,0.52);
@@ -285,11 +284,11 @@ class DashBoard extends EventManager {
} }
get active(){ get active(){
return this.group.visible; return this.object.visible;
} }
set active(v){ set active(v){
this.group.visible = v; this.object.visible = v;
} }
get points(){ get points(){
+10 -3
View File
@@ -4,7 +4,7 @@ class Draggable{
constructor(engine, defaultDistance){ constructor(engine, defaultDistance){
const objects = []; const objects = [];
const raycaster = new Raycaster(); const raycaster = new Raycaster();
let v = new Vector3; let v = new Vector3(), cv = new Vector3();
let dragging = null; let dragging = null;
this.add = function(object, dragZone, fn, distance){ this.add = function(object, dragZone, fn, distance){
objects.push(object); objects.push(object);
@@ -29,9 +29,16 @@ class Draggable{
this.handle = function(action){ this.handle = function(action){
if (['start', 'selectstart'].includes(action)){ if (['start', 'selectstart'].includes(action)){
let forExecute = []; let forExecute = [];
objects.forEach(o=>{ engine.cameraWorld.getWorldPosition(cv);
objects.filter(o=>{
do {
if (o.__active === false || o.visible === false) return false;
o = o.parent;
} while (o);
return true;
}).forEach(o=>{
o.getWorldPosition(v); o.getWorldPosition(v);
if (engine.cameraWorld.position.distanceTo(v) <= o._draggable.distance && o.visible){ if (cv.distanceTo(v) <= o._draggable.distance / engine.scale){
const intersects = raycaster.intersectObject(o); const intersects = raycaster.intersectObject(o);
if (intersects[0]) forExecute.push({o, i:intersects[0]}) if (intersects[0]) forExecute.push({o, i:intersects[0]})
} }
+19 -8
View File
@@ -20,12 +20,13 @@ import { MotionEngine } from './MotionEngine.js';
import { Draggable } from './Draggable.js'; import { Draggable } from './Draggable.js';
import { EventManager } from "./EventManager"; import { EventManager } from "./EventManager";
import { Telemetry } from './Telemetry.js'; import { Telemetry } from './Telemetry.js';
import { clearObject } from './MeshUtils.js'; import { MeshUtils } from './MeshUtils.js';
THREE.Cache.enabled = true THREE.Cache.enabled = true
const assetPath = '/asset/default/'; const assetPath = '/asset/default/';
const defaultLightIntensity = 11; const defaultLightIntensity = 11;
const sceneScale = 1//.33;
class GameEngine extends EventManager{ class GameEngine extends EventManager{
@@ -45,6 +46,11 @@ class GameEngine extends EventManager{
); );
const scene = new THREE.Scene(); const scene = new THREE.Scene();
this.sceneWrapper = new THREE.Group();
this.sceneWrapper.scale.setScalar(this.scale);
scene.add(this.sceneWrapper);
this.scene = scene; this.scene = scene;
this.initCameraPivot() this.initCameraPivot()
@@ -84,7 +90,7 @@ class GameEngine extends EventManager{
this.ambientSound = new THREE.Audio(this.listener); this.ambientSound = new THREE.Audio(this.listener);
this.activeObjects = new THREE.Group(); this.activeObjects = new THREE.Group();
scene.add(this.activeObjects); this.sceneWrapper.add(this.activeObjects);
if (this.opts.gizmo) { if (this.opts.gizmo) {
this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement); this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
@@ -99,6 +105,7 @@ class GameEngine extends EventManager{
this.orthographicCamera.position.set(0, 0, 100); this.orthographicCamera.position.set(0, 0, 100);
this.cameraRig.rotation.y = 0; this.cameraRig.rotation.y = 0;
} }
//this.scene.scale.setScalar(1.25);
//const controls = new MapControls( camera, renderer.domElement ); //const controls = new MapControls( camera, renderer.domElement );
@@ -145,11 +152,12 @@ class GameEngine extends EventManager{
} }
async init(domNode, opts = {}) { async init(domNode, opts = {}) {
this.scale = sceneScale;
this.w = domNode.clientWidth || 1200, this.h = domNode.clientHeight || 800; this.w = domNode.clientWidth || 1200, this.h = domNode.clientHeight || 800;
this.aspect = this.w / this.h this.aspect = this.w / this.h
this.opts = opts; this.opts = opts;
const gameEngine = this;
this.raycaster = new THREE.Raycaster(); this.raycaster = new THREE.Raycaster();
this.meshUtils = new MeshUtils(this);
const renderer = new THREE.WebGLRenderer({ const renderer = new THREE.WebGLRenderer({
antialias: true, antialias: true,
@@ -378,7 +386,7 @@ class GameEngine extends EventManager{
this.cameraRig.add(this.orthographicCamera); this.cameraRig.add(this.orthographicCamera);
this.cameraRig.rotation.y = Math.PI; this.cameraRig.rotation.y = Math.PI;
this.cameraWorld.add(this.cameraRig); this.cameraWorld.add(this.cameraRig);
this.scene.add(this.cameraWorld); this.sceneWrapper.add(this.cameraWorld);
} }
async initPhysics() { async initPhysics() {
@@ -626,10 +634,11 @@ class GameEngine extends EventManager{
} }
processHideIfFar(){ processHideIfFar(){
let v = new THREE.Vector3(); let v = new THREE.Vector3(), cv = new THREE.Vector3();
this.cameraWorld.getWorldPosition(cv);
this.farArray.forEach(e=>{ this.farArray.forEach(e=>{
e.object.getWorldPosition(v); e.object.getWorldPosition(v);
let dst = this.cameraWorld.position.distanceTo(v); let dst = v.distanceTo(cv) / this.scale;
if (dst <= e.distance && !e.object.visible) { if (dst <= e.distance && !e.object.visible) {
e.object.visible = true; e.object.visible = true;
}else if (dst > e.distance && e.object.visible){ }else if (dst > e.distance && e.object.visible){
@@ -672,14 +681,14 @@ class GameEngine extends EventManager{
this.gizmo?.dispose(); this.gizmo?.dispose();
this.motionQueue.clearAll(); this.motionQueue.clearAll();
this.ambientSound.stop(); this.ambientSound.stop();
this.loadedObjects.forEach(o=>clearObject(o.scene)) this.loadedObjects.forEach(o=>this.meshUtils.clearObject(o.scene))
GameEngine.loadedTextures.forEach(t=>{ GameEngine.loadedTextures.forEach(t=>{
t.dispose(); t.dispose();
}); });
GameEngine.loadedTextures.splice(0, GameEngine.loadedTextures.length); GameEngine.loadedTextures.splice(0, GameEngine.loadedTextures.length);
this.scene.background?.dispose?.(); this.scene.background?.dispose?.();
this.scene.environment?.dispose?.(); this.scene.environment?.dispose?.();
clearObject(this.scene); this.meshUtils.clearObject(this.scene);
this.scene = null; this.scene = null;
this.tm?.setScene(null); this.tm?.setScene(null);
this.removeAllListenersOfType('beforeRender'); this.removeAllListenersOfType('beforeRender');
@@ -739,6 +748,8 @@ class GameEngine extends EventManager{
}) })
} }
static scale = 1.33;
loadTexture = GameEngine.loadTexture loadTexture = GameEngine.loadTexture
} }
+6 -5
View File
@@ -1,11 +1,11 @@
import { InteractiveObject } from "@/components/InteractiveObjects/InteractiveObject"; import { InteractiveObject } from "@/components/InteractiveObjects/InteractiveObject";
import { VideoPlayer } from '@/components/InteractiveObjects/VideoPlayer'; import { VideoPlayer } from '@/components/InteractiveObjects/VideoPlayer';
import { Hero } from "./Hero"; import { Hero } from "./Hero";
import { getBoundingBox, getBoundingBoxSize, autoScale } from "./MeshUtils";
import { api } from "./Api"; import { api } from "./Api";
class GameManager{ class GameManager{
constructor(engine, gameData, scenarioData, opts = {}){ constructor(engine, gameData, scenarioData, opts = {}){
this.engine = engine
return new Promise(async (resolve, reject)=>{ return new Promise(async (resolve, reject)=>{
if (typeof gameData != 'object'){ if (typeof gameData != 'object'){
gameData = (await api.game.load(gameData)).data; gameData = (await api.game.load(gameData)).data;
@@ -85,8 +85,8 @@ class GameManager{
} }
if (!i.data.noPhysics){ if (!i.data.noPhysics){
let bb = getBoundingBox(io.object); let bb = engine.meshUtils.getBoundingBox(io.object);
let bbs = getBoundingBoxSize(bb); let bbs = engine.meshUtils.getBoundingBoxSize(bb);
engine.physics.add(io.object, 'fixed', false, undefined, 'capsule', { engine.physics.add(io.object, 'fixed', false, undefined, 'capsule', {
radius: Math.max(bbs.x, bbs.z)/2, halfHeight: bbs.y/2 radius: Math.max(bbs.x, bbs.z)/2, halfHeight: bbs.y/2
}) })
@@ -145,7 +145,7 @@ class GameManager{
engine.dashboard?.loading(1) engine.dashboard?.loading(1)
engine.physics.start(); engine.physics.start();
//this.debug('Scene loaded', engine.renderer.info.memory) //console.log('Scene loaded', engine.renderer.info.memory)
} }
resolve(this); resolve(this);
}) })
@@ -173,7 +173,8 @@ class GameManager{
object3d[p].copy(sceneObjects[data.id][p]) object3d[p].copy(sceneObjects[data.id][p])
}) })
}else if (!data.type || data.type == 'GenericObject'){ }else if (!data.type || data.type == 'GenericObject'){
autoScale(object3d, autoScaleFactor); console.log('autoscaling', data.id, autoScaleFactor);
this.engine.meshUtils.autoScale(object3d, autoScaleFactor);
} }
sceneObjects[data.id] = sceneObjects[data.id] || {}; sceneObjects[data.id] = sceneObjects[data.id] || {};
if (this.opts.onObjectLoad){ if (this.opts.onObjectLoad){
+6 -6
View File
@@ -1,5 +1,4 @@
import { AnimationMixer, Vector3, Vector2 } from 'three'; import { AnimationMixer, Vector3, Vector2 } from 'three';
import { getBoundingBox, getBoundingBoxSize } from './MeshUtils';
import { QueryFilterFlags } from '@dimforge/rapier3d'; import { QueryFilterFlags } from '@dimforge/rapier3d';
const zero2 = new Vector2(0,0); const zero2 = new Vector2(0,0);
@@ -66,8 +65,9 @@ class Hero{
// let bb = this.model.userData.bbox; // let bb = this.model.userData.bbox;
// let size = getBoundingBoxSize(bb); // let size = getBoundingBoxSize(bb);
// let center = getBoundingBoxCenterPoint(bb, this.model.userData.object.position) // let center = getBoundingBoxCenterPoint(bb, this.model.userData.object.position)
let bb = getBoundingBox(io.object); let bb = engine.meshUtils.getBoundingBox(io.object);
this.size = getBoundingBoxSize(bb); this.size = engine.meshUtils.getBoundingBoxSize(bb);
console.log('Hero size is', this.size);
// let center = getBoundingBoxCenterPoint(bb, io.object.position) // let center = getBoundingBoxCenterPoint(bb, io.object.position)
// console.log('hero', size, center, size.y - 2*this.characterGapOffset) // console.log('hero', size, center, size.y - 2*this.characterGapOffset)
@@ -307,9 +307,9 @@ class Hero{
this.camera.position.copy(cameraPosition) this.camera.position.copy(cameraPosition)
if (!this.fpv){ if (!this.fpv){
this.camera.lookAt( this.camera.lookAt(
this.model.position.x, this.engine.scale * this.model.position.x,
this.cameraY -this.size.y * 0.5 + this.model.position.y, this.engine.scale * (this.cameraY -this.size.y * 0.5 + this.model.position.y),
this.model.position.z this.engine.scale * this.model.position.z
) )
} }
} }
+129 -126
View File
@@ -1,134 +1,137 @@
import { Box3, Vector3, Group } from "three"; import { Box3, Vector3, Group } from "three";
import { GameEngine } from "./GameEngine"; class MeshUtils {
constructor(engine) {
function assignParams(mesh, params){ this.engine = engine;
['scale', 'rotation', 'position'].forEach(p=>params[p] && mesh[p].fromArray(params[p]));
[
'visible', 'name', 'fontSize', 'color', 'lineHeight',
'maxWidth', 'anchorX', 'anchorY', 'outlineColor', 'outlineWidth', 'textAlign'
].forEach(p=>{
if (params[p]!==undefined) mesh[p] = params[p];
});
}
function assignMaterial(mesh, params){
if (params.name && params.material){
//let mp = params.material.metalness ? new MeshStandardMaterial(params.material) : new MeshBasicMaterial(params.material)
Object.assign(mesh.material, params.material)
if (params.dm){
GameEngine.loadTexture(params.dm, params.path, undefined, [mesh.material, 'map'])
// var dm = new TextureLoader().setPath(params.path).load(params.dm);
// mesh.material.map = dm;
}
if (params.nm){
GameEngine.loadTexture(params.nm, params.path, undefined, [mesh.material, 'normalMap'])
//mesh.material.normalMap = new TextureLoader().setPath(params.path).load(params.nm);
}
if (params.em) {
GameEngine.loadTexture(params.em, params.path, undefined, [mesh.material, 'emissiveMap'])
//mesh.material.emissiveMap = new TextureLoader().setPath(params.path).load(params.em);
}
//mesh.material = mp;
mesh.material.needsUpdate = true;
} }
}
function getBoundingBox(object){ assignParams(mesh, params){
return new Box3().setFromObject(object); ['scale', 'rotation', 'position'].forEach(p=>params[p] && mesh[p].fromArray(params[p]));
} [
'visible', 'name', 'fontSize', 'color', 'lineHeight',
function getBoundingBoxSize(bb){ 'maxWidth', 'anchorX', 'anchorY', 'outlineColor', 'outlineWidth', 'textAlign'
return new Vector3(bb.max.x - bb.min.x, bb.max.y - bb.min.y, bb.max.z - bb.min.z); ].forEach(p=>{
} if (params[p]!==undefined) mesh[p] = params[p];
});
function getBoundingBoxMaxLength(bb){ }
let size = getBoundingBoxSize(bb)
return Math.max(size.x, size.y, size.z) assignMaterial(mesh, params){
} if (params.name && params.material){
//let mp = params.material.metalness ? new MeshStandardMaterial(params.material) : new MeshBasicMaterial(params.material)
function getBoundingBoxCenterPoint(bb, relativeTo){ Object.assign(mesh.material, params.material)
relativeTo = relativeTo || new Vector3(0,0,0) if (params.dm){
let size = getBoundingBoxSize(bb) this.engine.loadTexture(params.dm, params.path, undefined, [mesh.material, 'map'])
return new Vector3( // var dm = new TextureLoader().setPath(params.path).load(params.dm);
bb.min.x + (size.x)/2 - relativeTo.x, // mesh.material.map = dm;
bb.min.y + (size.y)/2 - relativeTo.y, }
bb.min.z + (size.z)/2 - relativeTo.z if (params.nm){
) this.engine.loadTexture(params.nm, params.path, undefined, [mesh.material, 'normalMap'])
} //mesh.material.normalMap = new TextureLoader().setPath(params.path).load(params.nm);
}
function autoScale(object, mk = 1) { if (params.em) {
if (mk === null) return; this.engine.loadTexture(params.em, params.path, undefined, [mesh.material, 'emissiveMap'])
let bb = getBoundingBox(object); //mesh.material.emissiveMap = new TextureLoader().setPath(params.path).load(params.em);
let k = getBoundingBoxMaxLength(bb); }
object.scale.multiplyScalar(mk / k); //mesh.material = mp;
} mesh.material.needsUpdate = true;
function wrapInGroup(object){
if (object.isWrapper) return object;
let group = new Group();
group.userData.bbox = getBoundingBox(object);
group.add(object);
group.userData.object = object;
group.isWrapper = true;
return group;
}
function centerOrigin(object){
let group = wrapInGroup(object);
let position = getBoundingBoxCenterPoint(group.userData.bbox, object.position).negate();
object.position.copy(position)
return group;
}
function bottomOrigin(object){
let group = centerOrigin(object);
group.userData.object.position.y = -group.userData.bbox.min.y
return group;
}
function clearObject(o){
let disposables = []
o.traverse(object => {
if (object.isMesh) {
disposables.push(object);
} }
if (object.isLight){ }
//console.log('Disposeing light', object)
object.dispose(); getBoundingBox(object){
object.shadow?.dispose(); let bb = new Box3().setFromObject(object);
object.shadow?.map?.dispose(); bb.min.multiplyScalar(1 / this.engine.scale);
} bb.max.multiplyScalar(1 / this.engine.scale);
if (object.userData?._io){ return bb;
object.userData._io.dispose?.(); }
delete object.userData._io;
} getBoundingBoxSize(bb){
}); return new Vector3(bb.max.x - bb.min.x, bb.max.y - bb.min.y, bb.max.z - bb.min.z);
disposables.forEach(object=>{ }
object.removeFromParent();
object.geometry.dispose(); getBoundingBoxMaxLength(bb){
if (object.material.isMaterial) { let size = this.getBoundingBoxSize(bb)
clearMaterial(object.material) return Math.max(size.x, size.y, size.z)
} else { }
for (const material of object.material) clearMaterial(material)
} getBoundingBoxCenterPoint(bb, relativeTo){
}) relativeTo = relativeTo || new Vector3(0,0,0)
o.clear(); let size = this.getBoundingBoxSize(bb)
} return new Vector3(
bb.min.x + (size.x)/2 - relativeTo.x,
function clearMaterial(material) { bb.min.y + (size.y)/2 - relativeTo.y,
material.dispose(); bb.min.z + (size.z)/2 - relativeTo.z
for (const key of Object.keys(material)) { )
const value = material[key] }
if (value && typeof value == 'object' && 'minFilter' in value) {
//console.log('Disposing', value.name, this.renderer.info.memory.textures ); autoScale(object, mk = 1) {
value.dispose(); if (mk === null) return;
//console.log('Disposed', value.name, this.renderer.info.memory.textures ); let bb = this.getBoundingBox(object);
let k = this.getBoundingBoxMaxLength(bb);
object.scale.multiplyScalar(mk / k);
}
wrapInGroup(object){
if (object.isWrapper) return object;
let group = new Group();
group.userData.bbox = this.getBoundingBox(object);
group.add(object);
group.userData.object = object;
group.isWrapper = true;
return group;
}
centerOrigin(object){
let group = this.wrapInGroup(object);
let position = this.getBoundingBoxCenterPoint(group.userData.bbox, object.position).negate();
object.position.copy(position)
return group;
}
bottomOrigin(object){
let group = this.centerOrigin(object);
group.userData.object.position.y = -group.userData.bbox.min.y
return group;
}
clearObject(o){
let disposables = []
o.traverse(object => {
if (object.isMesh) {
disposables.push(object);
}
if (object.isLight){
//console.log('Disposeing light', object)
object.dispose();
object.shadow?.dispose();
object.shadow?.map?.dispose();
}
if (object.userData?._io){
object.userData._io.dispose?.();
delete object.userData._io;
}
});
disposables.forEach(object=>{
object.removeFromParent();
object.geometry.dispose();
if (object.material.isMaterial) {
this.clearMaterial(object.material)
} else {
for (const material of object.material) this.clearMaterial(material)
}
})
o.clear();
}
clearMaterial(material) {
material.dispose();
for (const key of Object.keys(material)) {
const value = material[key]
if (value && typeof value == 'object' && 'minFilter' in value) {
//console.log('Disposing', value.name, this.renderer.info.memory.textures );
value.dispose();
//console.log('Disposed', value.name, this.renderer.info.memory.textures );
}
} }
} }
} }
export { export { MeshUtils }
assignParams, assignMaterial, autoScale, centerOrigin, wrapInGroup, bottomOrigin,
getBoundingBox, getBoundingBoxSize, getBoundingBoxMaxLength, getBoundingBoxCenterPoint,
clearObject, clearMaterial
}