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 or TCastlePrecalculatedAnimation 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 T3D objects. All our 3D objects, like TCastleSceneCore (and so also TCastleScene) and TCastlePrecalculatedAnimation descend from T3D, and you can add them to the scene manager. And naturally you can implement your own T3D descendants, representing any 3D (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 TUIControl descendant, which means it's advised usage is to add this to TCastleWindowCustom.Controls or TCastleControlCustom.Controls. This passes relevant TUIControl events to all the T3D 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: P3DTriangle): boolean; virtual;
Protected procedure Notification(AComponent: TComponent; Operation: TOperation); override;
Protected function CameraMoveAllowed(ACamera: TWalkCamera; const ProposedNewPos: TVector3Single; out NewPos: TVector3Single; const BecauseOfGravity: boolean): boolean; override;
Protected function CameraHeight(ACamera: TWalkCamera; const Position: TVector3Single; out AboveHeight: Single; out AboveGround: P3DTriangle): boolean; override;
Protected function CameraRayCollision(const RayOrigin, RayDirection: TVector3Single): TRayCollision; override;
Protected procedure CameraVisibleChange(ACamera: TObject); override;
Protected function GetItems: T3DWorld; 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: TVector3Single): boolean; override;
Protected procedure PointingDeviceActivateFailed(const Active: boolean); virtual;
Protected function PointingDeviceActivate3D(const Item: T3D; const Active: boolean; const Distance: Single): boolean; virtual;
Protected function MoveAllowed(const OldPosition, NewPosition: TVector3Single; 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: T3D; 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 CreateDefaultCamera(AOwner: TComponent): TCamera; override;
Public function GravityUp: TVector3Single;
Public function Rect: TRectangle; 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: T3DWorld 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;

Description

Fields

Protected FSectors: TSectorList;
 
Protected Waypoints: TWaypointList;
 

Methods

Protected procedure SetCamera(const Value: TCamera); override;
 
Protected function CollisionIgnoreItem(const Sender: TObject; const Triangle: P3DTriangle): boolean; virtual;

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: TVector3Single; out NewPos: TVector3Single; const BecauseOfGravity: boolean): boolean; override;
 
Protected function CameraHeight(ACamera: TWalkCamera; const Position: TVector3Single; out AboveHeight: Single; out AboveGround: P3DTriangle): boolean; override;
 
Protected function CameraRayCollision(const RayOrigin, RayDirection: TVector3Single): TRayCollision; override;
 
Protected procedure CameraVisibleChange(ACamera: TObject); override;
 
Protected function GetItems: T3DWorld; 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: TVector3Single): 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: T3D; const Active: boolean; const Distance: Single): boolean; virtual;

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

Protected function MoveAllowed(const OldPosition, NewPosition: TVector3Single; 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;
 
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. This is especially useful for long precalculated animations (TCastlePrecalculatedAnimation with a lot of ScenesCount), they show nice linearly increasing progress bar.

Public procedure PrepareResources(const Item: T3D; 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 CreateDefaultCamera(AOwner: TComponent): TCamera; override;
 
Public function GravityUp: TVector3Single;

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

Public function Rect: TRectangle; 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: T3DWorld 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.

T3DList is also T3D instance, so yes — this may be a tree of T3D, not only a flat list.

Published property MainScene: TCastleScene read FMainScene write SetMainScene;

The main scene of your 3D world. It's not necessary to set this (after all, your 3D world doesn't even need to have any TCastleScene instance). This must be also added to our Items (otherwise things will work strangely).

When set, this is used for a couple of things:

  • Decides what headlight is used (by TCastleScene.Headlight).

  • Decides what background is rendered. Notes for implementing descendants of this class: You can change this by overriding Background method.

  • Decides if, and where, the main light casting shadows is. Notes for implementing descendants of this class: You can change this by overriding MainLightForShadows method.

  • Determines projection for viewing (if you use default CalculateProjection implementation).

  • Synchronizes our Camera with VRML/X3D viewpoints and navigation info. This means that Camera will be updated when VRML/X3D events change current Viewpoint or 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 Scene events: 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.

The above stuff is only sensible when done once per scene manager, that's why we need MainScene property to indicate this. (We cannot just use every 3D object from Items for this.)

Freeing MainScene will automatically set this to Nil.

Published property OnCameraChanged: TNotifyEvent read FOnCameraChanged write FOnCameraChanged;

Called on any camera change. Exactly when TCamera generates it's OnVisibleChange event.

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 T3D.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.PointInside(NewPos);


Generated by PasDoc 0.14.0.