import { ArcRotateCamera, Color3, Tools, Engine, HemisphericLight, MeshBuilder, Scene, StandardMaterial, SceneLoader, Texture, Vector3, Animation, AbstractMesh , ActionManager, ExecuteCodeAction, AnimationGroup, Mesh} from "babylonjs"; import {AdvancedDynamicTexture, Button, TextBlock} from 'babylonjs-gui'; import 'babylonjs-loaders' export default class SkyBox { engine: Engine scene: Scene camera: ArcRotateCamera | undefined; table: AbstractMesh[] | undefined; chair: AbstractMesh[] | undefined; animationGroup: AnimationGroup | undefined; constructor(private readonly canvas: boolean) { this.engine = new Engine(this.canvas); this.scene = this.CreateScene(); this.engine.runRenderLoop(() => { this.scene.render(); }) } CreateScene(): Scene { const scene = new Scene(this.engine); this.camera = new ArcRotateCamera('camera', 5, 1.3, 50, new Vector3(0, 0, 0), scene) this.camera.attachControl(this.canvas, true) this.camera.lowerBetaLimit = Tools.ToRadians(0) this.camera.upperBetaLimit = Tools.ToRadians(80) this.camera.lowerRadiusLimit = 15 const light = new HemisphericLight('light', new Vector3(1, 1, 0), scene) light.diffuse = new Color3(1, 1, 1) SceneLoader.ImportMeshAsync('', '/Meshes/', 'house.glb', this.scene).then((result) => { const plane = MeshBuilder.CreatePlane('plane', { size: 1 }) plane.parent = result.meshes[0] plane.position.y = 3 plane.position.z = 9.5 plane.position.x = -0.5 const advancedTexture = AdvancedDynamicTexture.CreateForMesh(plane, 128, 128, false) advancedTexture.renderScale = 1 const button = Button.CreateSimpleButton('button', '进入房间') button.width = 1 button.height = 0.5 button.color = 'white' button.background = 'green' button.onPointerClickObservable.add(() => { const cameraAnimation = new Animation('cameraAnimation', 'radius', 30, Animation.ANIMATIONTYPE_FLOAT, Animation.ANIMATIONLOOPMODE_CONSTANT) const Keys = [ { frame: 0, value: this.camera!.radius }, { frame: 60, value: 6.5 } ] cameraAnimation.setKeys(Keys) this.camera!.animations = [] this.camera!.animations.push(cameraAnimation) this.camera!.lowerRadiusLimit = 3 scene.beginAnimation(this.camera, 0, 60, false, 0.6, () => { this.camera!.upperRadiusLimit = 6.8 }) }) advancedTexture.addControl(button) const LogoPlane = MeshBuilder.CreatePlane('logo', { width: 3, height: 1.5 }, this.scene) LogoPlane.rotation.y = Math.PI / 2 LogoPlane.position.x = 5.9 LogoPlane.position.y = 2 LogoPlane.position.z = 1 const LogoMaterial = new StandardMaterial('logoMaterial', scene) LogoMaterial.diffuseTexture = new Texture('/Meshes/gwise.png', scene) LogoMaterial.emissiveColor = new Color3(0.5, 0.5, 0.5) LogoPlane.material = LogoMaterial }) SceneLoader.ImportMeshAsync('', '/Meshes/', 'chair.glb', this.scene).then((result) => { this.chair = result.meshes this.chair[0].position.x = 1.5 this.chair.forEach((mesh) => { console.log(mesh.name) mesh.actionManager = new ActionManager(this.scene) mesh.actionManager.registerAction( new ExecuteCodeAction(ActionManager.OnPickTrigger, () => { this.animationGroup!.play(false) }) ) }) this.createAnimation(this.chair[0]) const LinePoints = [ new Vector3(0, 0.5, 0), new Vector3(0, 1.5, 0) ] const line = MeshBuilder.CreateDashedLines('dashedLine', { points: LinePoints, dashSize: 0.5, gapSize: 0.2, dashNb: 20 }, this.scene) line.parent = this.chair[0] const disc = MeshBuilder.CreateDisc('circle', { radius: 0.3, tessellation: 60 }, this.scene) disc.parent = this.chair[0] disc.position.y = 1.6 disc.rotation.x = Math.PI const advancedTexture = AdvancedDynamicTexture.CreateForMesh(disc, 128, 128, false) advancedTexture.renderScale = 1 const textBlock = new TextBlock() textBlock.text = '点击椅子' textBlock.color = 'white' textBlock.fontSize = 16 textBlock.fontWeight = '800' advancedTexture.addControl(textBlock) }) SceneLoader.ImportMeshAsync('', '/Meshes/', 'table.glb', this.scene).then((result) => { this.table = result.meshes this.table[0].position.x = -1 this.table[0].scaling = new Vector3(1.4, 1.4, 1.4) }) return scene; } createAnimation(mesh: any) { // 创建动画并作用于position属性 const positionAnimation = new Animation('move', 'position', 30, Animation.ANIMATIONTYPE_VECTOR3, Animation.ANIMATIONLOOPMODE_CYCLE) // 定义关键帧 let Keys = [ { frame: 0, value: new Vector3(1.5, 0, 0) }, { frame: 20, value: new Vector3(1, 0, -1) }, { frame: 40, value: new Vector3(-0.5, 0, -1.5) }, { frame: 60, value: new Vector3(-0.6, 0, -0.8) } ] positionAnimation.setKeys(Keys) const rotationAnimation = new Animation('rotation', 'rotation', 30, Animation.ANIMATIONTYPE_VECTOR3, Animation.ANIMATIONLOOPMODE_CYCLE) Keys = [ { frame: 0, value: new Vector3(0, Math.PI, 0) }, { frame: 20, value: new Vector3(0, Math.PI + Math.PI / 10, 0) }, { frame: 40, value: new Vector3(0, Math.PI + Math.PI / 5, 0) }, { frame: 60, value: new Vector3(0, Math.PI + Math.PI / 3.6) } ] rotationAnimation.setKeys(Keys) this.animationGroup = new AnimationGroup('Animation Group') this.animationGroup.addTargetedAnimation(positionAnimation, mesh) this.animationGroup.addTargetedAnimation(rotationAnimation, mesh) this.animationGroup.normalize(0, 60) this.animationGroup.speedRatio = 0.5 const plane = MeshBuilder.CreatePlane('plane', { size: 0.3 }) plane.parent = this.table![0] plane.position.y = 1 plane.billboardMode = Mesh.BILLBOARDMODE_ALL const advancedTexture = AdvancedDynamicTexture.CreateForMesh(plane, 128, 128, false) advancedTexture.renderScale = 1 const button = Button.CreateSimpleButton('button', '离开房间') button.width = 1 button.height = 0.5 button.color = 'white' button.background = 'green' button.onPointerClickObservable.add(() => { const cameraAnimation = new Animation('cameraAnimation', 'radius', 30, Animation.ANIMATIONTYPE_FLOAT, Animation.ANIMATIONLOOPMODE_CONSTANT) const Keys = [ { frame: 0, value: this.camera!.radius }, { frame: 60, value: 50 } ] cameraAnimation.setKeys(Keys) this.camera!.animations = [] this.camera!.animations.push(cameraAnimation) this.camera!.upperRadiusLimit = 60 this.scene.beginAnimation(this.camera, 0, 60, false, 0.6, () => { this.camera!.lowerRadiusLimit = 15 }) }) advancedTexture.addControl(button) } }