2
// This unit is part of the GLScene Engine https://github.com/glscene
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
10
30/06/11 - DaStr - [Smooth]OrbitToPos now correctly uses local and absolute coordinates
11
Camera is now a TGLBaseSceneObject
12
Added CameraTarget property
13
Most procedures now use "const" parameters
14
Restructured TGLCameraJob: published some properties, deleted others
15
Added basic Notification
16
Removed Cadencer dependancy
17
14/06/11 - Vince - Correct positioning errors (OrbitToPosAdvance)
18
07/05/11 - DaStr - Added Smooth OrbitToPos support
19
20/05/11 - YanP - GLCameraController refactored as a Job manager, each camera movement is a job in a list
20
10/05/11 - Vince - Add OnMove event
21
04/05/11 - Vince - Add OrbitToPosAdvanced function to support OrbitToPos when axis are different from -1,0 or 1
22
24/07/09 - DaStr - Got rid of compiler hints
23
20/03/09 - DanB - Donated to GLScene by Bogdan Deaky.
27
//GLCameraController v1.1
28
//Bogdan Deaky / Bluemind Software
29
//Bluemind Software allows free usage and distribution of this component
30
//Do let the author know if you do code changes/improvements
31
//bogdan@bluemind-software.ro
33
//v1.1 2009 (for GLScene, ships with glscene_icon_TGLCameraController.bmp)
37
//You should block user GUI access to the GLSceneViewer
38
//while movement is being done, check the AllowUserAction property!
39
//Block user GUI access while AllowUserAction is false to avoid behaviour errors
41
//if GLCameraController1.AllowUserAction then
42
// //do whatever you want on mouse move, form wheel etc
44
// methods and properties are explained in the interface section (through comments)
45
// additional comments might apear in implementation section where needed
47
unit GLCameraController;
52
GLScene, Classes, SysUtils, Contnrs, GLVectorGeometry,
53
GLSmoothNavigator {$IFNDEF GLS_DELPHI},GLVectorTypes{$ENDIF};
57
EGLCameraController = class(Exception);
59
// Forward declaration of the camera controller main class
60
TGLCameraController = class;
62
// Forward declaration of a generic camera job
65
TGLCameraJobList = class(TObjectList)
67
FController : TGLCameraController;
68
function GetCameraJob(const AIndex: integer): TGLCameraJob;
69
procedure SetCameraJob(const AIndex: integer; const Value: TGLCameraJob);
71
constructor Create(AController: TGLCameraController);
72
function Add(ACameraJob: TGLCameraJob): integer;
73
property Items[const AIndex: integer]: TGLCameraJob read GetCameraJob write SetCameraJob; default;
74
function First: TGLCameraJob;
75
function Last: TGLCameraJob;
78
TGLCameraJob = class(TObject)
80
FJoblist : TGLCameraJobList;
86
FElapsedTime : Double;
89
FProceedTime : Double;
91
constructor Create(const AJoblist : TGLCameraJobList); virtual;
92
destructor Destroy; override;
95
procedure Step; virtual; abstract;
96
procedure Init; virtual; abstract;
98
property Running: Boolean read FRunning write FRunning;
99
property ElapsedTime: Double read FElapsedTime write FElapsedTime;
100
property StartTime: Double read FStartTime write FStartTime;
101
property ProceedTime: Double read FProceedTime write FProceedTime;
104
TGLMoveToPosJob = class(TGLCameraJob)
106
FInitialPos : TVector;
113
procedure Step; override;
114
procedure Init; override;
117
property InitialPos: TVector read FInitialPos;
118
property FinalPos: TVector read FFinalPos;
121
TGLZoomToDistanceJob = class(TGLCameraJob)
123
FInitialPos : TVector;
128
procedure Step; override;
129
procedure Init; override;
132
property InitialPos: TVector read FInitialPos;
133
property FinalPos: TVector read FFinalPos;
136
TGLOrbitToPosJob = class(TGLCameraJob)
138
FFinalPos: TVector; // Yep, FFinalPos is stored in relative coordinates.
139
FRotateSpeed: TVector2f;
140
FCameraUpVector: TVector;
142
// Absolute Coordinates, can even be not normalized by radius.
143
// Procesed in Init, not used anywhere else.
144
FTargetPosition: TVector;
147
procedure Step; override;
148
procedure Init; override;
151
property RotateSpeed: TVector2f read FRotateSpeed;
152
property CameraUpVector: TVector read FCameraUpVector;
153
property TargetPosition: TVector read FTargetPosition;
154
property FinalPos: TVector read FFinalPos;
155
property Time: Double read FTime;
158
TGLSmoothOrbitToPos = class(TGLOrbitToPosJob)
160
FCutoffAngle: Single;
161
FNeedToRecalculateZoom: Boolean;
162
FShouldBeMatrix: TMatrix;
163
FSmoothNavigator: TGLNavigatorSmoothChangeVector;
165
constructor Create(const AJoblist : TGLCameraJobList); override;
166
procedure Step; override;
167
property CutoffAngle: Single read FCutoffAngle write FCutoffAngle;
168
property NeedToRecalculateZoom: Boolean read FNeedToRecalculateZoom write FNeedToRecalculateZoom;
171
TGLOrbitToPosAdvJob = class(TGLCameraJob)
173
FInitialPos : TVector;
175
FInitialUp : TVector;
176
FInitialDir : TVector;
185
PreferUpAxis : Boolean;
186
procedure Step; override;
187
procedure Init; override;
190
property InitialPos: TVector read FInitialPos;
191
property InitialUp: TVector read FInitialUp;
192
property InitialDir: TVector read FInitialDir;
193
property FinalPos: TVector read FFinalPos;
196
TGLSmoothOrbitToPosAdvJob = class(TGLOrbitToPosAdvJob)
198
FPreviousPosition: TVector;
199
FSmoothNavigator: TGLNavigatorSmoothChangeVector;
200
FRestoreUpVector: Boolean;
202
procedure Step; override;
203
procedure Init; override;
206
TGLCameraJobEvent = procedure(Sender : TGLCameraJob) of object;
208
TGLCameraController = class(TComponent)
211
FCameraJobList : TGLCameraJobList;
212
FCamera: TGLBaseSceneObject;
213
FCameraTarget: TGLBaseSceneObject;
216
FOnJobAdded: TGLCameraJobEvent;
217
FOnJobFinished: TGLCameraJobEvent;
218
FOnJobStep: TGLCameraJobEvent;
220
//fields used by SafeOrbitAndZoomToPos
221
FsoSafeDist, FsoTimeToSafePlacement, FsoTimeToOrbit, FsoTimeToZoomBackIn:double;
224
//used to test whether camera and cadencer are assigned
225
//Extended = true -> will test also for Camera.TargetObject
226
procedure CheckAssignments(Extended: boolean);
228
//after AdjustScene the Camera.DepthofView will be modified
229
//if you want to zoom back in from GUI
230
//you should use something like
231
// Camera.DepthOfView:=2*Camera.DistanceToTarget+2*camera.TargetObject.BoundingSphereRadius;
232
procedure SetOnJobAdded(const Value: TGLCameraJobEvent);
233
procedure SetOnJobFinished(const Value: TGLCameraJobEvent);
234
procedure SetOnJobStep(const Value: TGLCameraJobEvent);
235
procedure SetCamera(const Value: TGLBaseSceneObject);
236
procedure SetCameraTarget(const Value: TGLBaseSceneObject);
238
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
241
constructor Create(AOwner:TComponent); override;
242
destructor Destroy; override;
245
//linear movement from current pos
246
function MoveToPos(x,y,z,time:double): TGLMoveToPosJob;
248
//orbiting from current pos to the pos where
249
//the camera points at the camera.targetObject TROUGH the given point
250
//it will not move to the given point(!), use SafeOrbitAndZoomToPos instead
251
//there has to be a camera.targetObject assigned!
252
function OrbitToPos(x,y,z,time:double): TGLOrbitToPosJob;
254
// Same as OrbitToPos(), but makes use of SmoothNavigator to make
255
// sure all camera movements are smooth.
256
function OrbitToPosSmooth(const ATargetPosition: TVector; const ATime: Double;
257
const ASmoothNavigator: TGLNavigatorSmoothChangeVector; const AFNeedToRecalculateZoom: Boolean;
258
const ACameraUpVector: PVector = nil): TGLSmoothOrbitToPos;
260
//Same function as OrbitToPos but support all camera states
261
//PreferUpAxis value is to setup if function use Camera Up based rotation axis
262
//instead of Camera direction based rotation axis when destination and camera
263
//position are opposite from Camera Target
264
function OrbitToPosAdvanced(x,y,z,time:double; PreferUpAxis: Boolean = True): TGLOrbitToPosAdvJob;
267
// Same as OrbitToPosAdvanced(), but makes use of SmoothNavigator to make
268
// sure all camera movements are smooth.
269
function OrbitToPosAdvancedSmooth(const x,y,z, time: double;
270
const ASmoothNavigator: TGLNavigatorSmoothChangeVector;
271
const PreferUpAxis: Boolean = True): TGLSmoothOrbitToPosAdvJob;
273
//zooms in/out by moving to the given distance from camera.targetObject
274
//there has to be a camera.targetObject assigned!
275
function ZoomToDistance(Distance,Time:double): TGLZoomToDistanceJob;
277
//google earth - like "fly-to"
278
// = zoom out to safe distance, orbit, and then zoom in to the given point
279
//there has to be a camera.targetObject assigned!
280
procedure SafeOrbitAndZoomToPos(x,y,z:double);
282
//Dan Bartlett said in the GLScene newsgroup that it might be a good idea
283
//to introduce ability to stop movement and return control to user
285
procedure StopMovement;
287
// Called by the cadencer to animate the camera
288
procedure Step(const deltaTime, newTime: Double);
290
property CameraJobList: TGLCameraJobList read FCameraJobList;
292
// Moving object (usually a TGLCamera).
293
property Camera: TGLBaseSceneObject read FCamera write SetCamera;
295
// Target, around which Moving object should rotate(usually TGLCamera.TargetObject).
296
property CameraTarget: TGLBaseSceneObject read FCameraTarget write SetCameraTarget;
298
//specifies whether user should be able interract with the GLSceneViewer
299
//it is set to false while the camera is moving and
300
//coders should check this value and block GUI access to GLSceneViewer
301
//property AllowUserAction:boolean read FAllowUserAction;
303
//safe distance to avoid moving the camera trough the camera.targetObject
304
//while performing SafeOrbitAndZoomToPos
305
property soSafeDistance:double read FsoSafeDist write FsoSafeDist;
306
//time to zoom in/out to the safe position while performing SafeOrbitAndZoomToPos
307
property soTimeToSafePlacement:double read FsoTimeToSafePlacement write FsoTimeToSafePlacement;
308
//time to orbit while performing SafeOrbitAndZoomToPos
309
property soTimeToOrbit:double read FsoTimeToOrbit write FsoTimeToOrbit;
310
//time to zoom in/out to the given final position while performing SafeOrbitAndZoomToPos
311
property soTimeToZoomBackIn:double read FsoTimeToZoomBackIn write FsoTimeToZoomBackIn;
313
//this event is triggered when a job is init
314
property OnJobAdded : TGLCameraJobEvent read FOnJobAdded write SetOnJobAdded;
316
//this event is triggered when a job is step (like an OnMove)
317
property OnJobStep : TGLCameraJobEvent read FOnJobStep write SetOnJobStep;
319
//this event is triggered when a job is finished (not canceled)
320
property OnJobFinished : TGLCameraJobEvent read FOnJobFinished write SetOnJobFinished;
327
cGLCAMERACONTROLLER_CHECK_EXTENDED = TRUE;
330
{ TGLCameraController }
332
constructor TGLCameraController.Create(AOwner:TComponent);
335
//create the job list container
336
FCameraJobList := TGLCameraJobList.Create(Self);
337
FCameraJobList.OwnsObjects := true;
341
soTimeToSafePlacement:=1;
343
soTimeToZoomBackIn:=1;
346
destructor TGLCameraController.Destroy;
348
//delete job list and all jobs inside
354
procedure TGLCameraController.CheckAssignments(Extended:boolean);
356
/// Check camera assignment
357
if not Assigned(FCamera) then
359
Raise EGLCameraController.CreateFmt('%s (%s) needs to have a Camera assigned',[Self.Name, Self.ClassName]);
363
/// Check camera;TargetObject assignment
364
if not Assigned(FCameraTarget) then
366
Raise EGLCameraController.CreateFmt('%s (%s) needs Camera to have a TargetObject assigned',[Self.Name, Self.ClassName]);
370
procedure TGLCameraController.Step(const deltaTime, newTime: Double);
372
CurrentJob : TGLCameraJob;
375
if FCameraJobList.Count > 0 then
377
CurrentJob := FCameraJobList.First;
379
if CurrentJob.FInit then
382
CurrentJob.FStartTime := newTime;
383
CurrentJob.FRunning := True;
384
CurrentJob.FInit := False;
387
if Assigned(FOnJobAdded) then
388
FOnJobAdded(CurrentJob);
391
if CurrentJob.FRunning then
393
CurrentJob.FElapsedTime := newTime - CurrentJob.FStartTime;
394
CurrentJob.FDeltaTime := deltaTime;// newTime - CurrentJob.FElapsedTime;
398
if Assigned(FOnJobStep) then
399
FOnJobStep(CurrentJob);
402
if not CurrentJob.FRunning then
404
FCameraJobList.Remove(CurrentJob);
407
if Assigned(FOnJobFinished) then
408
FOnJobFinished(CurrentJob);
417
function TGLCameraController.MoveToPos(x,y,z, time:double): TGLMoveToPosJob;
419
Result := TGLMoveToPosJob.Create(FCameraJobList);
428
function TGLCameraController.ZoomToDistance(Distance, Time:double): TGLZoomToDistanceJob;
430
Result := TGLZoomToDistanceJob.Create(FCameraJobList);
431
Result.Distance := Distance;
436
function TGLCameraController.OrbitToPos(x,y,z,time:double): TGLOrbitToPosJob;
438
Result := TGLOrbitToPosJob.Create(FCameraJobList);
439
Result.FTargetPosition := PointMake(x, y, z);
440
Result.FCameraUpVector := FCameraJobList.FController.FCamera.AbsoluteUp;
441
Result.FTime := time;
445
function TGLCameraController.OrbitToPosSmooth(const ATargetPosition: TVector; const ATime: Double;
446
const ASmoothNavigator: TGLNavigatorSmoothChangeVector; const AFNeedToRecalculateZoom: Boolean;
447
const ACameraUpVector: PVector = nil): TGLSmoothOrbitToPos;
449
Result := TGLSmoothOrbitToPos.Create(FCameraJobList);
451
Result.FTargetPosition := ATargetPosition;
452
Result.FTime := ATime;
453
Result.FSmoothNavigator := ASmoothNavigator;
454
Result.FShouldBeMatrix := FCameraJobList.FController.FCamera.Matrix;
455
Result.FNeedToRecalculateZoom := AFNeedToRecalculateZoom;
456
if ACameraUpVector = nil then
457
Result.FCameraUpVector := FCameraJobList.FController.FCamera.AbsoluteUp
459
Result.FCameraUpVector := ACameraUpVector^;
462
function TGLCameraController.OrbitToPosAdvanced(x,y,z,time:double; PreferUpAxis: Boolean = True): TGLOrbitToPosAdvJob;
464
Result := TGLOrbitToPosAdvJob.Create(FCameraJobList);
469
Result.PreferUpAxis := PreferUpAxis;
473
function TGLCameraController.OrbitToPosAdvancedSmooth(const x,y,z, time: double;
474
const ASmoothNavigator: TGLNavigatorSmoothChangeVector; const PreferUpAxis: Boolean = True): TGLSmoothOrbitToPosAdvJob;
476
Result := TGLSmoothOrbitToPosAdvJob.Create(FCameraJobList);
481
Result.PreferUpAxis := PreferUpAxis;
483
Result.FSmoothNavigator := ASmoothNavigator;
484
Result.FPreviousPosition := ASmoothNavigator.OnGetCurrentValue(ASmoothNavigator);
485
Result.FRestoreUpVector := True;
488
procedure TGLCameraController.SafeOrbitAndZoomToPos(x,y,z:double);
490
//this was the main purpose of this component
491
//as you can see, it actually is a combination of the other 3 methods
492
CheckAssignments(cGLCAMERACONTROLLER_CHECK_EXTENDED);
493
ZoomToDistance(soSafeDistance,soTimeToSafePlacement);
494
OrbitToPos(x,y,z,soTimeToOrbit);
495
MoveToPos(x,y,z,soTimeToZoomBackIn);
499
procedure TGLCameraController.StopMovement;
501
FCameraJobList.Clear;
505
procedure TGLCameraController.SetOnJobAdded(const Value: TGLCameraJobEvent);
507
FOnJobAdded := Value;
510
procedure TGLCameraController.SetOnJobStep(const Value: TGLCameraJobEvent);
515
procedure TGLCameraController.SetOnJobFinished(const Value: TGLCameraJobEvent);
517
FOnJobFinished := Value;
520
procedure TGLCameraController.SetCamera(const Value: TGLBaseSceneObject);
522
if FCamera <> nil then FCamera.RemoveFreeNotification(Self);
524
if FCamera <> nil then FCamera.FreeNotification(Self);
526
if (FCamera is TGLCamera) and (FCameraTarget = nil) then
527
SetCameraTarget(TGLCamera(FCamera).TargetObject);
530
procedure TGLCameraController.SetCameraTarget(
531
const Value: TGLBaseSceneObject);
533
if FCameraTarget <> nil then FCameraTarget.RemoveFreeNotification(Self);
534
FCameraTarget := Value;
535
if FCameraTarget <> nil then FCameraTarget.FreeNotification(Self);
538
procedure TGLCameraController.Notification(AComponent: TComponent;
539
Operation: TOperation);
542
if Operation = opRemove then
544
if AComponent = FCamera then
546
else if AComponent = FCameraTarget then
547
FCameraTarget := nil;
554
constructor TGLCameraJobList.Create(AController: TGLCameraController);
557
FController := AController;
560
function TGLCameraJobList.GetCameraJob(const AIndex: integer): TGLCameraJob;
562
Result := inherited Get(AIndex);
565
procedure TGLCameraJobList.SetCameraJob(const AIndex: integer;
566
const Value: TGLCameraJob);
568
inherited Put(AIndex, Value);
571
function TGLCameraJobList.Add(ACameraJob: TGLCameraJob): integer;
573
Result := inherited Add(ACameraJob);
576
function TGLCameraJobList.First: TGLCameraJob;
578
Result := TGLCameraJob(inherited First);
581
function TGLCameraJobList.Last: TGLCameraJob;
583
Result := TGLCameraJob(inherited Last);
588
constructor TGLCameraJob.Create(const AJoblist : TGLCameraJobList);
590
FJoblist := AJoblist;
598
destructor TGLCameraJob.Destroy;
604
procedure TGLCameraJob.Abort;
612
procedure TGLMoveToPosJob.Init;
614
FProceedTime := Time;
615
FInitialPos := VectorSubtract(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition);
616
MakeVector(FFinalPos, X, Y, Z);
619
procedure TGLMoveToPosJob.Step;
623
if FElapsedTime < FProceedTime then
625
Vect := VectorLerp(FInitialPos, FFinalPos, FElapsedTime/FProceedTime);
633
if Assigned(FJobList.FController.FCamera.Parent) then
634
Vect:=FJobList.FController.FCamera.Parent.AbsoluteToLocal(Vect);
636
FJobList.FController.FCamera.Position.AsVector := Vect;
639
{ TGLZoomToDistanceJob }
641
procedure TGLZoomToDistanceJob.Init;
643
FProceedTime := Time;
644
FInitialPos := VectorSubtract(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition);
645
// To determine final position, we normalize original position and scale it with final distance
646
SetVector(FFinalPos, FInitialPos);
647
NormalizeVector(FFinalPos);
648
ScaleVector(FFinalPos, Distance);
651
procedure TGLZoomToDistanceJob.Step;
655
if FElapsedTime < FProceedTime then
657
Vect := VectorLerp(FInitialPos, FFinalPos, FElapsedTime/FProceedTime);
665
if Assigned(FJobList.FController.FCamera.Parent) then
666
Vect:=FJobList.FController.FCamera.Parent.AbsoluteToLocal(Vect);
668
FJobList.FController.FCamera.Position.AsVector := Vect;
676
procedure TGLOrbitToPosJob.Init;
678
FProceedTime := FTime;
680
FFinalPos := ShiftObjectFromCenter(FTargetPosition, FJobList.FController.FCameraTarget.AbsolutePosition,
681
VectorDistance(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition), True);
683
// Yep, FFinalPos is stored in relative coordinates.
684
if FJobList.FController.FCamera.Parent <> nil then
685
FFinalPos := FJobList.FController.FCamera.Parent.AbsoluteToLocal(FFinalPos);
687
FRotateSpeed := GLVectorGeometry.GetSafeTurnAngle(
688
FJobList.FController.FCamera.AbsolutePosition, FCameraUpVector, FTargetPosition,
689
FJobList.FController.FCameraTarget.AbsolutePosition);
691
ScaleVector(FRotateSpeed, 1 / FProceedTime);
696
procedure TGLOrbitToPosJob.Step;
699
if FElapsedTime < FProceedTime then
701
FJobList.FController.FCamera.AbsolutePosition := MoveObjectAround(
702
FJobList.FController.FCamera.AbsolutePosition, FCameraUpVector,
703
FJobList.FController.FCameraTarget.AbsolutePosition,
704
FRotateSpeed.V[0] * FDeltaTime, FRotateSpeed.V[1] * FDeltaTime);
708
// Yep, FFinalPos is stored in ralative coordinates.
709
FJobList.FController.FCamera.Position.AsVector := FFinalPos;
716
{ TGLOrbitToPosAdvJob }
718
procedure TGLOrbitToPosAdvJob.Init;
721
lAbsVectorToTarget: TVector;
724
FProceedTime := time;
725
FInitialPos := VectorSubtract(FJobList.FController.FCamera.AbsolutePosition, FJobList.FController.FCameraTarget.AbsolutePosition);
727
if Assigned(FJobList.FController.FCamera.Parent) then
728
FFinalPos := VectorSubtract(FJobList.FController.FCamera.Parent.LocalToAbsolute(VectorMake(x,y,z,1)), FJobList.FController.FCameraTarget.AbsolutePosition)
730
FFinalPos := VectorSubtract(VectorMake(x,y,z,1), FJobList.FController.FCameraTarget.AbsolutePosition);
732
//if destination is Target Pos, we can't compute
733
if VectorLength(FFinalPos)<cEPSILON then
735
//FAllowUserAction := True;
739
//Compute Angle of Rotation
740
FAngle:= ArcCos(VectorAngleCosine(Vector3fMake(FFinalPos), Vector3fMake(FInitialPos)));
742
lAbsVectorToTarget := VectorNormalize(VectorSubtract(
743
FJobList.FController.FCameraTarget.AbsolutePosition,
744
FJobList.FController.FCamera.AbsolutePosition));
746
Right := VectorNormalize(VectorCrossProduct(lAbsVectorToTarget, FJobList.FController.FCamera.AbsoluteUp));
748
FInitialDir := FJobList.FController.FCamera.AbsoluteDirection;
749
FInitialUp := FJobList.FController.FCamera.AbsoluteUp;
751
// Determine rotation Axis
752
// if Angle equals 0 degrees.
753
if FAngle < cEPSILON then
755
FRotAxis := VectorNormalize(VectorCrossProduct(
756
VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
760
// if Angle equals 180 degrees.
761
if FAngle >Pi - cEPSILON then
763
FRotAxis := VectorNormalize(VectorCrossProduct(VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
767
FRotAxis:= VectorNormalize(VectorCrossProduct(FFinalPos, FInitialPos));
771
procedure TGLOrbitToPosAdvJob.Step;
773
tempUp, tempDir, tempPos : TVector;
776
if FElapsedTime < FProceedTime then
779
tempPos := FInitialPos;
780
RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
781
FJobList.FController.FCamera.AbsolutePosition := VectorAdd(FJobList.FController.FCameraTarget.AbsolutePosition, tempPos);
783
//Compute Direction vector
784
tempDir := FInitialDir;
785
RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
786
FJobList.FController.FCamera.AbsoluteDirection := tempDir;
789
tempUp := FInitialUp;
790
RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
791
FJobList.FController.FCamera.AbsoluteUp := tempUp;
796
tempPos := FInitialPos;
797
RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle);
798
FJoblist.FController.FCamera.AbsolutePosition := VectorAdd(
799
FJoblist.FController.FCameraTarget.AbsolutePosition, tempPos);
801
//Compute Direction vector
802
tempDir := FInitialDir;
803
RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle);
804
FJoblist.FController.FCamera.AbsoluteDirection := tempDir;
807
tempUp := FInitialUp;
808
RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle);
809
FJoblist.FController.FCamera.AbsoluteUp := tempUp;
816
{ TGLSmoothOrbitToPosAdvJob }
818
procedure TGLSmoothOrbitToPosAdvJob.Init;
822
FProceedTime := time;
823
FInitialPos:= VectorSubtract(FPreviousPosition, FJobList.FController.FCameraTarget.AbsolutePosition);
825
if Assigned(FJobList.FController.FCamera.Parent) then
826
FFinalPos := VectorSubtract(FJobList.FController.FCamera.Parent.LocalToAbsolute(VectorMake(x,y,z,1)), FJobList.FController.FCameraTarget.AbsolutePosition)
828
FFinalPos := VectorSubtract(VectorMake(x,y,z,1), FJobList.FController.FCameraTarget.AbsolutePosition);
830
//if destination is Target Pos, we can't compute
831
if VectorLength(FFinalPos)<cEPSILON then
833
//FAllowUserAction := True;
837
//Compute Angle of Rotation
838
FAngle:= ArcCos(VectorAngleCosine(Vector3fMake(FFinalPos), Vector3fMake(FInitialPos)));
840
Right := VectorNormalize(VectorCrossProduct(
841
// FJobList.FController.FCamera.AbsoluteVectorToTarget,
842
VectorNormalize(VectorSubtract(FJobList.FController.FCameraTarget.AbsolutePosition, FPreviousPosition)),
843
FJobList.FController.FCamera.AbsoluteUp));
845
FInitialDir := FJobList.FController.FCamera.AbsoluteDirection;
846
FInitialUp := FJobList.FController.FCamera.AbsoluteUp;
848
// Determine rotation Axis
849
// if Angle equals 0 degrees.
850
if FAngle < cEPSILON then
852
FRotAxis := VectorNormalize(VectorCrossProduct(
853
VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
857
// if Angle equals 180 degrees.
858
if FAngle >Pi - cEPSILON then
860
FRotAxis := VectorNormalize(VectorCrossProduct(VectorCrossProduct(FFinalPos, FInitialUp), FFinalPos))
864
FRotAxis:= VectorNormalize(VectorCrossProduct(FFinalPos, FInitialPos));
868
procedure TGLSmoothOrbitToPosAdvJob.Step;
870
tempUp, tempDir, tempPos : TVector;
873
if FElapsedTime < FProceedTime then
876
tempPos := FInitialPos;
877
RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
878
FSmoothNavigator.TargetValue.DirectVector := VectorAdd(FJobList.FController.FCameraTarget.AbsolutePosition, tempPos);
879
FPreviousPosition := FSmoothNavigator.TargetValue.DirectVector;
881
//Compute Direction vector
882
tempDir := FInitialDir;
883
RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
884
FJobList.FController.FCamera.AbsoluteDirection := tempDir;
887
if FRestoreUpVector then
888
FJobList.FController.FCamera.AbsoluteUp := FInitialUp
891
tempUp := FInitialUp;
892
RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle * FElapsedTime/FProceedTime);
893
FJobList.FController.FCamera.AbsoluteUp := tempUp;
899
tempPos := FInitialPos;
900
RotateVector(tempPos, Vector3fMake(FRotAxis), FAngle);
901
FJoblist.FController.FCamera.AbsolutePosition := VectorAdd(
902
FJoblist.FController.CameraTarget.AbsolutePosition, tempPos);
904
//Compute Direction vector
905
tempDir := FInitialDir;
906
RotateVector(tempDir, Vector3fMake(FRotAxis), FAngle);
907
FJoblist.FController.FCamera.AbsoluteDirection := tempDir;
910
if FRestoreUpVector then
911
FJoblist.FController.FCamera.AbsoluteUp := FInitialUp
914
tempUp := FInitialUp;
915
RotateVector(tempUp, Vector3fMake(FRotAxis), FAngle);
916
FJoblist.FController.FCamera.AbsoluteUp := tempUp;
924
{ TGLSmoothOrbitToPosAdv }
926
constructor TGLSmoothOrbitToPos.Create(const AJoblist: TGLCameraJobList);
932
procedure TGLSmoothOrbitToPos.Step;
934
lCurrentDistanceToTarget: Single;
935
lTargetPosition: TVector;
936
lCurrentMatrix: TMatrix;
938
lAbsTargetPosition: TVector;
940
procedure RestoreDistanceToTarget();
944
lDirection := VectorNormalize(VectorSubtract(
945
FJobList.FController.FCameraTarget.AbsolutePosition,
946
FJobList.FController.FCamera.AbsolutePosition));
948
FJobList.FController.FCamera.AbsolutePosition := VectorAdd(
949
FJobList.FController.FCameraTarget.AbsolutePosition,
950
VectorScale(lDirection, - lCurrentDistanceToTarget));
954
procedure SetTargetValueRelative(const AAbsolutePosition: TVector);
956
if FJobList.FController.FCamera.Parent = nil then
957
FSmoothNavigator.TargetValue.DirectVector := AAbsolutePosition
959
FSmoothNavigator.TargetValue.DirectVector := FJobList.FController.FCamera.Parent.AbsoluteToLocal(AAbsolutePosition);
962
procedure ApplyDistanceToResult();
964
lDirection, lNewTargetPosition: TVector;
966
lDirection := VectorNormalize(VectorSubtract(
967
FJobList.FController.FCameraTarget.AbsolutePosition,
968
lAbsTargetPosition));
970
lNewTargetPosition := VectorAdd(
971
FJobList.FController.FCameraTarget.AbsolutePosition,
972
VectorScale(lDirection, - lCurrentDistanceToTarget));
974
SetTargetValueRelative(lNewTargetPosition);
978
if FElapsedTime < FProceedTime then
980
// Save current matrix.
981
lCurrentMatrix := FJobList.FController.FCamera.Matrix;
983
if FNeedToRecalculateZoom then
984
lCurrentDistanceToTarget := FJobList.FController.FCamera.DistanceTo(FJobList.FController.FCameraTarget)
986
lCurrentDistanceToTarget := 0; // To avoid warning message.
988
// Calculate the position, in which camera should have been.
989
FJobList.FController.FCamera.Matrix := FShouldBeMatrix;
991
FJobList.FController.FCamera.AbsolutePosition := MoveObjectAround(
992
FJobList.FController.FCamera.AbsolutePosition, FCameraUpVector,
993
FJobList.FController.FCameraTarget.AbsolutePosition,
994
FRotateSpeed.V[0] * FDeltaTime, FRotateSpeed.V[1] * FDeltaTime);
996
if FNeedToRecalculateZoom then
997
RestoreDistanceToTarget();
999
lTargetPosition := FJobList.FController.FCamera.AbsolutePosition;
1000
FShouldBeMatrix := FJobList.FController.FCamera.Matrix;
1002
// Restore Camera position and move it to the desired vector.
1003
FJobList.FController.FCamera.Matrix := lCurrentMatrix;
1004
SetTargetValueRelative(lTargetPosition);
1008
if FNeedToRecalculateZoom then
1010
if FJobList.FController.FCamera.Parent = nil then
1011
lAbsTargetPosition := FFinalPos
1013
lAbsTargetPosition := FJobList.FController.FCamera.Parent.LocalToAbsolute(FFinalPos);
1015
lAngle := RadToDeg(AngleBetweenVectors(FJobList.FController.FCamera.AbsolutePosition,
1016
lAbsTargetPosition, FJobList.FController.FCameraTarget.AbsolutePosition));
1017
if lAngle < FCutoffAngle then
1019
FSmoothNavigator.Enabled := False;
1024
lCurrentDistanceToTarget := FJobList.FController.FCamera.DistanceTo(FJobList.FController.FCameraTarget);
1025
ApplyDistanceToResult();
1030
FSmoothNavigator.TargetValue.DirectVector := FFinalPos;