Object TFrustum

Unit

Declaration

type TFrustum = object(TObject)

Description

Viewing frustum, defined as 6 plane equations. Calculating and operating on such frustum. Frustums with far plane in infinity (typically used in conjunction with shadow volumes) are fully supported by all methods (we just have 5 frustum planes then).

We define this using ObjectPascal old-style "object", to have comfort and low-overhead at the same time.

Hierarchy

  • TObject
  • TFrustum

Overview

Fields

Public Planes: array [TFrustumPlane] of TVector4Single;
Public ZFarInfinity: boolean;

Methods

Public constructor Init(const Matrix: TMatrix4Single);
Public constructor Init(const ProjectionMatrix, ModelviewMatrix: TMatrix4Single);
Public procedure CalculatePoints(out FrustumPoints: TFrustumPointsSingle); overload;
Public procedure CalculatePoints(out FrustumPoints: TFrustumPointsDouble); overload;
Public function SphereCollisionPossible( const SphereCenter: TVector3Single; const SphereRadiusSqr: Single): TFrustumCollisionPossible;
Public function SphereCollisionPossibleSimple( const SphereCenter: TVector3Single; const SphereRadiusSqr: Single): boolean;
Public function Box3DCollisionPossible( const Box: TBox3D): TFrustumCollisionPossible;
Public function Box3DCollisionPossibleSimple( const Box: TBox3D): boolean;
Public function Move(const M: TVector3Single): TFrustum;
Public procedure MoveVar(const M: TVector3Single);
Public function DirectionInside(const Direction: TVector3Single): boolean;
Public function Transform(const M: TMatrix4Single): TFrustum;
Public function ToNiceStr(const Indent: string): string;

Description

Fields

Public Planes: array [TFrustumPlane] of TVector4Single;

Six planes defining the frustum. Direction vectors of these planes must point to the inside of the frustum. Currently, they are always normalized.

Note that if projection has far plane in infinity (indicated by ZFarInfinity) then the far plane will be invalid — first three values of it's equation will be 0.

Public ZFarInfinity: boolean;
 

Methods

Public constructor Init(const Matrix: TMatrix4Single);

Calculate frustum, knowing the combined matrix (modelview * projection).

Public constructor Init(const ProjectionMatrix, ModelviewMatrix: TMatrix4Single);

Calculate frustum, knowing projection and modelview matrices. This is equivalent to 1-parameter Init with Matrix = ModelviewMatrix * ProjectionMatrix. This way you can get from OpenGL your two matrices (modelview and projection) (or you can calculate them using routines like FrustumProjectionMatrix), then pass them to this routine and you get your current viewing frustum.

Public procedure CalculatePoints(out FrustumPoints: TFrustumPointsSingle); overload;

Calculate 8 points of frustum. These points are simply calculated doing ThreePlanesIntersectionPoint on appropriate planes.

Using these points you can easily draw given frustum on screen. Use FrustumPointsQuadsIndexes to obtain indexes to FrustumPoints.

Note that when the far plane is in infinity, the 4 points of the far plane will be "in infinity", that is will have 4th component set to zero. Or, equivalently, they will be directions. Homogeneous coordinates allow us for this, and in fact you can just render such points without any problems in OpenGL.

For good precision, always use TFrustumPointsDouble. Tests show that, while storing the plane equations with Single precision is sufficient, calculating FrustumPoints using Single precision is *not* sufficient.

(Testcase that the Double precision is needed: run view3dscene demo_models/vrml_2/cones.wrl. Jump to viewpoint named "Frustum needs double-precision". Turn "Show viewing frustum" on. When view3dscene.lpr uses Single precision with CalculatePoints (use TFrustumPointsSingle, and GL_FLOAT at glVertexPointer) the result is incorrect, near and far quads are visibly asymetrical.)

Exceptions raised
EPlanesParallel
If Frustum doesn't have planes of any valid frustum.
Public procedure CalculatePoints(out FrustumPoints: TFrustumPointsDouble); overload;
 
Public function SphereCollisionPossible( const SphereCenter: TVector3Single; const SphereRadiusSqr: Single): TFrustumCollisionPossible;

Checks for collision between frustum and sphere.

Check is done fast, but is not accurate, that's why this function's name contains "CollisionPossible". It returns:

fcNoCollision when it's sure that there no collision,

fcSomeCollisionPossible when some collision is possible, but nothing is sure. There *probably* is some collision, but it's not difficult to find some special situations where there is no collision but this function answers fcSomeCollisionPossible. There actually may be either no collision, or only part of sphere may be inside frustum.

Note that it's guaranteed that if the whole sphere (or the whole box in case of Box3DCollisionPossible) is inside the frustum that fcInsideFrustum will be returned, not fcSomeCollisionPossible.

fcInsideFrustum if sphere is for sure inside the frustum.

So this function usually cannot be used for some precise collision detection, but it can be used for e.g. optimizing your graphic engine by doing frustum culling. Note that fcInsideFrustum result is often useful when you're comparing your frustum with bounding volume of some tree (e.g. octree) node: fcInsideFrustum tells you that not only this node collides with frustum, but also all it's children nodes collide for sure with frustum. This allows you to save some time instead of doing useless recursion down the tree.

Many useful optimization ideas used in implementing this function were found at [http://www.flipcode.com/articles/article_frustumculling.shtml].

See also
TFrustum.Box3DCollisionPossible
Checks for collision between frustum and box.
Public function SphereCollisionPossibleSimple( const SphereCenter: TVector3Single; const SphereRadiusSqr: Single): boolean;

Checks for collision between frustum and sphere, faster. Like TFrustum.SphereCollisionPossible, but this only returns true (when TFrustum.SphereCollisionPossible would return fcSomeCollisionPossible or fcInsideFrustum) or false (when TFrustum.SphereCollisionPossible would return fcNoCollision).

Consequently, it runs (very slightly) faster. Use this if you don't need to differentiate between fcSomeCollisionPossible or fcInsideFrustum cases.

Public function Box3DCollisionPossible( const Box: TBox3D): TFrustumCollisionPossible;

Checks for collision between frustum and box. Meaning of return value like SphereCollisionPossible.

Public function Box3DCollisionPossibleSimple( const Box: TBox3D): boolean;

Checks for collision between frustum and box, faster. Meaning of return value like SphereCollisionPossibleSimple.

Public function Move(const M: TVector3Single): TFrustum;
 
Public procedure MoveVar(const M: TVector3Single);
 
Public function DirectionInside(const Direction: TVector3Single): boolean;

Is Direction within a frustum. You can think of direction it as a "point infinitely away in given Direction", like the direction to the sun. Note that this ignores near/far planes of the frustum, only checking the 4 side planes.

Public function Transform(const M: TMatrix4Single): TFrustum;

Transform frustum by a matrix.

Parameters
M
Transformation matrix. This matrix must be "sane": it must transform homogeneous positions into homogeneous positions, and homogeneous directions into homogeneous directions. Also, it must not invert or do other weird stuff (like shear) with directions. To be safe just make sure it's a matrix composed only from translations, rotations, and scale (with all scale parameters being > 0).
Exceptions raised
ETransformedResultInvalid
In some cases when matrix is not sane.
Public function ToNiceStr(const Indent: string): string;
 

Generated by PasDoc 0.14.0.