Camera and navigation rework almost finished. TODO: This news announcement is too long, we have too much new stuff to announce

Posted on

Camera from Sketchfab in glTF

I’m nearly done with the big amount of changes on new-cameras branch. Below is a draft news announcement that will become official (and more complete) soon!

TODO: This is too long to announce, too many things. And this is not even finished yet, there will be more gains from this in UI.

TODO: Record a movie about this.

New features of camera and navigation:

  1. During design-time (that is, in CGE editor) you use an internal editor camera and navigation to move around the scene, without automatically changing the camera / navigation that will be used later for playing the game.

    This gives you more flexibility in how you move in the world at design-time, and this gives us more flexibility to implement best navigation at design-time, without worrying what is best for run-time.

    In particular

    • Dragging with left mouse button over viewport now doesn’t change camera. This makes it safer to navigate, as you don’t accidentally drag transform when you want to change camera, or vice versa, because now they are tied to different mouse buttons.

    • Navigation at design-time is activated by pressing and holding right mouse button over a viewport. This is consistent with various other game engines.

    • Design-time navigation fly mode shortcuts:

      Change speed by mouse wheel, as well as + and - keys.
      Keep holding right mouse button to rotate using mouse look.
      Nove by ASWD.
      Move down/up by QE.
    • Also (Viewport menu):

      Home to view all
      F to focus selected (a bit like in Unity, yes :) )
  2. TCastleCamera is now a TCastleTransform descendant, and as such it can be placed on Viewport.Items now.

    The current camera should be assigned to Viewport.Camera.

    In general Viewport.Camera and adding camera to Viewport.Items are independent actions (it was a mess when we tried to make them too much “magically” auto-connected). But

    • for backward-compatibility, camera from old designs is automatically assigned as Viewport.Camera, so old designs just work

    • when creating new viewport from code (but not when deserializing and not at design-time), we add new unnamed camera (as Viewport.Camera, and to Viewport.Items)

    • when creating new viewport in editor (but not when deserializing) we add new named camera (as Viewport.Camera, and to Viewport.Items)

  3. Camera can have children, like any other TCastleTransform.

    This is nice to place something relative to camera, e.g. weapon in typical FPS games.

    It is also new advised way to make a “headlight“. Just add a light, like TCastleDirectionalLight, as camera child. That’s it. Leave Viewport.UseHeadlight as hlOff, or UseHeadlight=hlMainScene (default) and leave Viewport.Items.MainScene=nil (default). We don’t need MainScene, we don’t need UseHeadlight anymore. This way it is also trivial how to control or adjust the headlight. It’s just your component, change it freely to another light, remove it, change the light Exists property etc.

    The default TCastleDirectionalLight direction is -Z, conveniently, as this is also the direction along which the camera is looking at. So just dropping default TCastleDirectionalLight as a TCastleCamera is all you need.

    See examples/viewport_and_scenes/headlight/ for example.

  4. Camera can be a child of some other transformation, e.g. you can mount camera on a car, or attach it to a bone of your skeleton.

  5. You can create TCastleCamera instances, from code or from editor, and have as many as you need. Just set Viewport.Camera to the current camera. You can set this property freely, also to nil (for consistency, it must be prepared for “no camera”, e.g. if you destroy the camera; viewport rendering is not done in this case).

    It also auto-synchronizes Viewport.Items.MainCamera with Viewport.Camera, if they were synchronized already. In simple cases (if you don’t use multiple viewports) Viewport.Items.MainCamera and Viewport.Camera are always synchronized.

  6. We display a preview from selected camera. This way you can reliably move any camera. And you can reliably move things with respect to camera.

    You can pin the preview, make it larger/smaller, to control and display it as necessary.

  7. This also makes the AnimateTo of cameras more useful.

    You can now setup various cameras around the world in editor, and use CurrentCamera.AnimateTo(SomeCamera) to smoothly animate to them.

  8. Adding Navigation components (to use at run-time) is no longer “special”. Just use “Add User Interface -> Navigation/xxx” to insert navigation as child of viewport.

    No more special menu to do that (that was previously trying to do some needless automatic around it, removing/adding it to children, removing previous navigation etc.) Also there’s no longer a need to use TCastleViewport.Navigation. It’s a deprecated property now, that just adds/removes children, nothing more.

    Also Navigation Exists works as expected. You can have multiple navigation components within on TCastleViewport, they can even work “all at once” but in practice (with current navigation classes) you will want to use Exists to make only one of them active.

  9. New property TCastleNavigation.CheckCollisions is also available.

More new features, done BTW:

  1. Editor improvements: Smaller gizmos

  2. Editor improvements: Show whether whole vector/color has modified state properly, e.g. see if Translation value is not bold or not

  3. glTF interpolators with unique names

  4. Inspector on F8 shows modified props (non-default value) more emphasized (blueish background for now)

  5. TCastleVectorXxxPersistent is now a TCastleComponent descendant, it can have owner, it can react to csLoading, it can and should be SetSubComponent(true), it is deserialized better: sets the final vector at once.

Backward compatibility notes:

  1. At the center of this change, is that TCastleCamera is now a TCastleTransform descendant. This generally makes it more powerful (e.g. you can add child objects to camera) but also makes some changes to API:

  2. TCastleCamera no longer stores “initial” vectors. Just like all TCastleTransform, it just stores current position/direction/up, delegating to some other code management of “initial” vs “current” state, if you need that.

  3. TCastleCamera.Position is deprecated. Use now Translation, not Position. Or WorldTranslation to get it in world-coordinates.

  4. TCastleCamera.Update now follows the signature of TCastleTransform.Update, thus it gets extra RemoveType parameter.

  5. TCastleCamera had some specialized GetView / SetView overloads. They have been removed — because they would be confusing now.

    TCastleCamera.GravityUp is always in world space.

    To get/set camera vectors, you should usually use GetWorldView / SetWorldView to operate in world space. The GetView / SetView, defined in TCastleTransform, continue to operate in local space. The new code should usually be updated from GetView / SetView to GetWorldView / SetWorldView — because almost always you want to query/set camera in world coordinates, not in local coordinates. This way you support the case “camera can be a child of something else”.

    So you should usually upgrade this code:

    // OLD
    MainViewport.Camera.GetView(Pos, Dir, Up, GravityUp);

    into this:

    // NEW
    MainViewport.Camera.GetWorldView(Pos, Dir, Up);
    GravityUp := MainViewport.Camera.GravityUp;

    And this code:

    // OLD
    MainViewport.Camera.SetView(Pos, Dir, Up, GravityUp);

    into this:

    // NEW
    MainViewport.Camera.SetWorldView(Pos, Dir, Up);
    MainViewport.Camera.GravityUp := GravityUp;
  6. TCastleNavigation had some deprecated GetView, SetView, Position, Direction, Up.

    They have been removed now. You should use Camera.GetWorldView, Camera.SetWorldView in most cases now.

  7. World.CameraXxx deprecated functions have been removed:

    function CameraPosition: TVector3; deprecated 'use MainCamera.Position if MainCamera <> nil';
    function CameraDirection: TVector3; deprecated 'use MainCamera.Direction if MainCamera <> nil';
    function CameraUp: TVector3; deprecated 'use MainCamera.Up if MainCamera <> nil';
    function CameraGravityUp: TVector3; deprecated 'use MainCamera.GravityUp if MainCamera <> nil';
    function CameraKnown: Boolean; deprecated 'use MainCamera <> nil';

    Because you should now usually upgrade to MainCamera.GetWorldView or WorldTranslation.
    In general you have to now be aware that camera that world and local coords,
    just like everything other TCastleTransform.

    Same for TCastleSceneCore, removed deprecated:

    function CameraPosition: TVector3; deprecated 'do not access camera properties this way, instead use e.g. Viewport.Camera.Position';
    function CameraDirection: TVector3; deprecated 'do not access camera properties this way, instead use e.g. Viewport.Camera.GetView';
    function CameraUp: TVector3; deprecated 'do not access camera properties this way, instead use e.g. Viewport.Camera.GetView';
    function CameraViewKnown: boolean; deprecated 'do not access camera properties this way, instead use e.g. Viewport.Camera';

    Also TCastleViewport.XxxCamera methods that actually talked about navigation (and not Camera) are removed. They have been deprecated for some time, and right now could be quite confusing. So removed:

  8. The already deprecated methods to auto-create the navigation have moved to separate deprecated class TCastleAutoNavigationViewport. The base TCastleViewport is free from their complication (that turned out to be useless, in most cases).

    This applies to you if you use AutoNavigation, NavigationType, ExamineNavigation, WalkNavigation.

    We advise you to instead create navigation explicitly, in code or in editor, like

    MyWalkNavigation := TCastleWalkNavigation.Create(...);

    But if you really need automatic management of navigation you can still use TCastleAutoNavigationViewport.

Screenshot using Steampunk Camera by lumoize from Sketchfab.

Start the discussion at Castle Game Engine Forum