CameraAnimation.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. import * as THREE from "../../../libs/three.js/build/three.module.js";
  2. import { EventDispatcher } from "../../EventDispatcher.js";
  3. import { Utils } from "../../utils.js";
  4. import {LineDraw} from "../../utils/DrawUtil";
  5. import CurveCtrl from "../../objects/tool/CurveCtrl";
  6. const colors = {
  7. position: 'red',
  8. target : 'blue'
  9. }
  10. let lineMats
  11. const getLineMat = function(name){
  12. if(!lineMats){
  13. lineMats = {
  14. position: LineDraw.createFatLineMat({
  15. color: colors.position,
  16. lineWidth: 3
  17. }),
  18. target : LineDraw.createFatLineMat({
  19. color: colors.target,
  20. lineWidth: 3
  21. }),
  22. frustum: LineDraw.createFatLineMat({
  23. color: colors.position,
  24. lineWidth: 2
  25. }),
  26. }
  27. }
  28. return lineMats[name]
  29. }
  30. export class CameraAnimation extends EventDispatcher{
  31. constructor(viewer){
  32. super();
  33. this.viewer = viewer;
  34. this.selectedElement = null;
  35. //this.controlPoints = [];
  36. this.uuid = THREE.Math.generateUUID();
  37. this.node = new THREE.Object3D();
  38. this.node.name = "camera animation";
  39. this.viewer.scene.scene.add(this.node);
  40. this.frustum = this.createFrustum();
  41. this.node.add(this.frustum);
  42. this.name = "Camera Animation";
  43. this.duration = 5;
  44. this.t = 0;
  45. // "centripetal", "chordal", "catmullrom"
  46. this.curveType = "centripetal"
  47. this.visible = true;
  48. this.createPath();
  49. this.addEventListener('dispose', ()=>{
  50. this.dispose()
  51. })
  52. }
  53. static defaultFromView(viewer){
  54. const animation = new CameraAnimation(viewer);
  55. const camera = viewer.scene.getActiveCamera();
  56. const target = viewer.scene.view.getPivot();
  57. const cpCenter = new THREE.Vector3(
  58. 0.3 * camera.position.x + 0.7 * target.x,
  59. 0.3 * camera.position.y + 0.7 * target.y,
  60. 0.3 * camera.position.z + 0.7 * target.z,
  61. );
  62. const targetCenter = new THREE.Vector3(
  63. 0.05 * camera.position.x + 0.95 * target.x,
  64. 0.05 * camera.position.y + 0.95 * target.y,
  65. 0.05 * camera.position.z + 0.95 * target.z,
  66. );
  67. const r = 2//camera.position.distanceTo(target) * 0.3;
  68. //const dir = target.clone().sub(camera.position).normalize();
  69. const angle = Utils.computeAzimuth(camera.position, target);
  70. const n = 5;
  71. for(let i = 0; i < n; i++){
  72. let u = 1.5 * Math.PI * (i / n) + angle;
  73. const dx = r * Math.cos(u);
  74. const dy = r * Math.sin(u);
  75. const cpPos = [
  76. cpCenter.x + dx,
  77. cpCenter.y + dy,
  78. cpCenter.z,
  79. ];
  80. const targetPos = [
  81. targetCenter.x + dx * 0.1,
  82. targetCenter.y + dy * 0.1,
  83. targetCenter.z,
  84. ];
  85. animation.createControlPoint();
  86. animation.posCurve.points[i].fromArray(cpPos)
  87. animation.targetCurve.points[i].fromArray(targetPos)
  88. }
  89. animation.changeCallback()
  90. return animation;
  91. }
  92. createControlPoint(index){
  93. const length = this.posCurve.points.length
  94. const position = new THREE.Vector3
  95. const target = new THREE.Vector3
  96. if(index === undefined){
  97. index = length;
  98. }
  99. if(length >= 2 && index === 0){
  100. const dir = new THREE.Vector3().subVectors(this.posCurve.points[0], this.posCurve.points[1] )
  101. position.copy(this.posCurve.points[0]).add(dir);
  102. const tDir = new THREE.Vector3().subVectors(this.targetCurve.points[0], this.targetCurve.points[1] )
  103. target.copy(this.targetCurve.points[0]).add(dir);
  104. }else if(length >= 2 && index === length){
  105. const dir = new THREE.Vector3().subVectors(this.posCurve.points[length-1], this.posCurve.points[length-2] )
  106. position.copy(this.posCurve.points[length-2]).add(dir);
  107. const tDir = new THREE.Vector3().subVectors(this.targetCurve.points[length-1], this.targetCurve.points[length-2] )
  108. target.copy(this.targetCurve.points[length-2]).add(dir);
  109. }else if(length >= 2){
  110. position.copy(this.posCurve.points[index-1].clone().add(this.posCurve.points[index]).multiplyScalar(0.5));
  111. target.copy(this.targetCurve.points[index-1].clone().add(this.targetCurve.points[index]).multiplyScalar(0.5));
  112. }
  113. this.posCurve.addPoint(position, index)
  114. this.targetCurve.addPoint(target, index)
  115. this.dispatchEvent({
  116. type: "controlpoint_added",
  117. index
  118. });
  119. }
  120. removeControlPoint(index){
  121. this.posCurve.removePoint(index)
  122. this.targetCurve.removePoint(index)
  123. this.dispatchEvent({
  124. type: "controlpoint_removed",
  125. index
  126. });
  127. }
  128. createPath(){
  129. this.posCurve = new CurveCtrl([],getLineMat('position'), colors.position);
  130. this.targetCurve = new CurveCtrl([], getLineMat('target'), colors.target);
  131. this.node.add(this.posCurve)
  132. this.node.add(this.targetCurve)
  133. }
  134. createFrustum(){
  135. const f = 0.3;
  136. const positions = [
  137. new THREE.Vector3( 0, 0, 0),
  138. new THREE.Vector3(-f, -f, +1),
  139. new THREE.Vector3( 0, 0, 0),
  140. new THREE.Vector3( f, -f, +1),
  141. new THREE.Vector3( 0, 0, 0),
  142. new THREE.Vector3( f, f, +1),
  143. new THREE.Vector3( 0, 0, 0),
  144. new THREE.Vector3(-f, f, +1),
  145. new THREE.Vector3(-f, -f, +1),
  146. new THREE.Vector3( f, -f, +1),
  147. new THREE.Vector3( f, -f, +1),
  148. new THREE.Vector3( f, f, +1),
  149. new THREE.Vector3( f, f, +1),
  150. new THREE.Vector3(-f, f, +1),
  151. new THREE.Vector3(-f, f, +1),
  152. new THREE.Vector3(-f, -f, +1),
  153. ]
  154. //geometry.computeBoundingSphere();//?
  155. const line = LineDraw.createFatLine( positions, {material:getLineMat('frustum')})
  156. //line.scale.set(20, 20, 20);
  157. return line;
  158. }
  159. at(t){
  160. if(t > 1){
  161. t = 1;
  162. }else if(t < 0){
  163. t = 0;
  164. }
  165. const camPos = this.posCurve.getPointAt(t);
  166. const target = this.targetCurve.getPointAt(t);
  167. const frame = {
  168. position: camPos,
  169. target: target,
  170. };
  171. return frame;
  172. }
  173. set(t){
  174. this.t = t;
  175. }
  176. setVisible(visible){
  177. this.node.visible = visible;
  178. this.posCurve.visible = visible
  179. this.targetCurve.visible = visible
  180. this.visible = visible;
  181. }
  182. setDuration(duration){
  183. this.duration = duration;
  184. }
  185. getDuration(duration){
  186. return this.duration;
  187. }
  188. play(){
  189. const tStart = performance.now();
  190. const duration = this.duration;
  191. const originalyVisible = this.visible;
  192. this.setVisible(false);
  193. const onUpdate = (delta) => {
  194. let tNow = performance.now();
  195. let elapsed = (tNow - tStart) / 1000;
  196. let t = elapsed / duration;
  197. this.set(t);
  198. const frame = this.at(t);
  199. viewer.scene.view.position.copy(frame.position);
  200. viewer.scene.view.lookAt(frame.target);
  201. this.updateFrustum()
  202. if(t > 1){
  203. this.setVisible(originalyVisible);
  204. this.viewer.removeEventListener("update", onUpdate);
  205. }
  206. };
  207. this.viewer.addEventListener("update", onUpdate);
  208. }
  209. updateFrustum(){ //
  210. const frame = this.at(this.t);
  211. const frustum = this.frustum;
  212. frustum.position.copy(frame.position);
  213. frustum.lookAt(...frame.target.toArray());
  214. }
  215. changeCallback(){
  216. this.posCurve.update()
  217. this.targetCurve.update()
  218. this.updateFrustum()
  219. }
  220. dispose(){//add
  221. this.posCurve.dispatchEvent({type:'dispose'})
  222. this.targetCurve.dispatchEvent({type:'dispose'})
  223. this.node.parent.remove(this.node);
  224. }
  225. }
  226. //scene.removeCameraAnimation