GLCameraController.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. Component for animating camera movement.
  6. Can be used to zoom in/out, for linear movement, orbiting and Google Earth - like "fly-to"
  7. Main purpose was the SafeOrbitAndZoomToPos method, the others are usable as well
  8. }
  9. unit GLCameraController;
  10. interface
  11. uses
  12. System.Classes,
  13. System.SysUtils,
  14. System.Math,
  15. System.Contnrs,
  16. System.Types,
  17. GLScene,
  18. GLCoordinates,
  19. GLPersistentClasses,
  20. GLVectorGeometry,
  21. GLSmoothNavigator,
  22. GLVectorTypes;
  23. type
  24. EGLCameraController = class(Exception);
  25. // Forward declaration of the camera controller main class
  26. TGLCameraController = class;
  27. // Forward declaration of a generic camera job
  28. TGLCameraJob = class;
  29. TGLCameraJobList = class(TObjectList)
  30. private
  31. FController : TGLCameraController;
  32. function GetCameraJob(const AIndex: integer): TGLCameraJob;
  33. procedure SetCameraJob(const AIndex: integer; const Value: TGLCameraJob);
  34. public
  35. constructor Create(AController: TGLCameraController);
  36. function Add(ACameraJob: TGLCameraJob): integer;
  37. property Items[const AIndex: integer]: TGLCameraJob read GetCameraJob write SetCameraJob; default;
  38. function First: TGLCameraJob;
  39. function Last: TGLCameraJob;
  40. end;
  41. TGLCameraJob = class(TObject)
  42. private
  43. FJoblist : TGLCameraJobList;
  44. protected
  45. FAbort : boolean;
  46. FInit : boolean;
  47. FRunning : Boolean;
  48. FElapsedTime : Double;
  49. FDeltaTime : Double;
  50. FStartTime : Double;
  51. FProceedTime : Double;
  52. public
  53. constructor Create(const AJoblist : TGLCameraJobList); virtual;
  54. destructor Destroy; override;
  55. procedure Abort;
  56. procedure Step; virtual; abstract;
  57. procedure Init; virtual; abstract;
  58. property Running: Boolean read FRunning write FRunning;
  59. property ElapsedTime: Double read FElapsedTime write FElapsedTime;
  60. property StartTime: Double read FStartTime write FStartTime;
  61. property ProceedTime: Double read FProceedTime write FProceedTime;
  62. end;
  63. TGLMoveToPosJob = class(TGLCameraJob)
  64. private
  65. FInitialPos : TVector;
  66. FFinalPos : TVector;
  67. public
  68. X : Double;
  69. Y : Double;
  70. Z : Double;
  71. Time : Double;
  72. procedure Step; override;
  73. procedure Init; override;
  74. // Properties.
  75. property InitialPos: TVector read FInitialPos;
  76. property FinalPos: TVector read FFinalPos;
  77. end;
  78. TGLZoomToDistanceJob = class(TGLCameraJob)
  79. private
  80. FInitialPos : TVector;
  81. FFinalPos : TVector;
  82. public
  83. Distance : Double;
  84. Time : Double;
  85. procedure Step; override;
  86. procedure Init; override;
  87. // Properties.
  88. property InitialPos: TVector read FInitialPos;
  89. property FinalPos: TVector read FFinalPos;
  90. end;
  91. TGLOrbitToPosJob = class(TGLCameraJob)
  92. private
  93. FFinalPos: TVector; // Yep, FFinalPos is stored in relative coordinates.
  94. FRotateSpeed: TVector2f;
  95. FCameraUpVector: TVector;
  96. // Absolute Coordinates, can even be not normalized by radius.
  97. // Procesed in Init, not used anywhere else.
  98. FTargetPosition: TVector;
  99. FTime : Double;
  100. public
  101. procedure Step; override;
  102. procedure Init; override;
  103. property RotateSpeed: TVector2f read FRotateSpeed;
  104. property CameraUpVector: TVector read FCameraUpVector;
  105. property TargetPosition: TVector read FTargetPosition;
  106. property FinalPos: TVector read FFinalPos;
  107. property Time: Double read FTime;
  108. end;
  109. TGLSmoothOrbitToPos = class(TGLOrbitToPosJob)
  110. private
  111. FCutoffAngle: Single;
  112. FNeedToRecalculateZoom: Boolean;
  113. FShouldBeMatrix: TMatrix;
  114. FSmoothNavigator: TGLNavigatorSmoothChangeVector;
  115. public
  116. constructor Create(const AJoblist : TGLCameraJobList); override;
  117. procedure Step; override;
  118. property CutoffAngle: Single read FCutoffAngle write FCutoffAngle;
  119. property NeedToRecalculateZoom: Boolean read FNeedToRecalculateZoom write FNeedToRecalculateZoom;
  120. end;
  121. TGLOrbitToPosAdvJob = class(TGLCameraJob)
  122. private
  123. FInitialPos : TVector;
  124. FFinalPos : TVector;
  125. FInitialUp : TVector;
  126. FInitialDir : TVector;
  127. FRotAxis : TVector;
  128. FAngle : Double;
  129. public
  130. X : Double;
  131. Y : Double;
  132. Z : Double;
  133. Time : Double;
  134. PreferUpAxis : Boolean;
  135. procedure Step; override;
  136. procedure Init; override;
  137. // Properties.
  138. property InitialPos: TVector read FInitialPos;
  139. property InitialUp: TVector read FInitialUp;
  140. property InitialDir: TVector read FInitialDir;
  141. property FinalPos: TVector read FFinalPos;
  142. end;
  143. TGLSmoothOrbitToPosAdvJob = class(TGLOrbitToPosAdvJob)
  144. private
  145. FPreviousPosition: TVector;
  146. FSmoothNavigator: TGLNavigatorSmoothChangeVector;
  147. FRestoreUpVector: Boolean;
  148. public
  149. procedure Step; override;
  150. procedure Init; override;
  151. end;
  152. TGLCameraJobEvent = procedure(Sender : TGLCameraJob) of object;
  153. TGLCameraController = class(TComponent)
  154. private
  155. // Objects.
  156. FCameraJobList : TGLCameraJobList;
  157. FCamera: TGLBaseSceneObject;
  158. FCameraTarget: TGLBaseSceneObject;
  159. // Events.
  160. FOnJobAdded: TGLCameraJobEvent;
  161. FOnJobFinished: TGLCameraJobEvent;
  162. FOnJobStep: TGLCameraJobEvent;
  163. //fields used by SafeOrbitAndZoomToPos
  164. FsoSafeDist, FsoTimeToSafePlacement, FsoTimeToOrbit, FsoTimeToZoomBackIn:double;
  165. //private methods
  166. //used to test whether camera and cadencer are assigned
  167. //Extended = true -> will test also for Camera.TargetObject
  168. procedure CheckAssignments(Extended: boolean);
  169. //after AdjustScene the Camera.DepthofView will be modified
  170. //if you want to zoom back in from GUI
  171. //you should use something like
  172. // Camera.DepthOfView:=2*Camera.DistanceToTarget+2*camera.TargetObject.BoundingSphereRadius;
  173. procedure SetOnJobAdded(const Value: TGLCameraJobEvent);
  174. procedure SetOnJobFinished(const Value: TGLCameraJobEvent);
  175. procedure SetOnJobStep(const Value: TGLCameraJobEvent);
  176. procedure SetCamera(const Value: TGLBaseSceneObject);
  177. procedure SetCameraTarget(const Value: TGLBaseSceneObject);
  178. protected
  179. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  180. public
  181. constructor Create(AOwner:TComponent); override;
  182. destructor Destroy; override;
  183. (*linear movement from current pos *)
  184. function MoveToPos(x,y,z,time:double): TGLMoveToPosJob;
  185. (*orbiting from current pos to the pos where
  186. the camera points at the camera.targetObject TROUGH the given point
  187. it will not move to the given point(!), use SafeOrbitAndZoomToPos instead
  188. there has to be a camera.targetObject assigned! *)
  189. function OrbitToPos(x,y,z,time:double): TGLOrbitToPosJob;
  190. (* Same as OrbitToPos(), but makes use of SmoothNavigator to make
  191. sure all camera movements are smooth. *)
  192. function OrbitToPosSmooth(const ATargetPosition: TVector; const ATime: Double;
  193. const ASmoothNavigator: TGLNavigatorSmoothChangeVector; const AFNeedToRecalculateZoom: Boolean;
  194. const ACameraUpVector: PVector = nil): TGLSmoothOrbitToPos;
  195. (*Same function as OrbitToPos but support all camera states
  196. PreferUpAxis value is to setup if function use Camera Up based rotation axis
  197. instead of Camera direction based rotation axis when destination and camera
  198. position are opposite from Camera Target *)
  199. function OrbitToPosAdvanced(x,y,z,time:double; PreferUpAxis: Boolean = True): TGLOrbitToPosAdvJob;
  200. (* Same as OrbitToPosAdvanced(), but makes use of SmoothNavigator to make
  201. sure all camera movements are smooth. *)
  202. function OrbitToPosAdvancedSmooth(const x,y,z, time: double;
  203. const ASmoothNavigator: TGLNavigatorSmoothChangeVector;
  204. const PreferUpAxis: Boolean = True): TGLSmoothOrbitToPosAdvJob;
  205. (*zooms in/out by moving to the given distance from camera.targetObject
  206. there has to be a camera.targetObject assigned! *)
  207. function ZoomToDistance(Distance,Time:double): TGLZoomToDistanceJob;
  208. (*google earth - like "fly-to" = zoom out to safe distance, orbit,
  209. and then zoom in to the given point
  210. there has to be a camera.targetObject assigned! *)
  211. procedure SafeOrbitAndZoomToPos(x,y,z:double);
  212. (* It might be a good idea to introduce ability to stop movement
  213. and return control to user, here it is *)
  214. procedure StopMovement;
  215. // Called by the cadencer to animate the camera
  216. procedure Step(const deltaTime, newTime: Double);
  217. property CameraJobList: TGLCameraJobList read FCameraJobList;
  218. published
  219. // Assign a Moving object (usually a TGLCamera).
  220. property Camera: TGLBaseSceneObject read FCamera write SetCamera;
  221. // Assign a target, around which Moving object should rotate(usually TGLCamera.TargetObject).
  222. property CameraTarget: TGLBaseSceneObject read FCameraTarget write SetCameraTarget;
  223. (*specifies whether user should be able interract with the GLSceneViewer
  224. it is set to false while the camera is moving and
  225. coders should check this value and block GUI access to GLSceneViewer *)
  226. //property AllowUserAction:boolean read FAllowUserAction;
  227. (*safe distance to avoid moving the camera trough the camera.targetObject
  228. while performing SafeOrbitAndZoomToPos *)
  229. property soSafeDistance:double read FsoSafeDist write FsoSafeDist;
  230. //time to zoom in/out to the safe position while performing SafeOrbitAndZoomToPos
  231. property soTimeToSafePlacement:double read FsoTimeToSafePlacement write FsoTimeToSafePlacement;
  232. //time to orbit while performing SafeOrbitAndZoomToPos
  233. property soTimeToOrbit:double read FsoTimeToOrbit write FsoTimeToOrbit;
  234. //time to zoom in/out to the given final position while performing SafeOrbitAndZoomToPos
  235. property soTimeToZoomBackIn:double read FsoTimeToZoomBackIn write FsoTimeToZoomBackIn;
  236. //this event is triggered when a job is init
  237. property OnJobAdded : TGLCameraJobEvent read FOnJobAdded write SetOnJobAdded;
  238. //this event is triggered when a job is step (like an OnMove)
  239. property OnJobStep : TGLCameraJobEvent read FOnJobStep write SetOnJobStep;
  240. //this event is triggered when a job is finished (not canceled)
  241. property OnJobFinished : TGLCameraJobEvent read FOnJobFinished write SetOnJobFinished;
  242. end;
  243. //====================================================================
  244. implementation
  245. //====================================================================
  246. const
  247. cGLCAMERACONTROLLER_CHECK_EXTENDED = TRUE;
  248. cEPSILON = 0.001;
  249. { TGLCameraController }
  250. constructor TGLCameraController.Create(AOwner:TComponent);
  251. begin
  252. inherited;
  253. //create the job list container
  254. FCameraJobList := TGLCameraJobList.Create(Self);
  255. FCameraJobList.OwnsObjects := true;
  256. //initialize values
  257. soSafeDistance:=10;
  258. soTimeToSafePlacement:=1;
  259. soTimeToOrbit:=2;
  260. soTimeToZoomBackIn:=1;
  261. end;
  262. destructor TGLCameraController.Destroy;
  263. begin
  264. //delete job list and all jobs inside
  265. FCameraJobList.Free;
  266. inherited;
  267. end;
  268. procedure TGLCameraController.CheckAssignments(Extended:boolean);
  269. begin
  270. /// Check camera assignment
  271. if not Assigned(FCamera) then
  272. begin
  273. Raise EGLCameraController.CreateFmt('%s (%s) needs to have a Camera assigned',[Self.Name, Self.ClassName]);
  274. end;
  275. if Extended then
  276. /// Check camera;TargetObject assignment
  277. if not Assigned(FCameraTarget) then
  278. begin
  279. Raise EGLCameraController.CreateFmt('%s (%s) needs Camera to have a TargetObject assigned',[Self.Name, Self.ClassName]);
  280. end;
  281. end;
  282. procedure TGLCameraController.Step(const deltaTime, newTime: Double);
  283. var
  284. CurrentJob : TGLCameraJob;
  285. begin
  286. if FCameraJobList.Count > 0 then
  287. begin
  288. CurrentJob := FCameraJobList.First;
  289. if CurrentJob.FInit then
  290. begin
  291. CurrentJob.Init;
  292. CurrentJob.FStartTime := newTime;
  293. CurrentJob.FRunning := True;
  294. CurrentJob.FInit := False;
  295. // Notify job
  296. if Assigned(FOnJobAdded) then
  297. FOnJobAdded(CurrentJob);
  298. end;
  299. if CurrentJob.FRunning then
  300. begin
  301. CurrentJob.FElapsedTime := newTime - CurrentJob.FStartTime;
  302. CurrentJob.FDeltaTime := deltaTime;// newTime - CurrentJob.FElapsedTime;
  303. CurrentJob.Step;
  304. // Notify job
  305. if Assigned(FOnJobStep) then
  306. FOnJobStep(CurrentJob);
  307. end;
  308. if not CurrentJob.FRunning then
  309. begin
  310. FCameraJobList.Remove(CurrentJob);
  311. // Notify job
  312. if Assigned(FOnJobFinished) then
  313. FOnJobFinished(CurrentJob);
  314. end;
  315. end;
  316. //AdjustScene;
  317. end;
  318. function TGLCameraController.MoveToPos(x,y,z, time:double): TGLMoveToPosJob;
  319. begin
  320. Result := TGLMoveToPosJob.Create(FCameraJobList);
  321. Result.X := x;
  322. Result.Y := y;
  323. Result.Z := z;
  324. Result.Time := time;
  325. end;
  326. function TGLCameraController.ZoomToDistance(Distance, Time:double): TGLZoomToDistanceJob;
  327. begin
  328. Result := TGLZoomToDistanceJob.Create(FCameraJobList);
  329. Result.Distance := Distance;
  330. Result.Time := Time;
  331. end;
  332. function TGLCameraController.OrbitToPos(x,y,z,time:double): TGLOrbitToPosJob;
  333. begin
  334. Result := TGLOrbitToPosJob.Create(FCameraJobList);
  335. Result.FTargetPosition := PointMake(x, y, z);
  336. Result.FCameraUpVector := FCameraJobList.FController.FCamera.AbsoluteUp;
  337. Result.FTime := time;
  338. end;
  339. function TGLCameraController.OrbitToPosSmooth(const ATargetPosition: TVector; const ATime: Double;
  340. const ASmoothNavigator: TGLNavigatorSmoothChangeVector; const AFNeedToRecalculateZoom: Boolean;
  341. const ACameraUpVector: PVector = nil): TGLSmoothOrbitToPos;
  342. begin
  343. Result := TGLSmoothOrbitToPos.Create(FCameraJobList);
  344. Result.FTargetPosition := ATargetPosition;
  345. Result.FTime := ATime;
  346. Result.FSmoothNavigator := ASmoothNavigator;
  347. Result.FShouldBeMatrix := FCameraJobList.FController.FCamera.Matrix^;
  348. Result.FNeedToRecalculateZoom := AFNeedToRecalculateZoom;
  349. if ACameraUpVector = nil then
  350. Result.FCameraUpVector := FCameraJobList.FController.FCamera.AbsoluteUp
  351. else
  352. Result.FCameraUpVector := ACameraUpVector^;
  353. end;
  354. function TGLCameraController.OrbitToPosAdvanced(x,y,z,time:double; PreferUpAxis: Boolean = True): TGLOrbitToPosAdvJob;
  355. begin
  356. Result := TGLOrbitToPosAdvJob.Create(FCameraJobList);
  357. Result.X := x;
  358. Result.Y := y;
  359. Result.Z := z;
  360. Result.PreferUpAxis := PreferUpAxis;
  361. Result.Time := time;
  362. end;
  363. function TGLCameraController.OrbitToPosAdvancedSmooth(const x,y,z, time: double;
  364. const ASmoothNavigator: TGLNavigatorSmoothChangeVector; const PreferUpAxis: Boolean = True): TGLSmoothOrbitToPosAdvJob;
  365. begin
  366. Result := TGLSmoothOrbitToPosAdvJob.Create(FCameraJobList);
  367. Result.X := x;
  368. Result.Y := y;
  369. Result.Z := z;
  370. Result.PreferUpAxis := PreferUpAxis;
  371. Result.Time := time;
  372. Result.FSmoothNavigator := ASmoothNavigator;
  373. Result.FPreviousPosition := ASmoothNavigator.OnGetCurrentValue(ASmoothNavigator);
  374. Result.FRestoreUpVector := True;
  375. end;
  376. procedure TGLCameraController.SafeOrbitAndZoomToPos(x,y,z:double);
  377. begin
  378. //this was the main purpose of this component
  379. //as you can see, it actually is a combination of the other 3 methods
  380. CheckAssignments(cGLCAMERACONTROLLER_CHECK_EXTENDED);
  381. ZoomToDistance(soSafeDistance,soTimeToSafePlacement);
  382. OrbitToPos(x,y,z,soTimeToOrbit);
  383. MoveToPos(x,y,z,soTimeToZoomBackIn);
  384. end;
  385. procedure TGLCameraController.StopMovement;
  386. begin
  387. FCameraJobList.Clear;
  388. end;
  389. procedure TGLCameraController.SetOnJobAdded(const Value: TGLCameraJobEvent);
  390. begin
  391. FOnJobAdded := Value;
  392. end;
  393. procedure TGLCameraController.SetOnJobStep(const Value: TGLCameraJobEvent);
  394. begin
  395. FOnJobStep := Value;
  396. end;
  397. procedure TGLCameraController.SetOnJobFinished(const Value: TGLCameraJobEvent);
  398. begin
  399. FOnJobFinished := Value;
  400. end;
  401. procedure TGLCameraController.SetCamera(const Value: TGLBaseSceneObject);
  402. begin
  403. if FCamera <> nil then FCamera.RemoveFreeNotification(Self);
  404. FCamera := Value;
  405. if FCamera <> nil then FCamera.FreeNotification(Self);
  406. if (FCamera is TGLCamera) and (FCameraTarget = nil) then
  407. SetCameraTarget(TGLCamera(FCamera).TargetObject);
  408. end;
  409. procedure TGLCameraController.SetCameraTarget(
  410. const Value: TGLBaseSceneObject);
  411. begin
  412. if FCameraTarget <> nil then FCameraTarget.RemoveFreeNotification(Self);
  413. FCameraTarget := Value;
  414. if FCameraTarget <> nil then FCameraTarget.FreeNotification(Self);
  415. end;
  416. procedure TGLCameraController.Notification(AComponent: TComponent;
  417. Operation: TOperation);
  418. begin
  419. inherited;
  420. if Operation = opRemove then
  421. begin
  422. if AComponent = FCamera then
  423. FCamera := nil
  424. else if AComponent = FCameraTarget then
  425. FCameraTarget := nil;
  426. end;
  427. end;
  428. { TGLCameraJobList }
  429. constructor TGLCameraJobList.Create(AController: TGLCameraController);
  430. begin
  431. inherited Create;
  432. FController := AController;
  433. end;
  434. function TGLCameraJobList.GetCameraJob(const AIndex: integer): TGLCameraJob;
  435. begin
  436. Result := inherited Get(AIndex);
  437. end;
  438. procedure TGLCameraJobList.SetCameraJob(const AIndex: integer;
  439. const Value: TGLCameraJob);
  440. begin
  441. inherited Put(AIndex, Value);
  442. end;
  443. function TGLCameraJobList.Add(ACameraJob: TGLCameraJob): integer;
  444. begin
  445. Result := inherited Add(ACameraJob);
  446. end;
  447. function TGLCameraJobList.First: TGLCameraJob;
  448. begin
  449. Result := TGLCameraJob(inherited First);
  450. end;
  451. function TGLCameraJobList.Last: TGLCameraJob;
  452. begin
  453. Result := TGLCameraJob(inherited Last);
  454. end;
  455. { TGLCameraJob }
  456. constructor TGLCameraJob.Create(const AJoblist : TGLCameraJobList);
  457. begin
  458. FJoblist := AJoblist;
  459. FJoblist.Add(Self);
  460. FInit := True;
  461. FStartTime := 0;
  462. FProceedTime := 0;
  463. end;
  464. destructor TGLCameraJob.Destroy;
  465. begin
  466. inherited;
  467. end;
  468. procedure TGLCameraJob.Abort;
  469. begin
  470. end;
  471. { TGLMoveToPosJob }
  472. procedure TGLMoveToPosJob.Init;
  473. begin
  474. FProceedTime := Time;
  475. FInitialPos := VectorSubtract(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition);
  476. MakeVector(FFinalPos, X, Y, Z);
  477. end;
  478. procedure TGLMoveToPosJob.Step;
  479. var
  480. Vect : TVector;
  481. begin
  482. if FElapsedTime < FProceedTime then
  483. begin
  484. Vect := VectorLerp(FInitialPos, FFinalPos, FElapsedTime/FProceedTime);
  485. end
  486. else
  487. begin
  488. Vect := FFinalPos;
  489. FRunning := false;
  490. end;
  491. if Assigned(FJobList.FController.FCamera.Parent) then
  492. Vect:=FJobList.FController.FCamera.Parent.AbsoluteToLocal(Vect);
  493. FJobList.FController.FCamera.Position.AsVector := Vect;
  494. end;
  495. { TGLZoomToDistanceJob }
  496. procedure TGLZoomToDistanceJob.Init;
  497. begin
  498. FProceedTime := Time;
  499. FInitialPos := VectorSubtract(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition);
  500. // To determine final position, we normalize original position and scale it with final distance
  501. SetVector(FFinalPos, FInitialPos);
  502. NormalizeVector(FFinalPos);
  503. ScaleVector(FFinalPos, Distance);
  504. end;
  505. procedure TGLZoomToDistanceJob.Step;
  506. var
  507. Vect : TVector;
  508. begin
  509. if FElapsedTime < FProceedTime then
  510. begin
  511. Vect := VectorLerp(FInitialPos, FFinalPos, FElapsedTime/FProceedTime);
  512. end
  513. else
  514. begin
  515. Vect := FFinalPos;
  516. FRunning := false;
  517. end;
  518. if Assigned(FJobList.FController.FCamera.Parent) then
  519. Vect:=FJobList.FController.FCamera.Parent.AbsoluteToLocal(Vect);
  520. FJobList.FController.FCamera.Position.AsVector := Vect;
  521. end;
  522. { TGLOrbitToPosJob }
  523. procedure TGLOrbitToPosJob.Init;
  524. begin
  525. FProceedTime := FTime;
  526. FFinalPos := ShiftObjectFromCenter(FTargetPosition, FJobList.FController.FCameraTarget.AbsolutePosition,
  527. VectorDistance(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition), True);
  528. // Yep, FFinalPos is stored in relative coordinates.
  529. if FJobList.FController.FCamera.Parent <> nil then
  530. FFinalPos := FJobList.FController.FCamera.Parent.AbsoluteToLocal(FFinalPos);
  531. FRotateSpeed := GetSafeTurnAngle(
  532. FJobList.FController.FCamera.AbsolutePosition, FCameraUpVector, FTargetPosition,
  533. FJobList.FController.FCameraTarget.AbsolutePosition);
  534. ScaleVector(FRotateSpeed, 1 / FProceedTime);
  535. FInit := True;
  536. end;
  537. procedure TGLOrbitToPosJob.Step;
  538. begin
  539. if FElapsedTime < FProceedTime then
  540. begin
  541. FJobList.FController.FCamera.AbsolutePosition := MoveObjectAround(
  542. FJobList.FController.FCamera.AbsolutePosition, FCameraUpVector,
  543. FJobList.FController.FCameraTarget.AbsolutePosition,
  544. FRotateSpeed.X * FDeltaTime, FRotateSpeed.Y * FDeltaTime);
  545. end
  546. else
  547. begin
  548. // Yep, FFinalPos is stored in ralative coordinates.
  549. FJobList.FController.FCamera.Position.AsVector := FFinalPos;
  550. FRunning := False;
  551. end;
  552. end;
  553. { TGLOrbitToPosAdvJob }
  554. procedure TGLOrbitToPosAdvJob.Init;
  555. var
  556. Right: TVector;
  557. lAbsVectorToTarget: TVector;
  558. begin
  559. FProceedTime := time;
  560. FInitialPos := VectorSubtract(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition);
  561. if Assigned(FJobList.FController.FCamera.Parent) then
  562. FFinalPos := VectorSubtract(FJobList.FController.FCamera.Parent.LocalToAbsolute(VectorMake(x,y,z,1)), FJobList.FController.FCameraTarget.AbsolutePosition)
  563. else
  564. FFinalPos := VectorSubtract(VectorMake(x,y,z,1), FJobList.FController.FCameraTarget.AbsolutePosition);
  565. //if destination is Target Pos, we can't compute
  566. if VectorLength(FFinalPos)<cEPSILON then
  567. begin
  568. //FAllowUserAction := True;
  569. Exit;
  570. end;
  571. //Compute Angle of Rotation
  572. FAngle:= ArcCos(VectorAngleCosine(Vector3fMake(FFinalPos), Vector3fMake(FInitialPos)));
  573. lAbsVectorToTarget := VectorNormalize(VectorSubtract(
  574. FJobList.FController.FCameraTarget.AbsolutePosition,
  575. FJobList.FController.FCamera.AbsolutePosition));
  576. Right := VectorNormalize(VectorCrossProduct(lAbsVectorToTarget, FJobList.FController.FCamera.AbsoluteUp));
  577. FInitialDir := FJobList.FController.FCamera.AbsoluteDirection;
  578. FInitialUp := FJobList.FController.FCamera.AbsoluteUp;
  579. // Determine rotation Axis
  580. // if Angle equals 0 degrees.
  581. if FAngle < cEPSILON then
  582. if PreferUpAxis then
  583. FRotAxis := VectorNormalize(VectorCrossProduct(
  584. VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
  585. else
  586. FRotAxis := Right
  587. else
  588. // if Angle equals 180 degrees.
  589. if FAngle >Pi - cEPSILON then
  590. if PreferUpAxis then
  591. FRotAxis := VectorNormalize(VectorCrossProduct(VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
  592. else
  593. FRotAxis := Right
  594. else
  595. FRotAxis:= VectorNormalize(VectorCrossProduct(FFinalPos, FInitialPos));
  596. end;
  597. procedure TGLOrbitToPosAdvJob.Step;
  598. var
  599. tempUp, tempDir, tempPos : TVector;
  600. begin
  601. if FElapsedTime < FProceedTime then
  602. begin
  603. //Compute Position
  604. tempPos := FInitialPos;
  605. RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  606. FJobList.FController.FCamera.AbsolutePosition := VectorAdd(FJobList.FController.FCameraTarget.AbsolutePosition, tempPos);
  607. //Compute Direction vector
  608. tempDir := FInitialDir;
  609. RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  610. FJobList.FController.FCamera.AbsoluteDirection := tempDir;
  611. //Compute Up Vector
  612. tempUp := FInitialUp;
  613. RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  614. FJobList.FController.FCamera.AbsoluteUp := tempUp;
  615. end
  616. else
  617. begin
  618. //Compute Position
  619. tempPos := FInitialPos;
  620. RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle);
  621. FJoblist.FController.FCamera.AbsolutePosition := VectorAdd(
  622. FJoblist.FController.FCameraTarget.AbsolutePosition, tempPos);
  623. //Compute Direction vector
  624. tempDir := FInitialDir;
  625. RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle);
  626. FJoblist.FController.FCamera.AbsoluteDirection := tempDir;
  627. //Compute Up Vector
  628. tempUp := FInitialUp;
  629. RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle);
  630. FJoblist.FController.FCamera.AbsoluteUp := tempUp;
  631. FRunning := false;
  632. end;
  633. end;
  634. { TGLSmoothOrbitToPosAdvJob }
  635. procedure TGLSmoothOrbitToPosAdvJob.Init;
  636. var
  637. Right: TVector;
  638. begin
  639. FProceedTime := time;
  640. FInitialPos:= VectorSubtract(FPreviousPosition, FJobList.FController.FCameraTarget.AbsolutePosition);
  641. if Assigned(FJobList.FController.FCamera.Parent) then
  642. FFinalPos := VectorSubtract(FJobList.FController.FCamera.Parent.LocalToAbsolute(VectorMake(x,y,z,1)), FJobList.FController.FCameraTarget.AbsolutePosition)
  643. else
  644. FFinalPos := VectorSubtract(VectorMake(x,y,z,1), FJobList.FController.FCameraTarget.AbsolutePosition);
  645. //if destination is Target Pos, we can't compute
  646. if VectorLength(FFinalPos)<cEPSILON then
  647. begin
  648. //FAllowUserAction := True;
  649. Exit;
  650. end;
  651. //Compute Angle of Rotation
  652. FAngle:= ArcCos(VectorAngleCosine(Vector3fMake(FFinalPos), Vector3fMake(FInitialPos)));
  653. Right := VectorNormalize(VectorCrossProduct(
  654. // FJobList.FController.FCamera.AbsoluteVectorToTarget,
  655. VectorNormalize(VectorSubtract(FJobList.FController.FCameraTarget.AbsolutePosition, FPreviousPosition)),
  656. FJobList.FController.FCamera.AbsoluteUp));
  657. FInitialDir := FJobList.FController.FCamera.AbsoluteDirection;
  658. FInitialUp := FJobList.FController.FCamera.AbsoluteUp;
  659. // Determine rotation Axis
  660. // if Angle equals 0 degrees.
  661. if FAngle < cEPSILON then
  662. if PreferUpAxis then
  663. FRotAxis := VectorNormalize(VectorCrossProduct(
  664. VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
  665. else
  666. FRotAxis := Right
  667. else
  668. // if Angle equals 180 degrees.
  669. if FAngle >Pi - cEPSILON then
  670. if PreferUpAxis then
  671. FRotAxis := VectorNormalize(VectorCrossProduct(VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
  672. else
  673. FRotAxis := Right
  674. else
  675. FRotAxis:= VectorNormalize(VectorCrossProduct(FFinalPos, FInitialPos));
  676. end;
  677. procedure TGLSmoothOrbitToPosAdvJob.Step;
  678. var
  679. tempUp, tempDir, tempPos : TVector;
  680. begin
  681. if FElapsedTime < FProceedTime then
  682. begin
  683. //Compute Position
  684. tempPos := FInitialPos;
  685. RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  686. FSmoothNavigator.TargetValue.DirectVector := VectorAdd(FJobList.FController.FCameraTarget.AbsolutePosition, tempPos);
  687. FPreviousPosition := FSmoothNavigator.TargetValue.DirectVector;
  688. //Compute Direction vector
  689. tempDir := FInitialDir;
  690. RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  691. FJobList.FController.FCamera.AbsoluteDirection := tempDir;
  692. //Compute Up Vector
  693. if FRestoreUpVector then
  694. FJobList.FController.FCamera.AbsoluteUp := FInitialUp
  695. else
  696. begin
  697. tempUp := FInitialUp;
  698. RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
  699. FJobList.FController.FCamera.AbsoluteUp := tempUp;
  700. end;
  701. end
  702. else
  703. begin
  704. //Compute Position
  705. tempPos := FInitialPos;
  706. RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle);
  707. FJoblist.FController.FCamera.AbsolutePosition := VectorAdd(
  708. FJoblist.FController.CameraTarget.AbsolutePosition, tempPos);
  709. //Compute Direction vector
  710. tempDir := FInitialDir;
  711. RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle);
  712. FJoblist.FController.FCamera.AbsoluteDirection := tempDir;
  713. //Compute Up Vector
  714. if FRestoreUpVector then
  715. FJoblist.FController.FCamera.AbsoluteUp := FInitialUp
  716. else
  717. begin
  718. tempUp := FInitialUp;
  719. RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle);
  720. FJoblist.FController.FCamera.AbsoluteUp := tempUp;
  721. FRunning := false;
  722. end;
  723. FRunning := false;
  724. end;
  725. end;
  726. { TGLSmoothOrbitToPosAdv }
  727. constructor TGLSmoothOrbitToPos.Create(const AJoblist: TGLCameraJobList);
  728. begin
  729. inherited;
  730. FCutoffAngle := 0.1;
  731. end;
  732. procedure TGLSmoothOrbitToPos.Step;
  733. var
  734. lCurrentDistanceToTarget: Single;
  735. lTargetPosition: TVector;
  736. lCurrentMatrix: TMatrix;
  737. lAngle: Single;
  738. lAbsTargetPosition: TVector;
  739. procedure RestoreDistanceToTarget();
  740. var
  741. lDirection: TVector;
  742. begin
  743. lDirection := VectorNormalize(VectorSubtract(
  744. FJobList.FController.FCameraTarget.AbsolutePosition,
  745. FJobList.FController.FCamera.AbsolutePosition));
  746. FJobList.FController.FCamera.AbsolutePosition := VectorAdd(
  747. FJobList.FController.FCameraTarget.AbsolutePosition,
  748. VectorScale(lDirection, - lCurrentDistanceToTarget));
  749. end;
  750. procedure SetTargetValueRelative(const AAbsolutePosition: TVector);
  751. begin
  752. if FJobList.FController.FCamera.Parent = nil then
  753. FSmoothNavigator.TargetValue.DirectVector := AAbsolutePosition
  754. else
  755. FSmoothNavigator.TargetValue.DirectVector := FJobList.FController.FCamera.Parent.AbsoluteToLocal(AAbsolutePosition);
  756. end;
  757. procedure ApplyDistanceToResult();
  758. var
  759. lDirection, lNewTargetPosition: TVector;
  760. begin
  761. lDirection := VectorNormalize(VectorSubtract(
  762. FJobList.FController.FCameraTarget.AbsolutePosition,
  763. lAbsTargetPosition));
  764. lNewTargetPosition := VectorAdd(
  765. FJobList.FController.FCameraTarget.AbsolutePosition,
  766. VectorScale(lDirection, - lCurrentDistanceToTarget));
  767. SetTargetValueRelative(lNewTargetPosition);
  768. end;
  769. begin
  770. if FElapsedTime < FProceedTime then
  771. begin
  772. // Save current matrix.
  773. lCurrentMatrix := FJobList.FController.FCamera.Matrix^;
  774. if FNeedToRecalculateZoom then
  775. lCurrentDistanceToTarget := FJobList.FController.FCamera.DistanceTo(FJobList.FController.FCameraTarget)
  776. else
  777. lCurrentDistanceToTarget := 0; // To avoid warning message.
  778. // Calculate the position, in which camera should have been.
  779. FJobList.FController.FCamera.SetMatrix(FShouldBeMatrix);
  780. FJobList.FController.FCamera.AbsolutePosition := MoveObjectAround(
  781. FJobList.FController.FCamera.AbsolutePosition, FCameraUpVector,
  782. FJobList.FController.FCameraTarget.AbsolutePosition,
  783. FRotateSpeed.X * FDeltaTime, FRotateSpeed.Y * FDeltaTime);
  784. if FNeedToRecalculateZoom then
  785. RestoreDistanceToTarget();
  786. lTargetPosition := FJobList.FController.FCamera.AbsolutePosition;
  787. FShouldBeMatrix := FJobList.FController.FCamera.Matrix^;
  788. // Restore Camera position and move it to the desired vector.
  789. FJobList.FController.FCamera.SetMatrix(lCurrentMatrix);
  790. SetTargetValueRelative(lTargetPosition);
  791. end
  792. else
  793. begin
  794. if FNeedToRecalculateZoom then
  795. begin
  796. if FJobList.FController.FCamera.Parent = nil then
  797. lAbsTargetPosition := FFinalPos
  798. else
  799. lAbsTargetPosition := FJobList.FController.FCamera.Parent.LocalToAbsolute(FFinalPos);
  800. lAngle := RadToDeg(AngleBetweenVectors(FJobList.FController.FCamera.AbsolutePosition,
  801. lAbsTargetPosition, FJobList.FController.FCameraTarget.AbsolutePosition));
  802. if lAngle < FCutoffAngle then
  803. begin
  804. FSmoothNavigator.Enabled := False;
  805. FRunning := False;
  806. end
  807. else
  808. begin
  809. lCurrentDistanceToTarget := FJobList.FController.FCamera.DistanceTo(FJobList.FController.FCameraTarget);
  810. ApplyDistanceToResult();
  811. end;
  812. end
  813. else
  814. begin
  815. FSmoothNavigator.TargetValue.DirectVector := FFinalPos;
  816. FRunning := False;
  817. end;
  818. end;
  819. end;
  820. end.