Class T3D

DescriptionHierarchyFieldsMethodsProperties

Unit

Declaration

type T3D = class(TComponent)

Description

Base 3D object, that can be managed by TCastleSceneManager. All 3D objects should descend from this, this way we can easily insert them into the TCastleSceneManager.

Default implementations of collision methods in this class work with our BoundingBox:

The idea is that by default everything simply uses BoundingBox, and that is the only method that you really have to override. You do not have to (in fact, usually you should not) call "inherited" when overriding collision methods mentioned above.

Hierarchy

  • TComponent
  • T3D

Overview

Methods

Protected procedure CursorChange; virtual;
Protected function GetExists: boolean; virtual;
Protected function GetCollides: boolean; virtual;
Protected function HeightCollision(const Position, GravityUp: TVector3Single; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc; out AboveHeight: Single; out AboveGround: P3DTriangle): boolean; virtual;
Protected function MoveCollision( const OldPos, ProposedNewPos: TVector3Single; out NewPos: TVector3Single; const IsRadius: boolean; const Radius: Single; const OldBox, NewBox: TBox3D; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc): boolean; virtual;
Protected function MoveCollision( const OldPos, NewPos: TVector3Single; const IsRadius: boolean; const Radius: Single; const OldBox, NewBox: TBox3D; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc): boolean; virtual;
Protected function SegmentCollision(const Pos1, Pos2: TVector3Single; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc; const ALineOfSight: boolean): boolean; virtual;
Protected function SphereCollision(const Pos: TVector3Single; const Radius: Single; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc): boolean; virtual;
Protected function BoxCollision(const Box: TBox3D; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc): boolean; virtual;
Protected function RayCollision(const RayOrigin, RayDirection: TVector3Single; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc): TRayCollision; virtual;
Public constructor Create(AOwner: TComponent); override;
Public destructor Destroy; override;
Public procedure Disable;
Public procedure Enable;
Public function BoundingBox: TBox3D; virtual; abstract;
Public procedure Render(const Frustum: TFrustum; const Params: TRenderParams); virtual;
Public procedure RenderShadowVolume( ShadowVolumeRenderer: TBaseShadowVolumeRenderer; const ParentTransformIsIdentity: boolean; const ParentTransform: TMatrix4Single); virtual;
Public procedure PrepareResources( Options: TPrepareResourcesOptions; ProgressStep: boolean; BaseLights: TAbstractLightInstancesList); virtual;
Public function PrepareResourcesSteps: Cardinal; virtual;
Public function Press(const Event: TInputPressRelease): boolean; virtual;
Public function Release(const Event: TInputPressRelease): boolean; virtual;
Public function PointingDeviceActivate(const Active: boolean; const Distance: Single): boolean; virtual;
Public function PointingDeviceMove(const Pick: TRayCollisionNode; const Distance: Single): boolean; virtual;
Public procedure Update(const SecondsPassed: Single; var RemoveMe: TRemoveType); virtual;
Public procedure VisibleChangeHere(const Changes: TVisibleChanges); virtual;
Public function World: T3DWorld; virtual;
Public procedure VisibleChangeNotification(const Changes: TVisibleChanges); virtual;
Public procedure GLContextClose; virtual;
Public procedure UpdateGeneratedTextures( const RenderFunc: TRenderFromViewFunction; const ProjectionNear, ProjectionFar: Single; const OriginalViewport: TRectangle); virtual;
Public function Dragging: boolean; virtual;
Public procedure Translate(const T: TVector3Single); virtual;
Public function Middle: TVector3Single; virtual;
Public function Sector: TSector;
Public function Sphere(out Radius: Single): boolean; virtual;
Public function Height(const MyPosition: TVector3Single; out AboveHeight: Single): boolean;
Public function Height(const MyPosition: TVector3Single; out AboveHeight: Single; out AboveGround: P3DTriangle): boolean;
Public function LineOfSight(const Pos1, Pos2: TVector3Single): boolean;
Public function MoveAllowed(const OldPos, ProposedNewPos: TVector3Single; out NewPos: TVector3Single; const BecauseOfGravity: boolean): boolean;
Public function MoveAllowed(const OldPos, NewPos: TVector3Single; const BecauseOfGravity: boolean): boolean;
Public function Move(const Translation: TVector3Single; const BecauseOfGravity: boolean; const EnableWallSliding: boolean = true): boolean;
Public function Ray(const RayOrigin, RayDirection: TVector3Single): TRayCollision;
Public function Shared: T3D; virtual;

Properties

Public property Exists: boolean read FExists write FExists default true;
Public property Collides: boolean read FCollides write FCollides default true;
Public property CastShadowVolumes: boolean read FCastShadowVolumes write FCastShadowVolumes default true;
Public property Parent: T3DList read FParent;
Public property Cursor: TMouseCursor read FCursor write SetCursor default mcDefault;
Public property CollidesWithMoving: boolean read FCollidesWithMoving write FCollidesWithMoving default false;

Description

Methods

Protected procedure CursorChange; virtual;

In T3D class, just calls Parent.CursorChange.

Protected function GetExists: boolean; virtual;

Does item really exist, see Exists and Enable, Disable. It T3D class, returns True if Exists and not disabled. May be modified in subclasses, to return something more complicated.

Protected function GetCollides: boolean; virtual;

Does item really collide, see Collides. It T3D class, returns Collides and GetExists. May be modified in subclasses, to return something more complicated.

Protected function HeightCollision(const Position, GravityUp: TVector3Single; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc; out AboveHeight: Single; out AboveGround: P3DTriangle): boolean; virtual;

Height of a point above the 3D model. This checks ray collision, from Position along the negated GravityUp vector. Measures distance to the nearest scene item (called "ground" here).

Parameters
AboveHeight
Height above the ground. One height unit equals one GravityUp vector. Always use normalized GravityUp vector if you expect to receive here a normal distance.

AboveHeight is always set to MaxSingle when returned result is False (this guarantee simplifies some code).

AboveGround
Pointer to P3DTriangle representing the ground. Must be Nil if returned result is False. May be Nil even if we returned True (not all 3D objects may be able to generate P3DTriangle information about collision).

This may be useful for example to make a footsteps sound dependent on texture of the ground. Or to decrease player life points for walking on hot lava. See "The Castle" game for examples.

Returns

If the 3D scene is hit. False means that Position floats above an empty space. That is, if you turn gravity on, it will fall down forever, as far as this 3D scene is concerned.

Protected function MoveCollision( const OldPos, ProposedNewPos: TVector3Single; out NewPos: TVector3Single; const IsRadius: boolean; const Radius: Single; const OldBox, NewBox: TBox3D; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc): boolean; virtual;

Can other 3D object (maybe a player) move without colliding with this object.

If IsRadius, then you should prefer to perform exact collision with sphere of given radius (must be > 0). At the very least, this checks that the line segment between OldPos and NewPos doesn't collide, and that sphere with given Radius centered around NewPos doesn't collide.

If not IsRadius, or if checking for collisions with sphere is not possible for some reasons, then you can check for collisions with boxes. OldBox should usually be ignored (it can be useful when collision-checking has to be approximate in some corner cases, see TCreature.MoveCollision). NewBox plays the same role as "sphere centered around NewPos" in paragraph above.

Overloaded version with separate ProposedNewPos and NewPos parameters allows you to accept the move, but for NewPos (that should be some slightly modified version of ProposedNewPos). This allows to implement wall-sliding: when camera tries to walk into the wall, we will change movement to move alongside the wall (instead of just completely blocking the move). When this version returns False, it's undefined what is the NewPos.

Protected function MoveCollision( const OldPos, NewPos: TVector3Single; const IsRadius: boolean; const Radius: Single; const OldBox, NewBox: TBox3D; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc): boolean; virtual;
 
Protected function SegmentCollision(const Pos1, Pos2: TVector3Single; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc; const ALineOfSight: boolean): boolean; virtual;
 
Protected function SphereCollision(const Pos: TVector3Single; const Radius: Single; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc): boolean; virtual;
 
Protected function BoxCollision(const Box: TBox3D; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc): boolean; virtual;
 
Protected function RayCollision(const RayOrigin, RayDirection: TVector3Single; const TrianglesToIgnoreFunc: T3DTriangleIgnoreFunc): TRayCollision; virtual;

Check collision with a ray, building a TRayCollision result. Returns a collision as TRayCollision instance, or Nil if no collision. Caller is responsible for freeing the returned TRayCollision instance.

Contrary to other collision routines, this should ignore the Collides property. The Collides property specifies whether item collides with camera. And this method is used for picking (pointing) 3D stuff — everything visible can be picked, collidable or not.

This always returns the first collision with the 3D world, that is the one with smallest TRayCollision.Distance. For example, when implemented in T3DList, this checks collisions for all list items, and chooses the closest one.

Public constructor Create(AOwner: TComponent); override;
 
Public destructor Destroy; override;
 
Public procedure Disable;

Items that are at least once disabled are treated like not existing. Every Disable call should always be paired with Enable call (usually using try ... finally .... end block). Internally, we keep a counter of how many times the object is disabled, and if this counter is <> 0 then GetExists returns False. Using this is useful for taming collisions, especially to avoid self-collisions (when a creature moves, it doesn't want to collide with other creatures, but obviously it doesn't collide with it's own bounding volume).

Public procedure Enable;
 
Public function BoundingBox: TBox3D; virtual; abstract;

Bounding box of the 3D object.

Should take into account both collidable and visible objects. For examples, invisible walls (not visible) and fake walls (not collidable) should all be accounted here.

As it's a bounding volume, it may naturally be slightly too large (although, for the same of various optimizations, you should try to make it as tight as reasonably possible.) For now, it's also OK to make it a little too small (nothing bad will happen). Although all currently implemented descendants (TCastleSceneCore, TCastlePrecalculatedAnimationCore, more) guarantee it's never too small.

Public procedure Render(const Frustum: TFrustum; const Params: TRenderParams); virtual;

Render given object. Should check and immediately exit when Exists is False. Should render only parts with matching Params.Transparency and Params.ShadowVolumesReceivers values (it may be called more than once to render frame).

Parameters
Frustum
May be used to optimize rendering, to not render the parts outside the Frustum.
Params
Other parameters helpful for rendering.
Public procedure RenderShadowVolume( ShadowVolumeRenderer: TBaseShadowVolumeRenderer; const ParentTransformIsIdentity: boolean; const ParentTransform: TMatrix4Single); virtual;

Render shadow quads for all the things rendered by Render. This is done only if Exists and CastShadowVolumes.

It does shadow volumes culling inside (so ShadowVolumeRenderer should have FrustumCullingInit already initialized).

ParentTransform and ParentTransformIsIdentity describe the transformation of this object in the 3D world. T3D objects may be organized in a hierarchy when parent transforms it's children. When ParentTransformIsIdentity, ParentTransform must be IdentityMatrix4Single (it's not guaranteed that when ParentTransformIsIdentity = True, Transform value will be ignored !).

Implementation note: In Render, it is usually possible to implement ParentTransform* by glPush/PopMatrix and Frustum.Move tricks. But RenderShadowVolume needs actual transformation explicitly: ShadowMaybeVisible needs actual box position in world coordinates, so bounding box has to be transformed by ParentTransform. And TCastleScene.RenderShadowVolumeCore needs explicit ParentTransform to correctly detect front/back sides (for silhouette edges and volume capping).

Public procedure PrepareResources( Options: TPrepareResourcesOptions; ProgressStep: boolean; BaseLights: TAbstractLightInstancesList); virtual;

Prepare resources, making various methods (like rendering and such) to execute fast.

This requires OpenGL to be initailized for most 3D objects. If not, some parts of preparations will be aborted.

This makes sure that appropriate methods execute as fast as possible. It's never required to call this method — everything will be prepared "as needed" anyway. But if you allow everything to be prepared "as needed", then e.g. the first Render call may take a long time because it may have to prepare resources that will be reused in next Render calls. This is bad, as your program will seem very slow at the beginning (when rendering resources are prepared, so a first frame, or a couple of first frames, if it's something like a precalculated animation). To avoid this, call this method, showing the user something like "now we're preparing the resources — please wait".

For OpenGL rendered objects, this method ties this object to the current OpenGL context. But it doesn't change any OpenGL state or buffers contents (at most, it allocates some texture and display list names).

Parameters
Options
What features should be prepared to execute fast. See TPrepareResourcesOption, the names should be self-explanatory (they refer to appropriate methods of T3D, TCastleSceneCore or TCastleScene).
ProgressStep
Says that we should make this many Progress.Step calls during preparation. Useful to show progress bar to the user during long preparation.

TODO: for now, do not include prSpatial if you use ProgressStep. Reason: octree preparations have a separate mechanism that may want to show progress.

BaseLights
Used if Options contains prRender. A list of base lights (always TLightInstancesList, although cannot be declated as such) used for rendering. May be Nil (equivalent to empty).
Public function PrepareResourcesSteps: Cardinal; virtual;

How many times PrepareResources will call Progress.Step. Useful only if you want to pass ProgressStep = True to PrepareResources. In the base class T3D this just returns 0.

Public function Press(const Event: TInputPressRelease): boolean; virtual;

Press and release events of key and mouse. Return True if you handled them. See also TUIControl analogous events.

Public function Release(const Event: TInputPressRelease): boolean; virtual;
 
Public function PointingDeviceActivate(const Active: boolean; const Distance: Single): boolean; virtual;

Pointing device (usually mouse) events. Return True if you handled the event.

  • PointingDeviceActivate signals that the picking button (usually, left mouse button) is pressed or released (depending on Active parameter).

    Note that the exact key or mouse responsible for this is configurable in our engine by Input_Interact. By default it's the left mouse button, as is usual for VRML/X3D browsers. But it can be configured to be other mouse button or a key, for example most 3D games use "e" key to interact.

  • PointingDeviceMove signals that pointer moves over this 3D object.

PointingDeviceMove receives Pick information about what exactly is hit by the 3D ray corresponding to the current mouse position. It contains the detailed information about 3D point, triangle and ray (all in local coordinate system) that are indicated by the mouse. PointingDeviceActivate does not receive this information now (because it may happen in obscure situations when ray direction is not known; this is all related to our "fallback to MainScene" mechanism).

They also receive Distance to the collision, in world coordinates. See TRayCollision.Distance.

The pointing device event (activation, deactivation or move) is send first to the innermost 3D object. That is, we first send this event to the first item on TRayCollision list corresponding to the current ray. This way, the innermost ("most local") 3D object has the chance to handle this event first. If the event is not handled, it is passed to other 3D objects (we simply iterate over the TRayCollision list). If nothing on TRayCollision list handled the item, it is eventually passed to main 3D scene (TCastleSceneManager.MainScene), if it wasn't already present on TRayCollision list.

Note that when passing this event to TCastleSceneManager.MainScene, it is possible that 3D ray simply didn't hit anything (mouse pointer is over the background). In this case, TRayCollisionNode.Point is undefined, TRayCollisionNode.Triangle is Nil and Distance is MaxSingle.

This event should be handled only if GetExists. Usually, 3D objects with GetExists = False will not be returned by RayCollision, so they will not receive this event anyway. However, if 3D object may be equal to TCastleSceneManager.MainScene, then it should be secured and check for GetExists inside PointingDeviceActivate and PointingDeviceMove.

Public function PointingDeviceMove(const Pick: TRayCollisionNode; const Distance: Single): boolean; virtual;
 
Public procedure Update(const SecondsPassed: Single; var RemoveMe: TRemoveType); virtual;

Continously occuring event, for various tasks.

Parameters
RemoveMe
Set this to rtRemove or rtRemoveAndFree to remove this item from 3D world (parent list) after Update finished. rtRemoveAndFree additionally will free this item. Initially it's rtNone when this method is called.
Public procedure VisibleChangeHere(const Changes: TVisibleChanges); virtual;

Something visible changed inside this 3D object. This is usually called by implementation of this 3D object, to notify others that it changed.

Changes is a set describing what changes occurred. It can be [], meaning "something else", we'll still broadcast VisibleChangeNotification then. See TVisibleChange docs for possible values. It must specify all things that possibly changed.

The information about visibility changed is passed upward, to the Parent, and eventually to the TCastleSceneManager, that broadcasts this to all 3D objects by VisibleChangeNotification. If you want to react to visibility changes, you should override VisibleChangeNotification, not this method.

Be careful when handling this, various changes may cause this, so be prepared to handle this at every time.

Public function World: T3DWorld; virtual;

World containing this 3D object. In other words, the root of 3D objects tree containing this object. Nil if we are not part of a hierarchy rooted in T3DWorld.

Public procedure VisibleChangeNotification(const Changes: TVisibleChanges); virtual;

Something visible changed in the 3D world. This is usually called by our container (like TCastleSceneManager), to allow this 3D object to react (e.g. by regenerating mirror textures) to changes in the 3D world (not necessarily in this 3D object, maybe in some other T3D instance).

If you want to react to visibility changes, you should override this.

Public procedure GLContextClose; virtual;

Called when OpenGL context of the window is destroyed. This will be also automatically called from destructor.

Control should clear here any resources that are tied to the GL context.

Public procedure UpdateGeneratedTextures( const RenderFunc: TRenderFromViewFunction; const ProjectionNear, ProjectionFar: Single; const OriginalViewport: TRectangle); virtual;
 
Public function Dragging: boolean; virtual;

Are we in the middle of dragging something by moving the mouse.

This should be set to True to disable camera navigation methods that also use mouse move. In practice, to disable TExamineCamera view rotation/movement by moving the mouse, as it makes (comfortable) dragging practically impossible (at each mouse move, view changes...).

In particular, when you operate on active X3D pointing-device sensors (like drag sensors, e.g. PlaneSensor, but also TouchSensor may use it).

Public procedure Translate(const T: TVector3Single); virtual;

Unconditionally move this 3D object by given vector. You usually don't want to use this directly, instead use Move method to move checking collisions (and with optional wall sliding).

By default, in T3D class, this does nothing, because the bare T3D class doesn't know how to move itself. But descendants like T3DTransform and T3DOrient (and their descendants like TPlayer, TCreature, TItemOnWorld) override this and can be moved using this.

Public function Middle: TVector3Single; virtual;

Middle point, usually "eye point", of the 3D model. This is used for sphere center (if overriden Sphere returns True) and is the central point from which collisions of this object are checked (Move, MoveAllowed, Height, LineOfSight). For 3D things like level scene this is mostly useless (as you will leave Sphere at default False then, and the scene itself doesn't move), but it's crucial for dynamic 3D things like player and moving creatures.

In short, it's usually most comfortable to think about this as a position of the eye, or the middle of the creature's head.

In an ideal situation, it should not be based on anything dynamic. For example, when this is based on the current bounding box of the animation, there is a risk that a large and sudden change in animation box could make the Middle point to jump to the other side of the wall (breaking collisions, as it changes Middle without a chance to check for collisions by MoveAllowed). Ideally, it should remain constant even when the shape of the object changes, and be possible to change only when MoveAllowed is checked (so only when T3DOrient.Position or T3DTransform.Translation can change).

In this class this is simply zero. In the descendant T3DCustomTransform (ancestor of T3DTransform, T3DOrient that in turn are ancestors of normal creatures, items etc.) this is overriden to return something sensible above the bottom of the box. See T3DCustomTransform.MiddleHeight.

Public function Sector: TSector;

Sector where the middle of this 3D object is. Used for AI. Nil if none (maybe because we're not part of any world, maybe because sectors of the world were not initialized, or maybe simply because we're outside of all sectors).

Public function Sphere(out Radius: Single): boolean; virtual;

Can the approximate sphere (around Middle point) be used for some collision-detection tasks. If True then Radius (and Middle point) determine the approximate sphere surrounding the 3D object (it does not have to be a perfect bounding sphere around the object), and it may be used for some collisions instead of BoundingBox. See CollidesWithMoving and MoveAllowed for when it may happen.

Must return False when not GetExists (because we can't express "empty sphere" by Sphere method for now, but BoundingBox can express EmptyBox3D).

By default, in T3D class, this always returns False and Sphere is undefined.

The advantages of using a sphere, that does not have to be a perfect bounding sphere (it may be smaller than necessary, and only account e.g. for upper body part of the creature), are:

  • It can have constant radius, even though the actual creature animates. This allows us to perfectly, reliably guarantee that sphere absolutely never collides with level and such.

    In case of a tight bounding volume (box or sphere) that animates, this guarantee is not really possible. Simply increasing time changes the animation to the next frame, which may be slightly larger in one dimension because e.g. creature moves a hand in this direction. This means that simply increasing time may change the non-collidable creature into a collidable one, if creature stands close to a wall/other creature and such. And we cannot simply stop/reverse an arbitrary animation at an arbitrary time (to avoid collision), this would look weird for some animations and would require some additional work at preparing animations and designing AI (as then "every action can be interrupted").

    Also using a bounding volume large enough to account for all possible positions is not doable, as it would be too large. Consider that for humanoid creatures, walking animation usually has tall and thin bounding box (creature stands) but dead/lying animation usually has flat and wide bounding box.

    So, only a bounding volume (like a sphere) that may be smaller than bounding volume can remain constant and easily guarantee the assertion "it never collides".

    This means that using such sphere results in simpler collision detection routines, as they may assume that collision doesn't occur. In contrast, detection routines looking at our (possibly animated) BoundingBox must take into account that collision may already be happening, and they must incorporate code to allow creatures/players to "get unstruck".

  • Using smaller sphere also allows to naturally ascend the stairs and upward slopes. Sphere can move forward slightly, and then creature may raise up, to reach it's preferred height. Then sphere can move further forward, and so on. This alllows to allow stair climbing for creatures without any extra effort in the code.

    The downside is that creature legs will temporarily "sink into the floor" when climbing up the stairs. But it's not noticeable if "growing up" mechanism works fast enough.

Sphere disadvantage:

  • Sphere is far from perfect as a bounding volume — it's too small, sometimes also too large, sometimes both at the same time...

    Since the Sphere radius remains always the same, it must be good for many creature animation frames. In cases where the sphere isn't suitable, and you don't need advantages above — you can make Sphere return False. E.g. a dead creature may be stuck in a wall, and it doesn't have to climb stairs. So you don't really need sphere advantages listed above, and Sphere may return False when creature is in dying state.

    But still it may be a problem sometimes, if some creature states have entirely different animations and bounding boxes. Then you will be forced to choose one universal Radius for all creature states. And you need constant radius to keep the advantage above of "guarantee".

    1. Obviously you can't set radius too small, because if it's much smaller than actual creature's geometry then the creature will noticeably collide with level geometry and other creatures.

    2. On the other hand, you can't set radius too large (or move sphere center, Middle, much lower). This would block stair climbing.

Public function Height(const MyPosition: TVector3Single; out AboveHeight: Single): boolean;

Get height of my point above the rest of the 3D world.

This ignores the geometry of this 3D object (to not accidentaly collide with your own geometry), and checks collisions with the rest of the world.

Public function Height(const MyPosition: TVector3Single; out AboveHeight: Single; out AboveGround: P3DTriangle): boolean;
 
Public function LineOfSight(const Pos1, Pos2: TVector3Single): boolean;
 
Public function MoveAllowed(const OldPos, ProposedNewPos: TVector3Single; out NewPos: TVector3Single; const BecauseOfGravity: boolean): boolean;

Is the move from OldPos to ProposedNewPos possible for me. Returns true and sets NewPos if some move is allowed. Overloaded version without ProposedNewPos doesn't do wall-sliding, and only answers if exactly this move is allowed.

If this 3D object allows to use sphere as the bounding volume (see Sphere), then this sphere must be centered around OldPos, not some other point. That is, we assume that Sphere returns Center that is equal to OldPos.

This ignores the geometry of this 3D object (to not accidentaly collide with your own geometry), and checks collisions with the rest of the world.

Public function MoveAllowed(const OldPos, NewPos: TVector3Single; const BecauseOfGravity: boolean): boolean;
 
Public function Move(const Translation: TVector3Single; const BecauseOfGravity: boolean; const EnableWallSliding: boolean = true): boolean;

Move, if possible (no collisions). This is the simplest way to move a 3D object, and a basic building block for artificial intelligence of creatures.

Checks move possibility by MoveAllowed, using Middle point. Actual move is done using Translate.

Public function Ray(const RayOrigin, RayDirection: TVector3Single): TRayCollision;

Cast a ray from myself to the world, see what is hit.

This ignores the geometry of this 3D object (to not accidentaly collide with your own geometry), and checks collisions with the rest of the world.

Public function Shared: T3D; virtual;

In case this scene shares lights with other scenes, this is the source scene. In usual circumstances, this method simply returns Self, which means "no sharing". In case of scenes that are children of TCastlePrecalculatedAnimation, their Shared methods all point to the 1st animation scene.

Properties

Public property Exists: boolean read FExists write FExists default true;

Is this object visible and colliding.

Setting this to False pretty much turns everything of this 3D object to "off". This is useful for objects that disappear completely from the level when something happens. You could just as well remove this object from TCastleSceneManager.Items tree, but sometimes it's more comfortable to simply turn this property to False.

Descendants may also override GetExists method.

Public property Collides: boolean read FCollides write FCollides default true;

Should this 3D object participate in collision detection. You can turn this off, useful to make e.g. "fake" walls (to some secret places on level).

This describes collision resolution with almost everything — camera, player (in third-person perspective, camera may differ from player), other creatures. That is because everything resolves collisions through our methods MoveCollision and HeightCollision (high-level) or SegmentCollision, SphereCollision, BoxCollision (low-level). (Note that RayCollision is excluded from this, it exceptionally ignores Collides value, as it's primarily used for picking. Same for SegmentCollision with LineOfSight=true.)

The only exception are the collisions with T3DMoving instances (movable world parts like elevators and doors) that have their own detection routines and look at CollidesWithMoving property of other objects. That is, the T3DMoving instance itself must still have Collides = True, but it interacts with other objects if and only if they have CollidesWithMoving = True (ignoring their Collides value). This allows items to be moved by elevators, but still player and creatures can pass through them.

Note that if not Exists then this doesn't matter (not existing objects never participate in collision detection).

Descendants may also override GetCollides method. Sometimes it's more comfortable than changing the property value.

Public property CastShadowVolumes: boolean read FCastShadowVolumes write FCastShadowVolumes default true;

Does the 3D object cast shadows by shadow volumes. See also TCastleScene.ReceiveShadowVolumes.

Public property Parent: T3DList read FParent;

Containing 3D list.

Public property Cursor: TMouseCursor read FCursor write SetCursor default mcDefault;

Mouse cursor over this object.

Public property CollidesWithMoving: boolean read FCollidesWithMoving write FCollidesWithMoving default false;

Can this object be pushed by (or block movement of) doors, elevators and other moving level parts (T3DMoving instances).

Some 3D moving objects may try to avoid crushing this item. Like an automatic door that stops it's closing animation to not crush things standing in the doorway.

Some other 3D moving objects may push this object. Like elevators (vertical, or horizontal moving platforms). We may use sphere (see T3D.Sphere) for checking collisions, or bounding box (T3D.BoundingBox), depending on need. The item is moved using T3D.Translate, so make sure it actually does something (for example, by descending from T3DTransform, that provides natural T3D.Translate implementation).


Generated by PasDoc 0.13.0 on 2014-05-01 01:40:59