|
@@ -2,6 +2,7 @@ import CharactorManager from "./CharactorManager.js";
|
|
|
import common from "./utils/common.js";
|
|
|
import houseShader from "./shaders/houseShader.js";
|
|
|
import settings from "./utils/settings.js";
|
|
|
+import CameraController from "./CameraController.js";
|
|
|
|
|
|
export default class App {
|
|
|
|
|
@@ -10,29 +11,7 @@ export default class App {
|
|
|
var scene = new BABYLON.Scene(engine);
|
|
|
this.scene = scene
|
|
|
scene.collisionsEnabled = true;
|
|
|
-
|
|
|
- var camera1 = new BABYLON.ArcRotateCamera("camera1", 0, Math.PI / 2, 10, new BABYLON.Vector3(0, 0, 0), scene);
|
|
|
- scene.activeCamera = camera1;
|
|
|
- // scene.activeCamera.attachControl(scene.canvas, true);
|
|
|
- camera1.inertia = 0
|
|
|
- camera1.minZ = 0
|
|
|
- camera1.fov = settings.camera.fov
|
|
|
- camera1.fovMode = BABYLON.ArcRotateCamera.FOVMODE_HORIZONTAL_FIXED
|
|
|
- camera1.lowerBetaLimit = Math.PI / 2
|
|
|
- camera1.upperBetaLimit = Math.PI / 2
|
|
|
- camera1.lowerRadiusLimit = settings.camera.distanceFromCharactor;
|
|
|
- camera1.upperRadiusLimit = settings.camera.distanceFromCharactor;
|
|
|
- camera1.angularSensibilityX /= 2;
|
|
|
- this.camera = camera1
|
|
|
- this.lastCameraAlpha = 0
|
|
|
- this.lastDirc = 0
|
|
|
- this.initAlpha = 0
|
|
|
- this.cameraControlEnable = true
|
|
|
-
|
|
|
- // 人物相机射线
|
|
|
- this.ray = new BABYLON.Ray(new BABYLON.Vector3(0,0,0), new BABYLON.Vector3(0,0,1), 50);
|
|
|
- // BABYLON.RayHelper.CreateAndShow(this.ray, scene, new BABYLON.Color3(1, 0.1, 0.1));
|
|
|
-
|
|
|
+
|
|
|
// Lights
|
|
|
var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, -1, 0), scene);
|
|
|
light.intensity = 1.0;
|
|
@@ -54,6 +33,7 @@ export default class App {
|
|
|
|
|
|
this.init()
|
|
|
this.bindEvents()
|
|
|
+ setTimeout(() => this.bindSocketEvents(), 1000)
|
|
|
}
|
|
|
|
|
|
init() {
|
|
@@ -76,13 +56,13 @@ export default class App {
|
|
|
BABYLON.Effect.ShadersStore['aFragmentShader'] = houseShader.fragment;
|
|
|
BABYLON.Effect.ShadersStore['aVertexShader'] = houseShader.vertex;
|
|
|
|
|
|
- let shaderMaterial = new BABYLON.ShaderMaterial("shader", scene, { vertex: "a", fragment: "a", }, {
|
|
|
+ let shaderMaterial = new BABYLON.ShaderMaterial("shader", self.scene, { vertex: "a", fragment: "a", }, {
|
|
|
attributes: houseShader.attributes,
|
|
|
uniforms: houseShader.uniforms,
|
|
|
defines: houseShader.defines
|
|
|
});
|
|
|
|
|
|
- let videoTexture = new BABYLON.VideoTexture("", houseVideo, scene)
|
|
|
+ let videoTexture = new BABYLON.VideoTexture("", houseVideo, self.scene)
|
|
|
// document.getElementById("houseTexture0").play()
|
|
|
// document.getElementById("houseTexture0").loop = "loop"
|
|
|
|
|
@@ -102,6 +82,8 @@ export default class App {
|
|
|
await self.charactorManager.readPointData()
|
|
|
self.charactorManager.importCharactorModel("../scenes/charactors/", "man_YXL.glb")
|
|
|
});
|
|
|
+
|
|
|
+ this.cameraController = new CameraController(self)
|
|
|
}
|
|
|
|
|
|
bindEvents() {
|
|
@@ -110,16 +92,16 @@ export default class App {
|
|
|
|
|
|
switch (pointerInfo.type) {
|
|
|
case BABYLON.PointerEventTypes.POINTERDOWN:
|
|
|
- this.lastFramePoint = new BABYLON.Vector2(pointerInfo.event.clientX, pointerInfo.event.clientY)
|
|
|
+ this.cameraController.startMouseRotate(pointerInfo)
|
|
|
break;
|
|
|
|
|
|
case BABYLON.PointerEventTypes.POINTERUP:
|
|
|
- this.lastFramePoint = null
|
|
|
- this.lastDirc = 0
|
|
|
+ this.cameraController.endMouseRotate()
|
|
|
break;
|
|
|
|
|
|
case BABYLON.PointerEventTypes.POINTERMOVE:
|
|
|
- if(this.lastFramePoint) this.cameraControl(pointerInfo)
|
|
|
+ if(this.cameraController.lastFramePoint)
|
|
|
+ this.cameraController.mouseRotating(pointerInfo)
|
|
|
break;
|
|
|
|
|
|
case BABYLON.PointerEventTypes.POINTERWHEEL:
|
|
@@ -149,135 +131,74 @@ export default class App {
|
|
|
|
|
|
this.scene.onBeforeRenderObservable.add(() => {
|
|
|
|
|
|
- this.updateCameraPos()
|
|
|
+ this.cameraController.updateCameraPos()
|
|
|
|
|
|
})
|
|
|
}
|
|
|
|
|
|
- updateCameraPos() {
|
|
|
-
|
|
|
- if(!this.charactorManager || !this.charactorManager.charactor) return
|
|
|
-
|
|
|
- // 实时更新相机target
|
|
|
- let cameraTarget = this.charactorManager.charactor.mesh.position.clone()
|
|
|
- cameraTarget.y = settings.camera.height
|
|
|
- this.camera.setTarget(cameraTarget)
|
|
|
-
|
|
|
- // 相机碰撞检测
|
|
|
- this.ray.origin = cameraTarget
|
|
|
- this.ray.direction = BABYLON.Vector3.Normalize( this.camera.position.clone().subtract(cameraTarget) )
|
|
|
- let info = this.ray.intersectsMeshes(this.house)[0];
|
|
|
- const offset = 0 // 0.6
|
|
|
- if(!info || info.distance > settings.camera.distanceFromCharactor + offset) return
|
|
|
- let charactorVisi = this.charactorManager.charactor.visible
|
|
|
- this.camera.lowerRadiusLimit = Math.max( info.distance - offset, 0.1 )
|
|
|
- this.camera.upperRadiusLimit = Math.max( info.distance - offset, 0.1 )
|
|
|
-
|
|
|
- // 根据相机位置更新人物显隐
|
|
|
- if(info.distance - offset < 0.25 && charactorVisi) this.charactorManager.charactor.visible = false
|
|
|
- if(info.distance - offset >= 0.25 && !charactorVisi) this.charactorManager.charactor.visible = true
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 鼠标移动时,计算xoffset,得到旋转方向
|
|
|
- * xoffset越大,瞬时速度越快,转的角度就越大
|
|
|
- * 指定xoffset大于一定值的帧,根据旋转方向和角度请求视频,相机animation改alpha与视频一致
|
|
|
- * 视频旋转中,计算每帧的xoffset,如果方向没变,不再发出请求
|
|
|
- * 如果方向相反,根据瞬时速度请求新视频,并停止当前动画,播放新动画
|
|
|
- */
|
|
|
- cameraControl(pointerInfo) {
|
|
|
+ bindSocketEvents() {
|
|
|
|
|
|
- if(!this.charactorManager || !this.charactorManager.charactor || !this.cameraControlEnable) return
|
|
|
-
|
|
|
- let charactor = this.charactorManager.charactor
|
|
|
- let currentFramePoint = new BABYLON.Vector2(pointerInfo.event.clientX, pointerInfo.event.clientY)
|
|
|
- let pointerOffset = currentFramePoint.clone().subtract(this.lastFramePoint).length()
|
|
|
- let dirc = Math.sign(this.lastFramePoint.x - currentFramePoint.x)
|
|
|
-
|
|
|
- // 一般来说瞬时距离不会超过100,定100时转180度
|
|
|
- // let alphaOffset = Math.max(Math.floor((pointerOffset / 100 * Math.PI / (Math.PI / 30)) * (Math.PI / 30) + Math.PI / 60), Math.PI / 30)
|
|
|
- let alphaOffset = pointerOffset / 100 * Math.PI
|
|
|
- alphaOffset *= dirc
|
|
|
+ window.connection.socket.on('getSocketVideo', async(data) => {
|
|
|
|
|
|
- this.initAlpha += alphaOffset
|
|
|
+ console.log("[3D] get: ", data)
|
|
|
|
|
|
- if(charactor.actionType.split("-")[1] == "Walking") {
|
|
|
- // 行走时旋转相机,行走停止
|
|
|
- charactor.startWalk([], this.charactorManager)
|
|
|
- }
|
|
|
- // && dirc * this.lastDirc <= 0
|
|
|
- else if(Math.abs(this.initAlpha) > Math.PI / 30 && dirc != 0) {
|
|
|
+ const blob = new Blob([data], { type: 'application/video' })
|
|
|
+ const url = URL.createObjectURL(blob)
|
|
|
+ // this.updateHouseVideoBlob(url, true)
|
|
|
+ let video = common.createVideoElement0(url)
|
|
|
+ video.loop = "loop"
|
|
|
+ setTimeout(function () {
|
|
|
+ return URL.revokeObjectURL(url)
|
|
|
+ }, 3000)
|
|
|
|
|
|
- this.initAlpha = 0
|
|
|
-
|
|
|
- let currentPath = charactor.walkData.pathArr[charactor.walkData.currentPoint]
|
|
|
- let startPoint = (currentPath && currentPath.point) || charactor.mesh.position
|
|
|
-
|
|
|
- let pointData = this.charactorManager.getClosestPointData(startPoint)
|
|
|
- let sendData = {
|
|
|
- videoList: [pointData.id + "/" + pointData.id],
|
|
|
- // reverse: dirc < 0
|
|
|
- videoId: common.uuid()
|
|
|
- }
|
|
|
- // window.connection.socket.emit("pushVideo", sendData)
|
|
|
- // console.log("[3D] send: ", sendData)
|
|
|
+ // this.cameraController.rotateCamera(this.cameraController.alphaOffset)
|
|
|
+ })
|
|
|
|
|
|
- this.rotateCamera(alphaOffset)
|
|
|
- }
|
|
|
+ window.connection.socket.on('getVideo', async (jsonArr) => {
|
|
|
+
|
|
|
+ let path = jsonArr.map( async (data) => {
|
|
|
|
|
|
- this.lastFramePoint = currentFramePoint
|
|
|
- this.lastDirc = dirc
|
|
|
- }
|
|
|
+ const blob = new Blob([data.video], { type: 'application/video' })
|
|
|
+ const url = URL.createObjectURL(blob)
|
|
|
+ setTimeout(function () {
|
|
|
+ return URL.revokeObjectURL(url)
|
|
|
+ }, 3000)
|
|
|
+
|
|
|
+ return {
|
|
|
+ point: new BABYLON.Vector3(data.point.x, 0, data.point.z),
|
|
|
+ video: await common.createVideoElement(url)
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
- async rotateCamera(alphaOffset, func) {
|
|
|
- // todo
|
|
|
- let video0 = this.house[1].material._textures.texture_video.video
|
|
|
-
|
|
|
- let startTime = Math.abs(this.camera.alpha) % (Math.PI * 2) / (Math.PI * 2) * video0.duration
|
|
|
- let durtime = Math.abs(alphaOffset / (Math.PI * 2) * video0.duration)
|
|
|
-
|
|
|
- if(video0.paused) {
|
|
|
- // if(dirc * this.lastDirc < 0) {
|
|
|
- // 清除已有动画再播新动画
|
|
|
- this.scene.stopAnimation(this.camera, "rotateCamera")
|
|
|
- // }
|
|
|
-
|
|
|
- const rotateAni = new BABYLON.Animation("rotateCamera", "alpha", settings.video.frameRate,
|
|
|
- BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE);
|
|
|
-
|
|
|
- let rotateCameraFrameNum = settings.video.frameRate * durtime
|
|
|
- const rotateFrames = [{
|
|
|
- frame: 0,
|
|
|
- value: this.camera.alpha
|
|
|
- },{
|
|
|
- frame: rotateCameraFrameNum,
|
|
|
- value: this.camera.alpha + alphaOffset
|
|
|
- }];
|
|
|
-
|
|
|
- rotateAni.setKeys(rotateFrames);
|
|
|
-
|
|
|
- video0.currentTime = startTime
|
|
|
- await video0.play()
|
|
|
-
|
|
|
- this.scene.beginDirectAnimation(this.camera, [rotateAni], 0, rotateCameraFrameNum, false, 1,
|
|
|
- () => {
|
|
|
- this.lastDirc = 0
|
|
|
- video0.pause()
|
|
|
- func && func()
|
|
|
- });
|
|
|
-
|
|
|
- } else {
|
|
|
- // console.error("-------------")
|
|
|
- // video0.pause()
|
|
|
- }
|
|
|
+ // 行走时锁定camera
|
|
|
+ this.cameraController.lockCamera(true)
|
|
|
+ this.charactorManager.charactor.startWalk(path, this)
|
|
|
|
|
|
- }
|
|
|
+ })
|
|
|
+
|
|
|
+ window.connection.socket.on("getRoute", (event) => {
|
|
|
+ console.log("getRoute", event);
|
|
|
+
|
|
|
+ // window.connection.socket.emit("getRotateVideo", {
|
|
|
+ // videoPath: pointData.id + "/" + pointData.id,
|
|
|
+ // sangle: 0,
|
|
|
+ // eangle: 359,
|
|
|
+ // reverses: true,
|
|
|
+ // sceneCode: settings.sceneCode,
|
|
|
+ // roomId: settings.roomId,
|
|
|
+ // userId: settings.userId,
|
|
|
+ // });
|
|
|
+ // window.connection.socket.emit("getRotateVideo", {
|
|
|
+ // videoPath: pointData.id + "/" + pointData.id,
|
|
|
+ // sangle: 0,
|
|
|
+ // eangle: 359,
|
|
|
+ // reverses: false,
|
|
|
+ // sceneCode: settings.sceneCode,
|
|
|
+ // roomId: settings.roomId,
|
|
|
+ // userId: settings.userId,
|
|
|
+ // });
|
|
|
|
|
|
- lockCamera(isTrue) {
|
|
|
- this.cameraControlEnable = isTrue
|
|
|
- this.camera.lowerAlphaLimit = isTrue ? this.camera.alpha : null
|
|
|
- this.camera.upperAlphaLimit = isTrue ? this.camera.alpha : null
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
updateHouseVideo(video, notPlay) {
|