Class TCastleSceneManager

Unit

Declaration

type TCastleSceneManager = class(TCastleAbstractViewport)

Description

Scene manager that knows about all 3D things inside your world.

Single scenes/models (like TCastleScene instances) can be rendered directly, but it's not always comfortable. Scenes have to assume that they are "one of the many" inside your 3D world, which means that multi-pass rendering techniques have to be implemented at a higher level. This concerns the need for multiple passes from the same camera (for shadow volumes) and multiple passes from different cameras (for generating textures for shadow maps, cube map environment etc.).

Scene manager overcomes this limitation. A single SceneManager object knows about all 3D things in your world, and renders them all for you, taking care of doing multiple rendering passes for particular features. Naturally, it also serves as container for all your visible 3D scenes.

Items property keeps a tree of TCastleTransform objects. TCastleTransform and TCastleScene can be added to this tree. Naturally you can implement your own TCastleTransform descendants, representing any (possibly dynamic, animated and even interactive) object.

TCastleSceneManager.Render can assume that it's the only manager rendering to the screen (although you can safely render more 3D geometry *after* calling TCastleSceneManager.Render). So it's Render method takes care of

  • clearing the screen,

  • rendering the background of the scene,

  • rendering the headlight,

  • rendering the scene from given camera,

  • and making multiple passes for shadow volumes and generated textures.

For some of these features, you'll have to set the MainScene property.

This is a TCastleUserInterface descendant, which means it's advised usage is to add this to TCastleWindowCustom.Controls or TCastleControlCustom.Controls. This passes relevant TCastleUserInterface events to all the TCastleTransform objects inside. Note that even when you set DefaultViewport = False (and use custom viewports, by TCastleViewport class, to render your 3D world), you still should add scene manager to the controls list (this allows e.g. 3D items to receive Update events).

Hierarchy

Overview

Fields

Protected FSectors: TSectorList;
Protected Waypoints: TWaypointList;

Methods

Protected procedure SetCamera(const Value: TCamera); override;
Protected function CollisionIgnoreItem(const Sender: TObject; const Triangle: PTriangle): boolean; virtual; deprecated 'use "Collision" X3D node with enabled=FALSE to selectively make some part of the world non-collidable';
Protected procedure Notification(AComponent: TComponent; Operation: TOperation); override;
Protected function CameraMoveAllowed(ACamera: TWalkCamera; const ProposedNewPos: TVector3; out NewPos: TVector3; const BecauseOfGravity: boolean): boolean; override;
Protected function CameraHeight(ACamera: TWalkCamera; const Position: TVector3; out AboveHeight: Single; out AboveGround: PTriangle): boolean; override;
Protected function CameraRayCollision(const RayOrigin, RayDirection: TVector3): TRayCollision; override;
Protected procedure CameraVisibleChange(const Sender: TInputListener; const Changes: TCastleUserInterfaceChanges; const ChangeInitiatedByChildren: boolean); override;
Protected function GetItems: TSceneManagerWorld; override;
Protected function GetMainScene: TCastleScene; override;
Protected function GetShadowVolumeRenderer: TGLShadowVolumeRenderer; override;
Protected function GetMouseRayHit: TRayCollision; override;
Protected function GetHeadlightCamera: TCamera; override;
Protected function GetPlayer: TPlayer; override;
Protected function GetTimeScale: Single; override;
Protected function PointingDeviceActivate(const Active: boolean): boolean; override;
Protected function PointingDeviceMove(const RayOrigin, RayDirection: TVector3): boolean; override;
Protected procedure PointingDeviceActivateFailed(const Active: boolean); virtual;
Protected function PointingDeviceActivate3D(const Item: TCastleTransform; const Active: boolean; const Distance: Single): boolean; virtual;
Protected function MoveAllowed(const OldPosition, NewPosition: TVector3; const BecauseOfGravity: boolean): boolean; virtual;
Protected procedure BoundNavigationInfoChanged; virtual;
Protected procedure BoundViewpointChanged; virtual;
Protected function Headlight: TAbstractLightNode; override;
Public constructor Create(AOwner: TComponent); override;
Public destructor Destroy; override;
Public procedure GLContextOpen; override;
Public procedure GLContextClose; override;
Public procedure PrepareResources(const DisplayProgressTitle: string = '');
Public procedure PrepareResources(const Item: TCastleTransform; const DisplayProgressTitle: string = ''); virtual;
Public procedure BeforeRender; override;
Public procedure Render; override;
Public function CameraToChanges: TVisibleChanges; virtual;
Public procedure Update(const SecondsPassed: Single; var HandleInput: boolean); override;
Public function GravityUp: TVector3;
Public function Rect: TFloatRectangle; override;

Properties

Public property MoveLimit: TBox3D read FMoveLimit write FMoveLimit;
Public property ShadowVolumeRenderer: TGLShadowVolumeRenderer read FShadowVolumeRenderer;
Public property MouseRayHit: TRayCollision read FMouseRayHit;
Public property Viewports: TCastleAbstractViewportList read FViewports;
Public property Sectors: TSectorList read FSectors;
Public property Water: TBox3D read FWater write FWater;
Published property TimeScale: Single read FTimeScale write FTimeScale default 1;
Published property Items: TSceneManagerWorld read FItems;
Published property MainScene: TCastleScene read FMainScene write SetMainScene;
Published property OnCameraChanged: TNotifyEvent read FOnCameraChanged write FOnCameraChanged;
Published property OnBoundViewpointChanged: TNotifyEvent read FOnBoundViewpointChanged write FOnBoundViewpointChanged;
Published property OnBoundNavigationInfoChanged: TNotifyEvent read FOnBoundNavigationInfoChanged write FOnBoundNavigationInfoChanged;
Published property DefaultViewport: boolean read FDefaultViewport write SetDefaultViewport default true;
Published property Player: TPlayer read FPlayer write SetPlayer;
Published property OnMoveAllowed: TWorldMoveAllowedEvent read FOnMoveAllowed write FOnMoveAllowed;
Published property HeadlightNode: TAbstractLightNode read GetHeadlightNode write SetHeadlightNode;
Published property UseHeadlight: TUseHeadlight read FUseHeadlight write FUseHeadlight default hlMainScene;

Description

Fields

Protected FSectors: TSectorList;
 
Protected Waypoints: TWaypointList;
 

Methods

Protected procedure SetCamera(const Value: TCamera); override;
 
Protected function CollisionIgnoreItem(const Sender: TObject; const Triangle: PTriangle): boolean; virtual; deprecated 'use "Collision" X3D node with enabled=FALSE to selectively make some part of the world non-collidable';

Warning: this symbol is deprecated: use "Collision" X3D node with enabled=FALSE to selectively make some part of the world non-collidable

Triangles to ignore by all collision detection in scene manager. The default implementation in this class resturns always False, so nothing is ignored. You can override it e.g. to ignore your "water" material, when you want player to dive under the water.

Protected procedure Notification(AComponent: TComponent; Operation: TOperation); override;
 
Protected function CameraMoveAllowed(ACamera: TWalkCamera; const ProposedNewPos: TVector3; out NewPos: TVector3; const BecauseOfGravity: boolean): boolean; override;
 
Protected function CameraHeight(ACamera: TWalkCamera; const Position: TVector3; out AboveHeight: Single; out AboveGround: PTriangle): boolean; override;
 
Protected function CameraRayCollision(const RayOrigin, RayDirection: TVector3): TRayCollision; override;
 
Protected procedure CameraVisibleChange(const Sender: TInputListener; const Changes: TCastleUserInterfaceChanges; const ChangeInitiatedByChildren: boolean); override;
 
Protected function GetItems: TSceneManagerWorld; override;
 
Protected function GetMainScene: TCastleScene; override;
 
Protected function GetShadowVolumeRenderer: TGLShadowVolumeRenderer; override;
 
Protected function GetMouseRayHit: TRayCollision; override;
 
Protected function GetHeadlightCamera: TCamera; override;
 
Protected function GetPlayer: TPlayer; override;
 
Protected function GetTimeScale: Single; override;
 
Protected function PointingDeviceActivate(const Active: boolean): boolean; override;
 
Protected function PointingDeviceMove(const RayOrigin, RayDirection: TVector3): boolean; override;
 
Protected procedure PointingDeviceActivateFailed(const Active: boolean); virtual;

Called when PointingDeviceActivate was not handled by any 3D object. You can override this to make a message / sound signal to notify user that his Input_Interact click was not successful.

Protected function PointingDeviceActivate3D(const Item: TCastleTransform; const Active: boolean; const Distance: Single): boolean; virtual;

Handle pointing device (mouse) activation/deactivation event over a given 3D object. See TCastleTransform.PointingDeviceActivate method for description how it should be handled. Default implementation in TCastleSceneManager just calls TCastleTransform.PointingDeviceActivate.

Protected function MoveAllowed(const OldPosition, NewPosition: TVector3; const BecauseOfGravity: boolean): boolean; virtual;

Handle OnMoveAllowed and default MoveLimit algorithm. See the description of OnMoveAllowed property for information.

When this is called, collision detection determined that this move is allowed. The default implementation in TCastleSceneManager calculates the result using the algorithm described at the MoveLimit property, then calls OnMoveAllowed event.

Protected procedure BoundNavigationInfoChanged; virtual;
 
Protected procedure BoundViewpointChanged; virtual;
 
Protected function Headlight: TAbstractLightNode; override;
 
Public constructor Create(AOwner: TComponent); override;

procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;

Public destructor Destroy; override;
 
Public procedure GLContextOpen; override;
 
Public procedure GLContextClose; override;
 
Public procedure PrepareResources(const DisplayProgressTitle: string = '');

Prepare resources, to make various methods (like Render) execute fast. If DisplayProgressTitle <> '', we will display progress bar during loading.

Public procedure PrepareResources(const Item: TCastleTransform; const DisplayProgressTitle: string = ''); virtual;
 
Public procedure BeforeRender; override;
 
Public procedure Render; override;
 
Public function CameraToChanges: TVisibleChanges; virtual;

What changes happen when camera changes. You may want to use it when calling Scene.CameraChanged.

Implementation in this class is correlated with RenderHeadlight.

Public procedure Update(const SecondsPassed: Single; var HandleInput: boolean); override;
 
Public function GravityUp: TVector3;

Up vector, according to gravity. Gravity force pulls in -GravityUp direction.

Public function Rect: TFloatRectangle; override;
 

Properties

Public property MoveLimit: TBox3D read FMoveLimit write FMoveLimit;

Where the 3D items (player, creatures, items) can move, and where the gravity works. In case of 1st-person view (always, for now) limiting the player position also implies limiting the camera position. Intuitively, this is the "sensible" part of 3D space where normal physics should work.

TODO: When you activate 3rd-person camera (not implemented yet), this limit will apply to the Player.Position, not Camera.Position.

  • When MoveLimit is an empty box (this is the default situation) then movement is limited to not fall because of gravity outside of Items.BoundingBox. Still, we can freely move anywhere (only gravity effect is limited to the Items.BoundingBox).

    This is the safest behavior for general 3D model browsers, it prevents camera from falling into an infinite abyss of our 3D space, since gravity will always stop at the Items.BoundingBox border.

  • When MoveLimit is not an empty box, then position cannot go outside of this box.

    Note that the TGameSceneManager.LoadLevel always, automatically, assigns this property to be non-empty. It's either determined by CasMoveLimit placeholder in the level 3D model, or it's automatically calculated to include level bounding box + some space for flying.

Public property ShadowVolumeRenderer: TGLShadowVolumeRenderer read FShadowVolumeRenderer;

Renderer of shadow volumes. You can use this to optimize rendering of your shadow quads in RenderShadowVolume, and you can control it's statistics (TGLShadowVolumeRenderer.Count and related properties).

This is internally initialized by scene manager. It's Nil when OpenGL context is not yet initialized (or scene manager is not added to Controls list yet).

Public property MouseRayHit: TRayCollision read FMouseRayHit;

Current 3D objects under the mouse cursor. Updated in every mouse move. May be Nil.

Public property Viewports: TCastleAbstractViewportList read FViewports;

List of viewports connected to this scene manager. This contains all TCastleViewport instances that have TCastleViewport.SceneManager set to us. Also it contains Self (this very scene manager) if and only if DefaultViewport = True (because when DefaultViewport, scene manager acts as an additional viewport too).

This list is read-only from the outside! It's automatically managed in this unit (when you change TCastleViewport.SceneManager or TCastleSceneManager.DefaultViewport, we automatically update this list as appropriate).

Public property Sectors: TSectorList read FSectors;

Sectors and waypoints of this world, for AI in 3D. Initialized by TGameSceneManager.LoadLevel. Nil if you never call TGameSceneManager.LoadLevel.

A generic AI code should work regardless if these are Nil or not. But if you're making a game and you know you will always call TGameSceneManager.LoadLevel, you can just use them straight away.

Public property Water: TBox3D read FWater write FWater;

Water volume in the scene. It may be used by various 3D objects to indicate appropriate behavior — some things swim, some things drown and such. For now, this is only used by TPlayer class to detect swimming (and make appropriate sounds, special rendering, drowning and such).

For now, this is just a simple TBox3D. It will be extended to represent a set of flexible 3D volumes in the future.

Empty initially. Initialize it however you want.

Published property TimeScale: Single read FTimeScale write FTimeScale default 1;

Time scale used when not Paused.

Published property Items: TSceneManagerWorld read FItems;

Tree of 3D objects within your world. This is the place where you should add your scenes to have them handled by scene manager. You may also set your main TCastleScene (if you have any) as MainScene.

Published property MainScene: TCastleScene read FMainScene write SetMainScene;

The main scene of your 3D world. It's not necessary to set this. It adds some optional features that require a notion of the "main" scene to make sense.

The scene you set here must also be added to our Items.

The MainScene is used for a couple of things:

  • Determines initial camera position, orientation, projection, move speed and other details. The initial camera follows the X3D Viewpoint, OrthoViewpoint and NavigationInfo nodes inside the MainScene.

    The camera will also stay synchronized with the X3D nodes in MainScene. This means that Camera will be updated when X3D events change current X3D Viewpoint or X3D NavigationInfo, for example you can animate the camera by animating the viewpoint (or it's transformation) or bind camera to a viewpoint.

    Note that scene manager "hijacks" some TCastleSceneCore events for this purpose: TCastleSceneCore.OnBoundViewpointVectorsChanged, TCastleSceneCore.ViewpointStack.OnBoundChanged, TCastleSceneCore.NavigationInfoStack.OnBoundChanged for this purpose. If you want to know when viewpoint changes, you can use scene manager's event OnBoundViewpointChanged, OnBoundNavigationInfoChanged.

    Note that descendants that overrride CalculateProjection can change this behaviour. For example TCastle2DSceneManager completely ignores the camera parameters in MainScene, and instead always sets up a suitable orthogonal camera.

  • Determines what background is rendered. If the MainScene contains an X3D Background node, it will be used. Otherwise we render a background using BackgroundColor.

    Note that when Transparent is True, we never render any background (neither from MainScene, nor from BackgroundColor).

  • Determines whether headlight is used if UseHeadlight is hlMainScene. The value of MainScene.HeadlightOn then determines the headlight. The initial MainScene.HeadlightOn value depends on the X3D NavigationInfo node inside MainScene.

  • Determines if, and where, the main light casting shadow volumes is.

  • Determines lights shining on all scenes, if UseGlobalLights.

  • Determines fog on all scenes, if UseGlobalFog.

Freeing MainScene will automatically set this property to Nil.

Published property OnCameraChanged: TNotifyEvent read FOnCameraChanged write FOnCameraChanged;

Called on any camera change.

Published property OnBoundViewpointChanged: TNotifyEvent read FOnBoundViewpointChanged write FOnBoundViewpointChanged;

Called when bound Viewpoint node changes. Called exactly when TCastleSceneCore.ViewpointStack.OnBoundChanged is called.

Published property OnBoundNavigationInfoChanged: TNotifyEvent read FOnBoundNavigationInfoChanged write FOnBoundNavigationInfoChanged;

Called when bound NavigationInfo changes (to a different node, or just a field changes).

Published property DefaultViewport: boolean read FDefaultViewport write SetDefaultViewport default true;

Should we render the 3D world in a default viewport that covers the whole window. This is usually what you want. For more complicated uses, you can turn this off, and use explicit TCastleViewport (connected to this scene manager by TCastleViewport.SceneManager property) for making your world visible.

Published property Player: TPlayer read FPlayer write SetPlayer;

Player in this 3D world. This currently serves various purposes:

  • In the 1st person view, this 3D object guides the camera and it never collides with the camera. That is, our CameraMoveAllowed and similar methods simply call Player.MoveAllowed, that in turn calls World.WorldMoveAllowed making sure that player is temporarily disabled (does not collide with itself).

    TGameSceneManager.LoadLevel will set Player.Camera to TCastleSceneManager.Camera. This means that user can directly control Player.Camera view (position, direction, up), which in turn is always synchronized with Player view (that is, TPlayer.Direction always equals TPlayer.Camera.Direction and so on).

  • For simple AI in CastleCreatures, hostile creatures will attack this player. So this determines the target position that creatures try to reach, where they shoot missiles etc. More advanced AI, with friendlies/companions, or cooperating factions of creatures, may have other mechanisms to determine who wants to attack who.

  • For items on level in CastleItems, this player will pick up the items lying on the ground, and will be able to equip weapons. This functionality may be generalized in the future, to allow anyone to pick up and carry and equip items.

Published property OnMoveAllowed: TWorldMoveAllowedEvent read FOnMoveAllowed write FOnMoveAllowed;

Enable or disable movement of the player, items and creatures. This applies to all 3D objects using TCastleTransform.WorldMoveAllowed for movement. In case of 1st-person view (always for now), limiting the player position also implies limiting the camera position.

When this event is called at all, the basic collision detection already decided that the move is allowed (so object does not collide with other collidable 3D features). You can now implement additional rules to say when the move is, or is not, allowed.

Callback parameters:

  • Allowed:

    Initially, the Allowed parameter is set following the algorithm described at the MoveLimit property. Your event can use this, and e.g. do something like

    Allowed := Allowed and (my custom move rule);

    Or you can simply ignore the default Allowed value, thus ignoring the algorithm described at the MoveLimit property, and simply always set Allowed to your own decision. For example, setting

    Allowed := true;

    will make gravity and movement work everywhere.

  • BecauseOfGravity:

    True if this move was caused by gravity, that is: given object is falling down. You can use this to limit gravity to some box, but keep other movement unlimited, like

    { Allow movement everywhere, but limit gravity to a box. }
    Allowed := (not BecauseOfGravity) or MyGravityBox.Contains(NewPos);

Published property HeadlightNode: TAbstractLightNode read GetHeadlightNode write SetHeadlightNode;

Determines the headlight look, if we use a headlight (which is determined by the algorithm described at UseHeadlight and TUseHeadlight). By default it's a simplest directional headlight, but you can customize it, and thus you can use a point light or a spot light for a headlight. Just like https://castle-engine.io/x3d_implementation_navigation_extensions.php#section_ext_headlight .

This is never Nil. Assigning here Nil simply causes us to recreate it using the simplest directional headlight.

Published property UseHeadlight: TUseHeadlight read FUseHeadlight write FUseHeadlight default hlMainScene;

Whether the headlight is shown, see TUseHeadlight for possible values.


Generated by PasDoc 0.15.0.