123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- import common from "./utils/common.js";
- import settings from "./utils/settings.js"
- export default class CameraController {
- constructor(app) {
- this.app = app
-
- var camera1 = new BABYLON.ArcRotateCamera("camera1", 0, Math.PI / 2, 10, new BABYLON.Vector3(0, 0, -1), app.scene);
- app.scene.activeCamera = camera1;
- // app.scene.activeCamera.attachControl(app.scene.canvas, true);
- camera1.inertia = 0
- camera1.minZ = 100
- 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.enable = true
- this.lastCameraAlpha = 0
- this.lastDirc = 0
- this.initAlpha = 0 // 初始角度积累
- // 人物相机射线
- 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));
- }
- updateCameraPos() {
- if(!this.app.charactorManager || !this.app.charactorManager.charactor) return
- let charactor = this.app.charactorManager.charactor
-
- // 实时更新相机target
- let cameraTarget = 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.app.house)[0];
- const offset = 0.05
- if(!info || info.distance > settings.camera.distanceFromCharactor + offset) return
- let charactorVisi = 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) charactor.visible = false
- // if(info.distance - offset >= 0.25 && !charactorVisi) charactor.visible = true
- }
- startMouseRotate(pointerInfo) {
- this.lastFramePoint = new BABYLON.Vector2(pointerInfo.event.clientX, pointerInfo.event.clientY)
- }
- endMouseRotate() {
- this.lastFramePoint = null
- // this.lastDirc = 0
- }
- /**
- * 鼠标移动时,计算xoffset,得到旋转方向
- * xoffset越大,瞬时速度越快,转的角度就越大
- * 指定xoffset大于一定值的帧,根据旋转方向和角度请求视频,相机animation改alpha与视频一致
- * 视频旋转中,计算每帧的xoffset,如果方向没变,不再发出请求
- * 如果方向相反,根据瞬时速度请求新视频,并停止当前动画,播放新动画
- */
- mouseRotating(pointerInfo) {
-
- if(!this.app.charactorManager || !this.app.charactorManager.charactor || !this.enable) return
- let charactor = this.app.charactorManager.charactor
- let currentFramePoint = new BABYLON.Vector2(pointerInfo.event.clientX, pointerInfo.event.clientY)
- let pointerOffset = currentFramePoint.clone().subtract(this.lastFramePoint).length()
- // 旋转方向:向右为负方向,顺时针;向左为正方向,逆时针(reverse)
- let dirc = Math.sign(currentFramePoint.x - this.lastFramePoint.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 = Math.min( pointerOffset / 1000 * Math.PI, Math.PI )
- alphaOffset *= dirc
- this.initAlpha += alphaOffset
- if(charactor.actionType.split("-")[1] == "Walking") {
- // 行走时旋转相机,行走停止
- charactor.startWalk([], this.app.charactorManager)
- }
- // && dirc * this.lastDirc <= 0
- else if(Math.abs(this.initAlpha) > Math.PI / 30 && dirc != 0) {
- // let currentPath = charactor.walkData.pathArr[charactor.walkData.currentPoint]
- // let startPoint = (currentPath && currentPath.point) || charactor.mesh.position
- // let point1 = Math.floor((-this.camera.alpha + Math.PI * 2) % (Math.PI * 2) / Math.PI * 180 / 6) * 6
- // let point2 = Math.floor((-this.camera.alpha - this.initAlpha + Math.PI * 2) % (Math.PI * 2) / Math.PI * 180 / 6) * 6
- let point1 = Math.floor(this.camera.alpha / Math.PI * 180 / 6) * 6
- let point2 = Math.floor((this.camera.alpha + this.initAlpha) / Math.PI * 180 / 6) * 6
- // let sangle, eangle
-
- this.alphaOffset = (point1 - point2) / 180 * Math.PI
-
- // if(dirc < 0) {
- // sangle = point1
- // eangle = point2 == 0 ? 359 : point2
- // } else {
- // sangle = point2
- // eangle = point1 == 0 ? 359 : point1
- // }
- // let pointData = this.app.charactorManager.getClosestPointData(startPoint)
- // let sendData = {
- // videoPath: pointData.id + "/" + pointData.id,
- // sangle: sangle,
- // eangle: eangle,
- // reverses: dirc < 0,
- // sceneCode: settings.sceneCode,
- // roomId: settings.roomId,
- // userId: settings.userId,
- // }
- // window.connection.socket.emit("getRotateVideo", sendData);
- // console.log("[3D] send: ", sendData)
- this.rotateCamera(this.alphaOffset, dirc)
- this.enable = false
- this.initAlpha = 0
- }
- this.lastFramePoint = currentFramePoint
- if(dirc != 0 && this.lastDirc * dirc > 0) this.lastDirc = dirc
- }
- async rotateCamera(alphaOffset, dirc, func) {
- if(dirc == 0) {
- func && func()
- return
- }
- let video0
- if(this.lastDirc * dirc <= 0) {
- if(dirc < 0) { // 顺时针
- video0 = document.getElementById("houseTexture")
- }
- if(dirc > 0) { // 逆时针
- video0 = document.getElementById("houseTextureReverse")
- }
- this.lastDirc = dirc
- } else {
- // 当行走结束后,texture是walk视频,所以必须重赋值
- if(this.lastDirc < 0) { // 顺时针
- video0 = document.getElementById("houseTexture")
- }
- if(this.lastDirc > 0) { // 逆时针
- video0 = document.getElementById("houseTextureReverse")
- }
- }
- if(video0.id != "houseTexture" && video0.id != "houseTextureReverse") return
-
- let startTime = (this.camera.alpha % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2) / (Math.PI * 2) * video0.duration
- if(dirc < 0) {
- startTime = video0.duration - startTime
- }
- let durtime = Math.abs(alphaOffset / (Math.PI * 2) * video0.duration)
- 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
- if(this.app.hasVideoTexture) this.app.house[1].material._textures.texture_video.video = video0
- await video0.play()
- // 实时矫正currentTime
- let endTime = (startTime + durtime) % video0.duration
- let handle = setInterval(() => {
- if(endTime > startTime) {
- // 不跨0
- if(video0.currentTime > endTime) video0.currentTime = endTime
- } else {
- if(video0.currentTime > endTime && video0.currentTime < startTime) video0.currentTime = endTime
- }
- }, 10)
- this.app.scene.beginDirectAnimation(this.camera, [rotateAni], 0, rotateCameraFrameNum, false, 1,
- () => {
- clearInterval(handle)
- this.enable = true
- video0.currentTime = (startTime + durtime) % video0.duration
- video0.pause()
- func && func()
- });
- }
- lockCamera(isTrue) {
- this.cameraControlEnable = isTrue
- this.camera.lowerAlphaLimit = isTrue ? this.camera.alpha : null
- this.camera.upperAlphaLimit = isTrue ? this.camera.alpha : null
- }
- }
|