Camera

We support the usage of TCamera and TGorillaCamera component. Both components work almost the same currently, but in the future they could differ significantly.

You can select the camera components from IDE components palette or create them at runtime.

If cameras are loaded from files like FBX, DAE or G3D the framework will create instances of TGorillaCamera and link the TCameraDef definition in the Def property of the camera.

Due to hardcoded Firemonkey restrictions the NearPlane and FarPlane property of TGorillaCamera has no effect yet, but in future we will solve this issue.

uses
  Gorilla.Camera;
 
[...]
 
/// Create a camera at runtime and activate it for rendering
var FCamera : TGorillaCamera;
 
/// Create the camera and attach it to the viewport as child component
FCamera := TGorillaCamera.Create(GorillaViewport1);
FCamera.Parent := GorillaViewport1;
 
/// Is equivalent to "AngleOfView" property
FCamera.FOV := 45;
 
/// Set our new camera as active camera and disable design time camera
GorillaViewport1.Camera := FCamera;
GorillaViewport1.UsingDesignCamera := false;

Target

A very useful property of Firemonkey's TCamera component is the Target property. You can link the camera to another 3D object to always look at it. This will generate a view direction always towards the linked 3D object.

You can use this property for easy camera navigation in 3D space. Combine a camera component with a non-visual TDummy instance to navigate.

var FDummy : TDummy;
var FCamera : TGorillaCamera;
 
/// Create a dummy component
FDummy := TDummy.Create(GorillaViewport1);
FDummy.Parent := GorillaViewport1;
 
/// Create the camera and attach it to the dummy!
FCamera := TGorillaCamera.Create(FDummy);
FCamera.Parent := FDummy;
 
/// Set the dummy as viewing target and the camera will always look at it.
FCamera.Target := FDummy;
 
/// Set our camera as active camera and disable design time camera
GorillaViewport1.Camera := FCamera;
GorillaViewport1.UsingDesignCamera := false;

To navigate you can simple rotate the dummy around its y-axis and move the camera on y-axis up and down.

type
  TForm1 = class(TForm)
    GorillaViewport1: TGorillaViewport;
    FDummy: TDummy;
    FCamera: TGorillaCamera;
 
  private
    FIsMoving : Boolean;
    FLastPoint : TPointF;
 
    procedure DoOnViewportMouseUp(ASender : TObject; AButton : TMouseButton;
      AShift : TShiftState; X, Y : Single);
    procedure DoOnViewportMouseDown(ASender : TObject; AButton : TMouseButton;
      AShift : TShiftState; X, Y : Single);
    procedure DoOnViewportMouseMove(ASender : TObject; AShiftState : TShiftState;
      X, Y : Single);
  end;
 
  [...]
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  GorillaViewport1.OnMouseUp   := DoOnViewportMouseUp;
  GorillaViewport1.OnMouseDown := DoOnViewportMouseDown;
  GorillaViewport1.OnMouseMove := DoOnViewportMouseMove;
 
  [...]
end;
 
procedure TForm1.DoOnViewportMouseUp(ASender : TObject; AButton : TMouseButton;
  AShift : TShiftState; X, Y : Single);
begin
  FIsMoving := false;
end;
 
procedure TForm1.DoOnViewportMouseDown(ASender : TObject; AButton : TMouseButton;
  AShift : TShiftState; X, Y : Single);
begin
  FIsMoving  := true;
  FLastPoint := PointF(X, Y);
end;
 
procedure TForm1.DoOnViewportMouseMove(ASender : TObject; AShiftState : TShiftState;
  X, Y : Single);
var LDiff : TPointF;
begin
  if FIsMoving then
  begin
    if (ssLeft in AShiftState) then
    begin
      LDiff := PointF(X, Y) - FLastPoint;
 
      /// Rotate around y-axis if left-right mouse movement
      FDummy.RotationAngle.Y := FDummy.RotationAngle.Y + LDiff.X;
 
      /// Move up and down, if up-down mouse movement
      /// We scale pixel offset down by 0.1 to move slowly
      FCamera.Position.Y := FCamera.Position.Y - LDiff.Y * 0.1;
    end;
 
    /// finally store the last mouse position
    FLastPoint := PointF(X, Y);
  end;
end;

Frustum Culling

The viewing frustum is a geometric representation of the volume visible to the virtual camera. Naturally, objects outside this volume will not be visible in the final image, so they are discarded.

Read more about here: Frustum Culling

Smooth Camera Controller

Since version 0.8.4.2341 a TGorillaViewport component provides an embedded TGorillaSmoothCameraController component with automatic mouse feedback integration. This means: In case TGorillaViewport.UsingDesignCamera is set to TRUE, the viewport will register OnMouseDown, OnMouseUp and OnMouseMove events and forward those events to the embedded TGorillaSmoothCameraController.

This enables an easy-to-use mouse navigation for your 3D scene without any effort. The smooth camera controller supports the following control:

  • Rotation around Y-axis
  • Rotation around X-axis (moving up / down)
  • Zooming in / out
  • Shifting / Translating on X-, Y- and Z-axis

It is called “Smooth” because it moves smoothly and will not stop abruptly if user stops interacting. This provides a good user experience.

Nevertheless you're able to control this smoothness and the controller itself by a variety of properties:

Property Description
Types Enable or disable separated parts of the control. You're allowed to turn off/on rotation, movement, zooming and shifting. TGorillaSmoothCameraControlType = (scctRotateY, scctMoveY, scctZoom, scctShiftX, scctShiftY, scctShiftZ)
ImpulseLimitRotateLimit the maximum input values for the rotation impulse.
ImpulseLimitUpAndDownLimit the maximum input values for the up/down movement impulse.
ImpulseLimitZoomLimit the maximum input values for the zoom impulse.
IntensityRotateGet or set the intensity of camera rotation.
IntensityUpAndDownGet or set the intensity of camera up and down movement.
IntensityZoomGet or set the intensity of camera zoom.
DampingRotateGet or set the damping value of camera rotation impulse.
DampingUpAndDownGet or set the damping value of camera up/down movement impulse.
DampingZoomGet or set the damping value of camera zoom impulse.
LimitRotationMinGet or set the min value of camera rotation around Y axis.
LimitRotationMaxGet or set the max value of camera rotation around Y axis.
LimitUpAndDownMinGet or set the min value of camera up/down movement on Y axis.
LimitUpAndDownMaxGet or set the max value of camera up/down movement on Y axis.
LimitZoomMinGet or set the min value of camera zoom on Z axis.
LimitZoomMaxGet or set the min value of camera zoom on Z axis.
ShiftImpulseLimitGet or set the shifting impulse limit.
ShiftDampingGet or set the shifting impulse damping.
ShiftIntensityGet or set the intensity of shifting on X, Y and Z axis.
Camera Link a TCamera or TGorillaCamera to the controller. If no camera is linked, the controller will do nothing.
ViewportLink a viewport to the controller for automatic mouse event registration. If you do not link a viewport you have to call AddImpulse(), Zoom() and Shift() yourself.
ShowControllerActivate or deactivate a cube rendered at the position of the controller from the view of the attached camera.
IntervalGet or set the internal update interval.
EnabledEnable or disable work of controller.
OnBeforeModifyA callback event before a specific type of control (rotate, up/down, zoom, …) getting modified.
OnAfterModifyA callback event after a specific type of control (rotate, up/down, zoom, …) was modified.

To retrieve and modify the embedded camera and camera controller from a viewport you can use the following public functions of a TGorillaViewport instance.

Function
function GetDesignCamera() : TCamera;
function GetDesignCameraController() : TGorillaSmoothCameraController;

Creating a Smooth Controller at Runtime

Besides the embedded camera controller in the viewport, you can of course create your own at runtime or designtime.

If you link the controller to a viewport component, it will automatically setup the necessary mouse events for you. But you are also allowed to control it yourself, f.e. by Gamepad or Keyboard events. For manual controlling please leave the viewport property empty.

In the following code snippet we modify rotation manually in user-specific mouse events. We're also blocking shifting, because we only want to rotate the camera.

uses
  Gorilla.Camera;
 
[...]
 
type
  TForm1 = class(TForm)
    GorillaViewport1: TGorillaViewport;
    FCameraCtrl : TGorillaSmoothCameraController;
    FMyCamera : TGorillaCamera;
 
  private
    FIsMoving : Boolean;
    FLastPoint : TPointF;
 
    procedure DoOnViewportMouseUp(ASender : TObject; AButton : TMouseButton;
      AShift : TShiftState; X, Y : Single);
    procedure DoOnViewportMouseDown(ASender : TObject; AButton : TMouseButton;
      AShift : TShiftState; X, Y : Single);
    procedure DoOnViewportMouseMove(ASender : TObject; AShiftState : TShiftState;
      X, Y : Single);
  end;
 
  [...]
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  /// Deactivate design camera controller before registering user-specific events for mouse feedback
  GorillaViewport1.UsingDesignCamera := FALSE;
 
  /// Register user-specific mouse events to control our camera
  GorillaViewport1.OnMouseUp   := DoOnViewportMouseUp;
  GorillaViewport1.OnMouseDown := DoOnViewportMouseDown;
  GorillaViewport1.OnMouseMove := DoOnViewportMouseMove;
 
  /// Create a smooth camera controller
  FCameraCtrl := TGorillaSmoothCameraController.Create(GorillaViewport1);
  FCameraCtrl.Parent := GorillaViewport;
 
  /// NOTICE: Enable only rotation. Disable zooming and shifting
  FCameraCtrl.Types := [TGorillaSmoothCameraControlType.scctRotateY, TGorillaSmoothCameraControlType.scctMoveY];
 
  /// Create our own camera for this controller
  FMyCamera := TGorillaCamera.Create(FCameraCtrl);
  FMyCamera.Parent := FCameraCtrl;
 
  /// Link the camera to the controller
  FCameraCtrl.Camera := FMyCamera;
 
  /// Activate the camera for rendering
  GorillaViewport1.Camera := FMyCamera;
 
  [...]
end;
 
procedure TForm1.DoOnViewportMouseUp(ASender : TObject; AButton : TMouseButton;
  AShift : TShiftState; X, Y : Single);
begin
  FIsMoving := false;
end;
 
procedure TForm1.DoOnViewportMouseDown(ASender : TObject; AButton : TMouseButton;
  AShift : TShiftState; X, Y : Single);
begin
  FIsMoving  := true;
  FLastPoint := PointF(X, Y);
end;
 
procedure TForm1.DoOnViewportMouseMove(ASender : TObject; AShiftState : TShiftState;
  X, Y : Single);
var LDiff : TPointF;
begin
  if FIsMoving then
  begin
    if (ssLeft in AShiftState) then
    begin
      LDiff := PointF(X, Y) - FLastPoint;
 
      /// Rotate around y-axis + Move up and down
      FCameraCtrl.AddImpulse(LDiff);
    end;
 
    /// finally store the last mouse position
    FLastPoint := PointF(X, Y);
  end;
end;

The smooth camera controller provides a number of helpful functions to modify it from external.

FunctionDescription
procedure AddImpulse(AOfs : TPointF);Call this procedure to rotate around Y axis (AOfs.X) and move the camera up or down (AOfs.Y).
procedure AddXImpulse(AAngle : Single);Call this procedure to rotate around Y axis.
procedure AddYImpulse(AAngle : Single); Call this procedure to move camera up and down.
procedure Zoom(AStrength : Single = 1);Call this procedure if you want to zoom in or out. The strength parameter defines the intensity of zooming.
procedure Shift(AOfs : TPoint3D);Move the camera controller on X, Y and Z axis.

You can manipulate impulse values for rotation, zooming and shifting directly by the following properties.

PropertyDescription
Impulse.XGet or set the current impulse for rotation around Y-axis (X value).
Impulse.YGet or set the current impulse for moving up and down (Y value)
Impulse.ZGet or set the current impulse for zooming in/out (Z value)
ShiftImpulse.XGet or set the current impulse for shifting on X axis.
ShiftImpulse.YGet or set the current impulse for shifting on Y axis.
ShiftImpulse.ZGet or set the current impulse for shifting on Z axis.

Next step: Lights