This component defines nodes to control the camera,
and some effects closely related to the camera.
NavigationInfo
controls the camera behavior.
Viewpoint
and OrthoViewpoint
define
the initial camera position and rotation, and may be used to animate
the camera. LOD
allows to implement level-of-detail,
where different versions of some object are displayed depending
on the camera distance. Collision
allows to use a simpler
geometry for collision purposes, or even to turn the collisions off
(like a fake wall hiding a secret room in games).
Billboard
may be used to create sprites, as it aligns
geometry (flat or not) with respect to the camera.
Contents:
See also Castle Game Engine (and view3dscene) extensions related to navigation.
For demos and tests of these features,
see the navigation
subdirectory inside our VRML/X3D demo models.
Viewpoint
(Pascal API: TViewpointNode
),
OrthoViewpoint
(Pascal API: TOrthoViewpointNode
).
These nodes define the initial camera position, rotation, and field of view.
The Viewpoint
makes a perspective projection (objects further away are smaller),
OrthoViewpoint
makes an orthographic projection.
You can even animate their transformation and properties, to animate the camera.
Note: In Castle Game Engine you can also control the camera by Pascal code,
using the Viewport.Camera
property that keeps a
TCastleCamera
instance.
See manual about controlling the camera.
Still, this X3D node is useful to set initial camera through e.g. Blender
(you can export to glTF or X3D and importing them will set initial camera properly).
view3dscene displays a nice menu allowing you to jump to any defined viewpoint, showing viewpoints' descriptions. Animating viewpoint's position and orientation (directly or by animating it's parent transformation) also works perfectly.
Note that merely adding a Viewpoint
(or OrthoViewpoint
) node to the X3D model, with everything at default, changes how view3dscene and CGE interpret the model.
Without the Viewpoint
(or OrthoViewpoint
), we determine center of rotation (important for proper "Examine" work) based on scene contents (bounding box middle).
With Viewpoint
(or OrthoViewpoint
), we assume you have set proper centerOfRotation
. The default centerOfRotation
is just (0,0,0). This follows X3D standard.
You can set Viewport.autoCenterOfRotation
(or OrthoViewport.autoCenterOfRotation
) to true
to explicitly request to automatically determine (based on bounding box middle) this center of rotation.
This field is a CGE extension.
TODO: We support most, but not all, X3D fields.
Fields not implemented yet: jump
, retainUserOffsets
.
As for animating viewpoints (and also possible jump
, retainUserOffsets
implementation):
We do not support right now the notion of preserving user offsets
from navigation. Tracking them in the past required to have a special
treatment of camera transformation (initial vs current),
but it was too complicated too keep (as we wanted to make
TCastleCamera
descend from TCastleTransform
)
and it didn't seem useful for authors in reality. (Of course please report
if it is useful for you!)
When you animate the viewpoint (either by animating viewpoint position/orientation or by animating viewpoint transformation) right now we just change the current camera to match the viewpoint. User offsets are not retained.
NavigationInfo
(Pascal API: TNavigationInfoNode
)
Controls the navigation behavior (mode of movement, gravity, etc.) and the headlight.
Note: In Castle Game Engine you can also control the navigation by Pascal code. See manual about navigation. And you can control the headlight by just adding lights as camera children. Still, this node is useful to define defaults.
Details about supported fields:
avatarSize
is honoured fully:
First avatarSize
item is the camera radius.
If you use Castle Model View,
note that --camera-radius
command-line option overrides
this value.
2nd avatarSize
item is the preferred height
above the ground.
3rd avatarSize
item
is the tallest object over which you can climb.
If this is missing (or it has value <= 0) then there's no such limit, and you can climb as long as you can move forward. So you can climb the stairs with steps almost as high as your own height minus the camera radius. Simplifying (ignoring other effects, like head bobbing), you can say that avatarSize[2] is by default like avatarSize[1] - avatarSize[0]).
See TCastleWalkNavigation.ClimbHeight API docs for more details about this.
speed
field is supported, it sets
the speed in meters/second. Speed = 0.0 is also correctly
honored (user will not be able to move in Walk/Fly modes,
only to rotate).
type
field is supported.
Navigation types fully supported are: EXAMINE
, WALK
,
FLY
, NONE
.
Inside the engine, the navigation paradigm is actually a little
more flexible. You can fine-tune the rotations and gravity
behavior by view3dscene Navigation -> Walk and Fly Settings
menu.
As an extension, we also support new navigation mode TURNTABLE
.
This is similar to the Examine mode, with controls comfortable
for viewing models that have a sense of floor/ground in the XZ plane,
and vertical axis in +Y. Implementation is not finished yet.
The presence of navigation type
ANY
is ignored by
Castle Model View.
We always show controls to change navigation settings, hiding them
feels harmful to user.
Nice transitions between viewpoints are supported,
honouring transitionType
and transitionTime
fields,
and (since view3dscene 3.13.0) making transitionComplete
event.
See demo model navigation/transition_multiple_viewpoints.x3dv showing how to use it to make an animated transition between a couple of viewpoints.
Binding different NavigationInfo
nodes,
and changing their exposed fields by events, of course works.
When no NavigationInfo
node is present in the scene:
avatarSize
and speed
are calculated based on scene's bounding box sizes, to a values that
will hopefully "feel right".
We try to calculate them intelligently, because simply using
NavigationInfo
defaults results in bad experience
in many scenes.headlight
behaves like true,
type
behaves like [EXAMINE, ANY]
,
this follows NavigationInfo
defaults.TODO: visibilityLimit
may be ignored if shadow
volumes are allowed (We use frustum with z-far in infinity then.)
Allows to define various versions of the same object, with varying level-of-detail. An appropriate child is automatically displayed based on the current distance to the camera.
Note: Right now, the only thing that decides
"which level of detail should be used"
is the distance to the camera.
Which means that only the supplied LOD.range
controls which level is displayed.
The forceTransitions
value is simply ignored,
and when range
is empty, we simply always use the first
(highest-detail) version.
Example: The simplest example is part of our demo models. View the X3D code here: navigation/lod_test.x3dv.
Billboard
(Pascal API: TBillboardNode
)
The children of this node are automatically aligned with the camera. Two modes are possible: where the objects are rotated only around a specified axis, or where objects are rotated freely to match the camera.
Example: The simplest example is part of our demo models. View the X3D code here: navigation/billboard_simple.x3dv.
Collision
(Pascal API: TCollisionNode
)
Allows to define a simpler geometry for collision purposes, or even to turn the collisions off (like a fake wall hiding a secret room in games).
Most things work: grouping (children
property, in particular),
allows to control collision detection by honoring
enabled
(named collide
in VRML 97) and proxy
fields.
bboxCenter/Size
is currently simply ignored, our engine
always calculates and updates the bounding boxes where needed.
TODO: collideTime and isActive out events are not implemented yet.
ViewpointGroup
(Pascal API: TViewpointGroupNode
)
You can use this to create submenus in "Navigation -> Jump To Viewpoint" menu in
Castle Model View.
Fields description
and children
are taken into account.
Also, you can use this node to hide some viewpoints from the menu:
the displayed
field also works.
TODO: size/center is not honored yet. Group is displayed
regardless of camera position. A possible workarond could be
to use a ProximitySensor
node,
routing ProximitySensor.isActive
to the displayed
field...
Except this workaround will not work too, because changing
of the displayed
field after the scene loading
doesn't change the menu for now.
TODO: retainUserOffsets is ignored.