CameraController.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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, -1), app.scene);
  7. app.scene.activeCamera = camera1;
  8. // app.scene.activeCamera.attachControl(app.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. if(dirc == 0) {
  115. func && func()
  116. return
  117. }
  118. let video0
  119. if(this.lastDirc * dirc <= 0) {
  120. if(dirc < 0) { // 顺时针
  121. video0 = document.getElementById("houseTexture")
  122. }
  123. if(dirc > 0) { // 逆时针
  124. video0 = document.getElementById("houseTextureReverse")
  125. }
  126. this.lastDirc = dirc
  127. } else {
  128. // 当行走结束后,texture是walk视频,所以必须重赋值
  129. if(this.lastDirc < 0) { // 顺时针
  130. video0 = document.getElementById("houseTexture")
  131. }
  132. if(this.lastDirc > 0) { // 逆时针
  133. video0 = document.getElementById("houseTextureReverse")
  134. }
  135. }
  136. if(video0.id != "houseTexture" && video0.id != "houseTextureReverse") return
  137. let startTime = (this.camera.alpha % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2) / (Math.PI * 2) * video0.duration
  138. if(dirc < 0) {
  139. startTime = video0.duration - startTime
  140. }
  141. let durtime = Math.abs(alphaOffset / (Math.PI * 2) * video0.duration)
  142. const rotateAni = new BABYLON.Animation("rotateCamera", "alpha", settings.video.frameRate,
  143. BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE);
  144. let rotateCameraFrameNum = settings.video.frameRate * durtime
  145. const rotateFrames = [{
  146. frame: 0,
  147. value: this.camera.alpha
  148. },{
  149. frame: rotateCameraFrameNum,
  150. value: this.camera.alpha - alphaOffset
  151. }];
  152. rotateAni.setKeys(rotateFrames);
  153. video0.currentTime = startTime
  154. if(this.app.hasVideoTexture) this.app.house[1].material._textures.texture_video.video = video0
  155. await video0.play()
  156. // 实时矫正currentTime
  157. let endTime = (startTime + durtime) % video0.duration
  158. let handle = setInterval(() => {
  159. if(endTime > startTime) {
  160. // 不跨0
  161. if(video0.currentTime > endTime) video0.currentTime = endTime
  162. } else {
  163. if(video0.currentTime > endTime && video0.currentTime < startTime) video0.currentTime = endTime
  164. }
  165. }, 10)
  166. this.app.scene.beginDirectAnimation(this.camera, [rotateAni], 0, rotateCameraFrameNum, false, 1,
  167. () => {
  168. clearInterval(handle)
  169. this.enable = true
  170. video0.currentTime = (startTime + durtime) % video0.duration
  171. video0.pause()
  172. func && func()
  173. });
  174. }
  175. lockCamera(isTrue) {
  176. this.cameraControlEnable = isTrue
  177. this.camera.lowerAlphaLimit = isTrue ? this.camera.alpha : null
  178. this.camera.upperAlphaLimit = isTrue ? this.camera.alpha : null
  179. }
  180. }