Browse Source

Merge branch 'master' of http://192.168.0.115:3000/zhouenguang/PrimordialUniverse

gemercheung 3 years ago
parent
commit
453f93d660
4 changed files with 135 additions and 164 deletions
  1. 1 0
      index.html
  2. 41 63
      modules/CharactorManager.js
  3. 85 101
      modules/index.js
  4. 8 0
      modules/utils/common.js

+ 1 - 0
index.html

@@ -50,6 +50,7 @@
           playsinline
           autoplay
           muted
+          loop
         ></video>
       </div>
 

+ 41 - 63
modules/CharactorManager.js

@@ -50,55 +50,27 @@ export default class CharactorManager {
 
         if(pickinfo.pickedPoint) {
 
-            // this.charactorWalkTo(pickinfo.pickedPoint)
-
             // 在行走之前,首先要把人物矫正到45度的倍数(有视频的8个方向)
 
-            if(this.charactor.actionType.split("-")[1] == "Walking") 
+            if(this.app.camera.alpha % (Math.PI / 4) == 0 ) 
             {
-                // 如果是行走时改方向的话,相机保持之前已校正的度数,所以不用再改
+                // 如果已经在8个方向上了
                 this.charactorWalkTo(pickinfo.pickedPoint)
             } 
             else {
-
-                let cameraAlphaAmend = parseInt(this.app.camera.alpha / (Math.PI / 2)) * (Math.PI / 2)
+                // 相机方向矫正
+                let cameraAlphaAmend = parseInt(this.app.camera.alpha / (Math.PI / 4)) * (Math.PI / 4)
+                let pointData = this.getClosestPointData(this.charactor.mesh.position)
                 let sendData = {
-                    type: "CameraRotate",
-                    point: this.charactor.mesh.position,
-                    dirc: {
-                        from: this.app.camera.alpha % (Math.PI * 2),
-                        to: cameraAlphaAmend % (Math.PI * 2)
-                    }
+                    video: [pointData.id],
+                    reverse: this.app.camera.alpha - cameraAlphaAmend < 0
                 }
-                window.connection.socket.emit("RotateCamera", sendData)
-                
-                // todo 发送数据
-                // common.postData("", sendData).then(response => {
-
-                    // let video = response[0].video
-
-                    // this.app.updateHouseVideo(video)
-
-                    // let rotateAni = new BABYLON.Animation("rotate", "alpha", this.frameRate, 
-                    //     BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE);
+                // window.connection.socket.emit("getPush", sendData)
 
-                    // const rotateFrameNum = this.frameRate * video.duration
-                    // const rotateKeyFrames = [{
-                    //     frame: 0,
-                    //     value: this.app.camera.alpha
-                    // },{
-                    //     frame: rotateFrameNum,
-                    //     value: cameraAlphaAmend
-                    // }]; 
-
-                    // rotateAni.setKeys(rotateKeyFrames);
-
-                    // scene.beginDirectAnimation(this.app.camera, [rotateAni], 0, rotateFrameNum, false, 1, () => {
-                    //     // 旋转完后开始行走
-                    //     this.charactorWalkTo(pickinfo.pickedPoint)
-                    // })
-
-                // })
+                // todo
+                this.app.rotateCamera(this.app.camera.alpha - cameraAlphaAmend, () => {
+                    // this.charactorWalkTo(pickinfo.pickedPoint)
+                })
             }
         }
     }
@@ -111,39 +83,45 @@ export default class CharactorManager {
 
     charactorWalkTo(endPoint) {
 
+        let endPointData = this.getClosestPointData(endPoint)
+
         let currentPath = this.charactor.walkData.pathArr[this.charactor.walkData.currentPoint]
         let startPoint = (currentPath && currentPath.point) || this.charactor.mesh.position
         let sendData = {
-            type: "Walk",
-            point: {
-                from: { x: startPoint.x, y: startPoint.z },
-                to: { x: endPoint.x, y: endPoint.z }
-            },
-            dirc: this.app.camera.alpha % (Math.PI * 2)
+            video: [endPointData.id],   // todo
+            reverse: true   // todo
         }
 
-        window.connection.socket.emit("Walk", sendData)
-
-        // todo 发送数据
-        // common.postData("", sendData).then(response => {
+        // window.connection.socket.emit("getPush", sendData)
 
-            // let path = data.walkPath    // response
-            // path.forEach(data => data.point = this.pointsData[data.id].position)
+        // todo
+        let path = data.walkPath    // response
+        path.forEach(data => data.point = this.pointsData[data.id].position)
 
-            // path = path.map(data => { 
-            //     return { 
-            //         point: new BABYLON.Vector3(data.point.x, 0, data.point.y), 
-            //         video: data.video && common.createVideoElement(data.video) 
-            //     } 
-            // })
-
-            // // 行走时锁定camera
-            // this.app.lockCamera(true)
+        path = path.map(data => { 
+            return { 
+                point: new BABYLON.Vector3(data.point.x, 0, data.point.y), 
+                video: data.video && common.createVideoElement(data.video) 
+            } 
+        })
 
-            // this.charactor.startWalk(path, this)
+        // 行走时锁定camera
+        this.app.lockCamera(true)
+        this.charactor.startWalk(path, this)
 
-        // })
+    }
 
+    getClosestPointData(vec) {
+        let ueVec = {x: vec.x, y: vec.z, z: vec.y}
+        let closestPoint = { data: null, length: 99999 }
+        this.pointsData.forEach( data => {
+            let length = common.getLengthBetweenVec3(ueVec, data.position)
+            if(length < closestPoint.length) {
+                closestPoint.data = data
+                closestPoint.length = length
+            }
+        })
+        return closestPoint.data
     }
 
 }

+ 85 - 101
modules/index.js

@@ -13,7 +13,7 @@ export default class App {
     
         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);
+        // scene.activeCamera.attachControl(scene.canvas, true);
         camera1.inertia = 0
         camera1.minZ = 0
         camera1.fov = settings.camera.fov
@@ -25,28 +25,11 @@ export default class App {
         camera1.angularSensibilityX /= 2;
         this.camera = camera1
         this.lastCameraAlpha = 0
-        // camera1.checkCollisions = true;
-        // camera1.collisionRadius = new BABYLON.Vector3(0.1, 0.1, 0.1)
-        
-        // let self = this
-        // var ray = new BABYLON.Ray(new BABYLON.Vector3(0,0,0), new BABYLON.Vector3(0,0,1), 50);
-        // BABYLON.RayHelper.CreateAndShow(ray, scene, new BABYLON.Color3(1, 0.1, 0.1));
-        // camera1.onCollide = function(mesh) {
-        //     let targetPos = camera1.position.clone()
-        //     targetPos.y = 1
-        //     ray.origin = self.charactorManager.charactor.mesh.position
-        //     ray.direction = BABYLON.Vector3.Normalize( targetPos.subtract(ray.origin) )
-        //     var info = ray.intersectsMesh(mesh);
-        //     if(!info.distance) return
-        //     camera1.lowerRadiusLimit = Math.max(info.distance - 0.5, 0.2)
-        //     camera1.upperRadiusLimit = Math.max(info.distance - 0.5, 0.2)
-        //     console.error(info.distance)
-        // }
-        // console.error(camera1)
+        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));
+        // 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);
@@ -72,6 +55,7 @@ export default class App {
     }
 
     init() {
+
         let self = this
         BABYLON.SceneLoader.ImportMesh("", "../scenes/house/", "000.glb", this.scene, function (newMeshes, particleSystems, skeletons, animationGroups) {
             
@@ -79,6 +63,8 @@ export default class App {
             self.house[0].position = new BABYLON.Vector3(0.6, 2.1, 1.5)
             // self.house[0].position = new BABYLON.Vector3(-22, 0, 12)
 
+            let houseVideo = document.getElementById("houseTexture0")
+
             newMeshes.forEach(m => {
                 // m.scaling.scaleInPlace(100);
                 m._geometry && (m.checkCollisions = true)
@@ -94,14 +80,13 @@ export default class App {
                         defines: houseShader.defines
                     });
                     
-                    let videoTexture = new BABYLON.VideoTexture("", document.getElementById("houseTexture0"), scene)
+                    let videoTexture = new BABYLON.VideoTexture("", houseVideo, scene)
                     // document.getElementById("houseTexture0").play()
                     // document.getElementById("houseTexture0").loop = "loop"
 
                     shaderMaterial.setTexture("texture_video", videoTexture)
-                    // shaderMaterial.setVector3("focal_width_height", new BABYLON.Vector3(735, settings.video.width, settings.video.height))   // 1100 470 860
                     shaderMaterial.setVector3("focal_width_height", new BABYLON.Vector3(
-                        735 * window.innerHeight / settings.video.height, 
+                        864 * window.innerWidth / settings.video.width, 
                         settings.video.width * window.innerHeight / settings.video.height, 
                         window.innerHeight
                     ))
@@ -122,15 +107,16 @@ export default class App {
 
             switch (pointerInfo.type) {
                 case BABYLON.PointerEventTypes.POINTERDOWN:
-                    this.pointDown = true
+                    this.lastFramePoint = new BABYLON.Vector2(pointerInfo.event.clientX, pointerInfo.event.clientY)
                     break;
 
                 case BABYLON.PointerEventTypes.POINTERUP:
-                    this.pointDown = false
+                    this.lastFramePoint = null
+                    this.lastDirc = 0
                     break;
 
                 case BABYLON.PointerEventTypes.POINTERMOVE:
-                    if(this.pointDown) this.rotateCamera()
+                    if(this.lastFramePoint) this.cameraControl(pointerInfo)
                     break;
 
                 case BABYLON.PointerEventTypes.POINTERWHEEL:
@@ -178,73 +164,109 @@ export default class App {
         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.6
+        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 )
-        // console.error(info.pickedPoint, this.camera.position)
         
         // 根据相机位置更新人物显隐
         if(info.distance - offset < 0.25 && charactorVisi) this.charactorManager.charactor.visible = false
         if(info.distance - offset >= 0.25 && !charactorVisi) this.charactorManager.charactor.visible = true
 
-        // let r = this.cameraCollision()
-        // this.camera.lowerRadiusLimit = Math.max( r, 0.1 )
-        // this.camera.upperRadiusLimit = Math.max( r, 0.1 )
-
     }
 
-    rotateCamera() {
-
-        if(!this.charactorManager || !this.charactorManager.charactor) return
+    /**
+     * 鼠标移动时,计算xoffset,得到旋转方向
+     * xoffset越大,瞬时速度越快,转的角度就越大
+     * 指定xoffset大于一定值的帧,根据旋转方向和角度请求视频,相机animation改alpha与视频一致
+     * 视频旋转中,计算每帧的xoffset,如果方向没变,不再发出请求
+     * 如果方向相反,根据瞬时速度请求新视频,并停止当前动画,播放新动画
+     */
+     cameraControl(pointerInfo) {
+        
+        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)
+        if(!this.lastDirc) this.lastDirc = 0
+
+        // 一般来说瞬时距离不会超过100,定100时转180度
+        let alphaOffset = pointerOffset / 100 * Math.PI
+        alphaOffset *= dirc
 
         if(charactor.actionType.split("-")[1] == "Walking") {
             // 行走时旋转相机,行走停止
             charactor.startWalk([], this.charactorManager)
         } 
-        // 根据单个点位视频的总帧数,计算每一帧的度数,只在度数至少到达一帧时,才去请求视频
-        else if(Math.abs(this.camera.alpha - this.lastCameraAlpha) >= Math.PI * 2 / settings.rotateVideoFrame)
-        {
-            this.lockCamera(true)
+        else if(dirc != 0 && dirc * this.lastDirc <= 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 = {
-                type: "RotateCamera",
-                point: { x: startPoint.x, y: startPoint.z },
-                dirc: {
-                    from: this.lastCameraAlpha % (Math.PI * 2),
-                    to: this.camera.alpha % (Math.PI * 2)
-                }
+                video: [pointData.id],
+                reverse: dirc < 0
             }
+            // window.connection.socket.emit("getPush", sendData)
 
-            window.connection.socket.emit("RotateCamera", sendData)
+            this.rotateCamera(alphaOffset)
+        }
 
-            // setTimeout(() => {
-            //     // this.lastCameraAlpha = this.camera.alpha
-            //     this.lockCamera(false)
-            // }, 10)
+        this.lastFramePoint = currentFramePoint
+        this.lastDirc = dirc
+    }
 
-            // todo 发送数据
-            // common.postData("", sendData).then(response => {
+    rotateCamera(alphaOffset, func) {
+        // todo
+        let video0 = document.getElementById("houseTexture0")
+
+        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) {
+            video0.currentTime = startTime
+            video0.play()
+
+            // 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);
+
+            this.scene.beginDirectAnimation(this.camera, [rotateAni], 0, rotateCameraFrameNum, false, 1, 
+                () => {
+                    this.lastDirc = 0
+                    video0.pause()
+                    func && func()
+                });
             
-            //     this.updateHouseVideo(response[0].video)
-
-            //     // this.lastCameraAlpha = this.camera.alpha
-            //     this.lockCamera(false)
-
-            // })
-
-            this.lastCameraAlpha = this.camera.alpha
+        } else {
+            // console.error("-------------")
+            video0.pause()
         }
-
     }
 
     lockCamera(isTrue) {
-        this.camera.lowerAlphaLimit = isTrue ? this.camera.alpha : null
-        this.camera.upperAlphaLimit = isTrue ? this.camera.alpha : null
+        this.cameraControlEnable = isTrue
+        // this.camera.lowerAlphaLimit = isTrue ? this.camera.alpha : null
+        // this.camera.upperAlphaLimit = isTrue ? this.camera.alpha : null
     }
 
     updateHouseVideo(video) {
@@ -255,42 +277,4 @@ export default class App {
         video.play()
     }
 
-    // cameraCollision() {
-    //     // if(this.cameraAngle) {
-    //     //     let {info, point, normal} = this.getRayInfoOnCircle(this.cameraAngle)
-    //     //     if( 
-    //     //         Math.abs(info.distance - point.clone().subtract(this.ray.origin).length()) < 1 &&
-    //     //         this.ray.origin.clone().subtract(info.pickedPoint).addInPlace(normal).length() <= 3.5 
-    //     //     ) {
-    //     //         return this.ray.origin.clone().subtract(info.pickedPoint).addInPlace(normal).length()
-    //     //     } 
-    //     //     else {
-    //     //         this.cameraAngle = null
-    //     //         return 3.5
-    //     //     }
-    //     // }
-
-    //     for(let i = 0; i < Math.PI * 2; i += Math.PI / 8) {
-    //         let {info, point, normal} = this.getRayInfoOnCircle(i)
-    //         if( 
-    //             Math.abs(info.distance - point.clone().subtract(this.ray.origin).length()) < 0.5 &&
-    //             (this.ray.origin.clone().subtract(info.pickedPoint).addInPlace(normal).length() - 3.5) < 0.5  
-    //         ) {
-    //             // this.cameraAngle = i
-    //             return this.ray.origin.clone().subtract(info.pickedPoint).addInPlace(normal).length()
-    //         }
-    //     }
-    //     // this.cameraAngle = null
-    //     return 3.5
-    // }
-
-    // getRayInfoOnCircle(angle) {
-    //     let normal = new BABYLON.Vector3(0, 0, 0.5)
-    //     normal.rotateByQuaternionToRef(BABYLON.Quaternion.RotationAxis(new BABYLON.Vector3(0, 1, 0), angle), normal)
-    //     let point = this.camera.position.clone().addInPlace(normal)    // 圆上的点坐标
-    //     let direction = BABYLON.Vector3.Normalize( point.clone().subtract(this.ray.origin) )
-    //     var ray = new BABYLON.Ray(this.ray.origin, direction, 50);
-    //     let info = ray.intersectsMeshes(this.house)[0];
-    //     return { info: info, point: point, normal: normal }
-    // }
 }

+ 8 - 0
modules/utils/common.js

@@ -38,6 +38,14 @@ export default {
         document.getElementById("videoTextureBox").appendChild(video)
         
         return video
+    },
+
+    getLengthBetweenVec3: (v1, v2) => {
+        return Math.sqrt(
+            (v1.x - v2.x) * (v1.x - v2.x) +
+            (v1.y - v2.y) * (v1.y - v2.y) +
+            (v1.z - v2.z) * (v1.z - v2.z)
+        )
     }
 
 }