CameraController.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import common from "./utils/common.js";
  2. import settings from "./utils/settings.js"
  3. export default class CameraController {
  4. constructor(app) {
  5. this.app = app
  6. var camera1 = new BABYLON.ArcRotateCamera("camera1", 0, Math.PI / 2, 10, new BABYLON.Vector3(0, 0, 0), app.scene);
  7. app.scene.activeCamera = camera1;
  8. // scene.activeCamera.attachControl(scene.canvas, true);
  9. camera1.inertia = 0
  10. camera1.minZ = 100
  11. camera1.fov = settings.camera.fov
  12. camera1.fovMode = BABYLON.ArcRotateCamera.FOVMODE_HORIZONTAL_FIXED
  13. camera1.lowerBetaLimit = Math.PI / 2
  14. camera1.upperBetaLimit = Math.PI / 2
  15. camera1.lowerRadiusLimit = settings.camera.distanceFromCharactor;
  16. camera1.upperRadiusLimit = settings.camera.distanceFromCharactor;
  17. camera1.angularSensibilityX /= 2;
  18. this.camera = camera1
  19. this.enable = true
  20. this.lastCameraAlpha = 0
  21. this.lastDirc = 0
  22. this.initAlpha = 0 // 初始角度积累
  23. // 人物相机射线
  24. this.ray = new BABYLON.Ray(new BABYLON.Vector3(0,0,0), new BABYLON.Vector3(0,0,1), 50);
  25. // BABYLON.RayHelper.CreateAndShow(this.ray, scene, new BABYLON.Color3(1, 0.1, 0.1));
  26. }
  27. updateCameraPos() {
  28. if(!this.app.charactorManager || !this.app.charactorManager.charactor) return
  29. let charactor = this.app.charactorManager.charactor
  30. // 实时更新相机target
  31. let cameraTarget = charactor.mesh.position.clone()
  32. cameraTarget.y = settings.camera.height
  33. this.camera.setTarget(cameraTarget)
  34. // 相机碰撞检测
  35. this.ray.origin = cameraTarget
  36. this.ray.direction = BABYLON.Vector3.Normalize( this.camera.position.clone().subtract(cameraTarget) )
  37. let info = this.ray.intersectsMeshes(this.app.house)[0];
  38. const offset = 0.05
  39. if(!info || info.distance > settings.camera.distanceFromCharactor + offset) return
  40. let charactorVisi = charactor.visible
  41. this.camera.lowerRadiusLimit = Math.max( info.distance - offset, 0.1 )
  42. this.camera.upperRadiusLimit = Math.max( info.distance - offset, 0.1 )
  43. // 根据相机位置更新人物显隐
  44. if(info.distance - offset < 0.25 && charactorVisi) charactor.visible = false
  45. if(info.distance - offset >= 0.25 && !charactorVisi) charactor.visible = true
  46. }
  47. startMouseRotate(pointerInfo) {
  48. this.lastFramePoint = new BABYLON.Vector2(pointerInfo.event.clientX, pointerInfo.event.clientY)
  49. }
  50. endMouseRotate() {
  51. this.lastFramePoint = null
  52. // this.lastDirc = 0
  53. }
  54. /**
  55. * 鼠标移动时,计算xoffset,得到旋转方向
  56. * xoffset越大,瞬时速度越快,转的角度就越大
  57. * 指定xoffset大于一定值的帧,根据旋转方向和角度请求视频,相机animation改alpha与视频一致
  58. * 视频旋转中,计算每帧的xoffset,如果方向没变,不再发出请求
  59. * 如果方向相反,根据瞬时速度请求新视频,并停止当前动画,播放新动画
  60. */
  61. mouseRotating(pointerInfo) {
  62. if(!this.app.charactorManager || !this.app.charactorManager.charactor || !this.enable) return
  63. let charactor = this.app.charactorManager.charactor
  64. let currentFramePoint = new BABYLON.Vector2(pointerInfo.event.clientX, pointerInfo.event.clientY)
  65. let pointerOffset = currentFramePoint.clone().subtract(this.lastFramePoint).length()
  66. // 旋转方向:向右为负方向,顺时针;向左为正方向,逆时针(reverse)
  67. let dirc = Math.sign(currentFramePoint.x - this.lastFramePoint.x)
  68. // 一般来说瞬时距离不会超过100,定100时转180度
  69. // let alphaOffset = Math.max(Math.floor((pointerOffset / 100 * Math.PI / (Math.PI / 30)) * (Math.PI / 30) + Math.PI / 60), Math.PI / 30)
  70. let alphaOffset = Math.min( pointerOffset / 1000 * Math.PI, Math.PI )
  71. alphaOffset *= dirc
  72. this.initAlpha += alphaOffset
  73. if(charactor.actionType.split("-")[1] == "Walking") {
  74. // 行走时旋转相机,行走停止
  75. charactor.startWalk([], this.app.charactorManager)
  76. }
  77. // && dirc * this.lastDirc <= 0
  78. else if(Math.abs(this.initAlpha) > Math.PI / 30 && dirc != 0) {
  79. // let currentPath = charactor.walkData.pathArr[charactor.walkData.currentPoint]
  80. // let startPoint = (currentPath && currentPath.point) || charactor.mesh.position
  81. // let point1 = Math.floor((-this.camera.alpha + Math.PI * 2) % (Math.PI * 2) / Math.PI * 180 / 6) * 6
  82. // let point2 = Math.floor((-this.camera.alpha - this.initAlpha + Math.PI * 2) % (Math.PI * 2) / Math.PI * 180 / 6) * 6
  83. let point1 = Math.floor(this.camera.alpha / Math.PI * 180 / 6) * 6
  84. let point2 = Math.floor((this.camera.alpha + this.initAlpha) / Math.PI * 180 / 6) * 6
  85. // let sangle, eangle
  86. this.alphaOffset = (point1 - point2) / 180 * Math.PI
  87. // if(dirc < 0) {
  88. // sangle = point1
  89. // eangle = point2 == 0 ? 359 : point2
  90. // } else {
  91. // sangle = point2
  92. // eangle = point1 == 0 ? 359 : point1
  93. // }
  94. // let pointData = this.app.charactorManager.getClosestPointData(startPoint)
  95. // let sendData = {
  96. // videoPath: pointData.id + "/" + pointData.id,
  97. // sangle: sangle,
  98. // eangle: eangle,
  99. // reverses: dirc < 0,
  100. // sceneCode: settings.sceneCode,
  101. // roomId: settings.roomId,
  102. // userId: settings.userId,
  103. // }
  104. // window.connection.socket.emit("getRotateVideo", sendData);
  105. // console.log("[3D] send: ", sendData)
  106. this.rotateCamera(this.alphaOffset, dirc)
  107. this.enable = false
  108. this.initAlpha = 0
  109. }
  110. this.lastFramePoint = currentFramePoint
  111. if(dirc != 0 && this.lastDirc * dirc > 0) this.lastDirc = dirc
  112. }
  113. async rotateCamera(alphaOffset, dirc, func) {
  114. console.log("alphaOffset", alphaOffset)
  115. let video0 = this.app.house[1].material._textures.texture_video.video
  116. let startTime = (this.camera.alpha % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2) / (Math.PI * 2) * video0.duration
  117. if(this.lastDirc * dirc <= 0) {
  118. if(dirc < 0) { // 顺时针
  119. video0 = document.getElementById("houseTexture")
  120. this.app.house[1].material._textures.texture_video.video = video0
  121. // this.app.updateHouseVideo(video0)
  122. }
  123. if(dirc > 0) { // 逆时针
  124. video0 = document.getElementById("houseTextureReverse")
  125. this.app.house[1].material._textures.texture_video.video = video0
  126. // this.app.updateHouseVideo(video0)
  127. }
  128. this.lastDirc = dirc
  129. } else {
  130. // 当行走结束后,video0是walk视频,所以必须重赋值
  131. if(this.lastDirc < 0) { // 顺时针
  132. video0 = document.getElementById("houseTexture")
  133. this.app.house[1].material._textures.texture_video.video = video0
  134. }
  135. if(this.lastDirc > 0) { // 逆时针
  136. video0 = document.getElementById("houseTextureReverse")
  137. this.app.house[1].material._textures.texture_video.video = video0
  138. }
  139. }
  140. if(video0.id != "houseTexture" && video0.id != "houseTextureReverse") return
  141. if(dirc < 0) {
  142. startTime = video0.duration - startTime
  143. }
  144. let durtime = Math.abs(alphaOffset / (Math.PI * 2) * video0.duration)
  145. const rotateAni = new BABYLON.Animation("rotateCamera", "alpha", settings.video.frameRate,
  146. BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE);
  147. let rotateCameraFrameNum = settings.video.frameRate * durtime
  148. const rotateFrames = [{
  149. frame: 0,
  150. value: this.camera.alpha
  151. },{
  152. frame: rotateCameraFrameNum,
  153. value: this.camera.alpha - alphaOffset
  154. }];
  155. rotateAni.setKeys(rotateFrames);
  156. video0.currentTime = startTime
  157. await video0.play()
  158. this.app.scene.beginDirectAnimation(this.camera, [rotateAni], 0, rotateCameraFrameNum, false, 1,
  159. () => {
  160. this.enable = true
  161. video0.pause()
  162. func && func()
  163. });
  164. }
  165. lockCamera(isTrue) {
  166. this.cameraControlEnable = isTrue
  167. this.camera.lowerAlphaLimit = isTrue ? this.camera.alpha : null
  168. this.camera.upperAlphaLimit = isTrue ? this.camera.alpha : null
  169. }
  170. }