Class TVRMLTriangleOctree

DescriptionHierarchyFieldsMethodsProperties

Unit

Declaration

type TVRMLTriangleOctree = class(TOctree)

Description

TVRMLTriangleOctree ————————————————————

Hierarchy

Overview

Fields

Public OctreeItems: TDynOctreeItemsArray;
Public DirectCollisionTestsCounter: TCollisionCount;

Methods

Protected function StatisticsBonus( const LeavesCount, ItemsCount, NonLeafNodesCount: Int64): string; override;
Public function TreeRoot: TTriangleOctreeNode;
Public procedure AddItemTriangle(const Triangle: TTriangle3Single; State: TVRMLGraphTraverseState; ShapeNode: TNodeGeneralShape; const MatNum, FaceCoordIndexBegin, FaceCoordIndexEnd: integer);
Public function SegmentCollision( out Intersection: TVector3Single; out IntersectionDistance: Single; const pos1, pos2: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
Public function SegmentCollision( out Intersection: TVector3Single; const pos1, pos2: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
Public function SegmentCollision( out IntersectionDistance: Single; const pos1, pos2: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
Public function SegmentCollision( const pos1, pos2: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
Public function SphereCollision(const pos: TVector3Single; const Radius: Single; const OctreeItemIndexToIgnore: integer; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer;
Public function BoxCollision(const ABox: TBox3d; const OctreeItemIndexToIgnore: integer; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): Integer;
Public function RayCollision( out Intersection: TVector3Single; out IntersectionDistance: Single; const Ray0, RayVector: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
Public function RayCollision( out Intersection: TVector3Single; const Ray0, RayVector: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
Public function RayCollision( out IntersectionDistance: Single; const Ray0, RayVector: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
Public function RayCollision(const Ray0, RayVector: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
Public function MoveAllowedSimple( const OldPos, ProposedNewPos: TVector3Single; const CameraRadius: Single; const OctreeItemIndexToIgnore: integer = NoItemIndex; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc = nil): boolean;
Public function MoveBoxAllowedSimple( const OldPos, ProposedNewPos: TVector3Single; const ProposedNewBox: TBox3d; const OctreeItemIndexToIgnore: integer = NoItemIndex; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc = nil): boolean;
Public function MoveAllowed( const OldPos, ProposedNewPos: TVector3Single; out NewPos: TVector3Single; const CameraRadius: Single; const OctreeItemIndexToIgnore: integer; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): boolean;
Public procedure GetCameraHeight( const CameraPos, GravityUp: TVector3Single; out IsAboveTheGround: boolean; out SqrHeightAboveTheGround: Single; out GroundItemIndex: Integer; const OctreeItemIndexToIgnore: integer; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc);
Public procedure GetCameraHeightZ( const CameraPos: TVector3Single; out IsAboveTheGround: boolean; out HeightAboveTheGround: Single; out GroundItemIndex: Integer; const OctreeItemIndexToIgnore: Integer; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc);
Public class function IgnoreTransparentItem( Octree: TVRMLTriangleOctree; OctreeItemIndex: Integer): boolean;
Public constructor Create(const ARootBox: TBox3d); overload;
Public constructor Create(AMaxDepth, AMaxLeafItemsCount: integer; const ARootBox: TBox3d); overload;
Public destructor Destroy; override;

Description

Fields

Public OctreeItems: TDynOctreeItemsArray;

tu beda zgromadzone wszystkie OctreeItems jakie mamy w drzewie. W lisciach beda tylko ItemsIndices ktore beda indeksami do tej tablicy. Zrobilem to 27.04.2003 gdy zobaczylem w drzewie z ciasno dobranymi MaxDepth i MaxLeafItemsCount jeden trojkat sceny moze byc powielony az 50 000 razy ! To powodowalo zzeranie niesamowitych ilosci pamieci, bo rekord TOctreeItem jest dosc duzy i z czasem pewnie bede go jeszcze rozszerzal. Trzymanie wszystkich elementow w tablicy pozwala mi miec w lapie kazdy element tylko raz. - ponadto unikajac robienia TOctreeItem jako obiektow unikam fragmentacji pamieci - umozliwilem sobie zrobienie OCTREE_ITEM_USE_MAILBOX - umozliwiam realizowanie OctreeItemToIgnore w RayCollision przez szybkie porownywanie indeksow (zamiast np. zawartosci TOctreeItem)

Public DirectCollisionTestsCounter: TCollisionCount;

you can use variable below for testing purposes. It is increemented each time SphereCollision or SegmentCollision or RayCollision makes a direct collision test, that is when some single triangle is tested for collision with a sphere, line segment or ray. When we use octree we expect that this number will be small.

Methods

Protected function StatisticsBonus( const LeavesCount, ItemsCount, NonLeafNodesCount: Int64): string; override;
 
Public function TreeRoot: TTriangleOctreeNode;
 
Public procedure AddItemTriangle(const Triangle: TTriangle3Single; State: TVRMLGraphTraverseState; ShapeNode: TNodeGeneralShape; const MatNum, FaceCoordIndexBegin, FaceCoordIndexEnd: integer);

Add single OctreeItem. Automatically checks whether IsValidTriangle. Przed dodaniem duzej ilosci trojkatow sugerowane jest aby ustalic OctreeItems.AllowedCapacityCount na odpowiednio duza wartosc.

Public function SegmentCollision( out Intersection: TVector3Single; out IntersectionDistance: Single; const pos1, pos2: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;

Ponizej mamy najwazniejsze procedury ktore wykorzystuja cala strukture jaka zbudowalismy zeby efektywnie badac kolizje.

SegmentCollision bada czy segment nie przecina zadnego elementu drzewa

SphereCollision bada czy sfera nie zawiera w sobie choc czesci jakiegos elementu drzewa.

RayCollision bada przeciecie promienia z drzewem.

Procedury zwracaja -1 (co preferujemy wyrazac jako NoItemIndex) jesli nie ma kolizji lub indeks do tablicy OctreeItems na element z ktorym jest kolizja. Pytanie brzmi "ktore przeciecie zwrocic jesli jest ich wiele ?". SphereCollision zwraca ktorykolwiek, podobnie jak Ray/SegmentCollision gdy (not ReturnClosestIntersection). Gdy ReturnClosestIntersection = true to RayCollision zwraca przeciecie najblizsze Ray0, SegmentCollision najblizsze pos1. (pamietaj ze placisz czasem wykonania za przekazanie ReturnClosestIntersection = true, wiec unikaj tego).

Segment/RayCollision uwzgledniaja ze na pewno NIE MA przeciecia z elementem OctreeItemIndexToIgnore, podaj OctreeItemIndexToIgnore = NoItemIndex aby uwzglednial wszystkie elementy (przydatne przy rekurencyjnym ray-tracingu gdy nie chcesz zeby promien odbity/zalamany/cienia omylkowo trafil na powierzchnie z ktorej wlasnie "wychodzisz" - mozna by bylo temu zaradzic tez przez nieznacznie przesuwanie Ray0, ale niniejsza metoda jest duzo bardziej elegancka). OctreeItemIndexToIgnore to naturalnie indeks do tablicy OctreeItems, podobnie jak wynik wszystkich tych funkcji *Collision i podobnie jak elementy TTriangleOctreeNode.ItemsIndices[]

Uwzgledniaja tez ze na pewno nie ma przeciecia z elementami dla ktorych ItemsToIgnoreFunc zwroci true (mozesz przekazac nil aby nie ignorowac nic na podstawie ItemsToIgnoreFunc).

Ponadto jesli podasz IgnoreMarginAtStart to beda ignorowac przeciecia ktore zdarzyly sie *bardzo* blisko Ray0 (lub Pos1). W ten sposob raytracer bedzie w stanie poradzic sobie nawet ze scenami ktore maja nieprawidlowo zdefiniowane (czesciowo zachodzace na siebie) polygony. Takie polygony normalnie generowalyby zbedne cienie (zaslanialyby sie nawzajem). Pozornie podajac IgnoreMarginAtStart = true raytracer moglby czesto nie podawac juz OctreeItemIndexToIgnore (tzn. podac je = NoItemIndex), bo przeciez po to sie zazwyczaj podaje OctreeItemIndexToIgnore. Ale prawda jest taka ze IgnoreMarginAtStart nie daje 100% pewnosci ze unikniemy kolizji z elementem od ktorego zaczelismy (bo on przeciez tylko unika pewnego *malego* marginesu wokol Ray0). W rezultacie i tak nalezy uzywac OctreeItemIndexToIgnore. To raczej podawanie IgnoreMarginAtStart = true jest zbedne, ale niestety jest to pozadane i daje dobre efekty gdy przychodzi do nieprawidlowo zbudowanych scen. A nawet sibenik.3ds i office.mgf.wrl a wiec sceny zrobione niby porzadnie ktorych uzywalem do zasadniczych testow na rayhunterze maja gdzeniegdzie tak nieprawidlowo zbudowane sciany.

Parameters
IntersectionDistance
For RayCollision: Returned IntersectionDistance is the distance along the RayVector: smaller IntersectionDistance, closer to Ray0. IntersectionDistance is always >= 0. Intersection is always equal to Ray0 + RayVector * IntersectionDistance.

For SegmentCollision: analogously, IntersectionDistance is along Pos2 - Pos1. IntersectionDistance is always in 0...1. Intersectio is always equal to Pos1 + (Pos2 - Pos1) * IntersectionDistance.

Public function SegmentCollision( out Intersection: TVector3Single; const pos1, pos2: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
 
Public function SegmentCollision( out IntersectionDistance: Single; const pos1, pos2: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
 
Public function SegmentCollision( const pos1, pos2: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
 
Public function SphereCollision(const pos: TVector3Single; const Radius: Single; const OctreeItemIndexToIgnore: integer; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer;
 
Public function BoxCollision(const ABox: TBox3d; const OctreeItemIndexToIgnore: integer; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): Integer;
 
Public function RayCollision( out Intersection: TVector3Single; out IntersectionDistance: Single; const Ray0, RayVector: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
 
Public function RayCollision( out Intersection: TVector3Single; const Ray0, RayVector: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
 
Public function RayCollision( out IntersectionDistance: Single; const Ray0, RayVector: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
 
Public function RayCollision(const Ray0, RayVector: TVector3Single; const ReturnClosestIntersection: boolean; const OctreeItemIndexToIgnore: integer; const IgnoreMarginAtStart: boolean; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): integer; overload;
 
Public function MoveAllowedSimple( const OldPos, ProposedNewPos: TVector3Single; const CameraRadius: Single; const OctreeItemIndexToIgnore: integer = NoItemIndex; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc = nil): boolean;

This checks if move between OldPos and ProposedNewPos is possible, by checking is segment between OldPos and ProposedNewPos free and sphere (with radius CameraRadius) ProposedNewPos is free.

CameraRadius must obviously be > 0.

See MoveAllowed for some more sophisticated way of collision detection.

OctreeItemIndexToIgnore and ItemsToIgnoreFunc meaning is just like for RayCollision. This can be used to allow camera to walk thorugh some surfaces (e.g. through water surface, or to allow player to walk through some "fake wall" and discover secret room in game etc.).

See also
TMatrixWalker.DoMoveAllowed is some place where you can use this function
DoMoveAllowed will be used when user will move in the scene, i.e. when user will want to change CameraPos.
Public function MoveBoxAllowedSimple( const OldPos, ProposedNewPos: TVector3Single; const ProposedNewBox: TBox3d; const OctreeItemIndexToIgnore: integer = NoItemIndex; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc = nil): boolean;

This is like MoveAllowedSimple, but it checks for collision around ProposedNewPos using TBox3d instead of a sphere.

Public function MoveAllowed( const OldPos, ProposedNewPos: TVector3Single; out NewPos: TVector3Single; const CameraRadius: Single; const OctreeItemIndexToIgnore: integer; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc): boolean;

This is like MoveAllowedSimple, but in some cases where MoveAllowedSimple would answer "false", this will answer "true" and will set NewPos to some other position (close to ProposedNewPos) that user is allowed to move into. This is used to allow user who is trying to walk "into the wall" to "move alongside the wall" (instead of just completely blocking his move, like MoveAllowedSimple would do).

Always when MoveAllowedSimple would return true, this will also answer true and set NewPos to ProposedNewPos.

CameraRadius must obviously be > 0.

Note that it sometimes modifies NewPos even when it returns false. Such modification has no meaning to you. So you should not assume that NewPos is not modified when it returns with false. You should assume that when it returns false, NewPos is undefined (especiall since NewPos is "out" parameter and it may be implicitly modified anyway).

OctreeItemIndexToIgnore and ItemsToIgnoreFunc meaning is just like for RayCollision.

See also
TMatrixWalker.DoMoveAllowed is some place where you can use this function
DoMoveAllowed will be used when user will move in the scene, i.e. when user will want to change CameraPos.
Public procedure GetCameraHeight( const CameraPos, GravityUp: TVector3Single; out IsAboveTheGround: boolean; out SqrHeightAboveTheGround: Single; out GroundItemIndex: Integer; const OctreeItemIndexToIgnore: integer; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc);

For given camera position and up vector, calculate camera height above the ground. This is comfortable for cooperation with TMatrixWalker.OnGetCameraHeight.

This simply checks collision of a ray from CameraPos in direction -GravityUp, and sets IsAboveTheGround and SqrHeightAboveTheGround as needed.

Also GroundItemIndex is set to index of octree item immediately below the camera (if IsAboveTheGround). This can be handy to detect e.g. that player walks on hot lava and he should be wounded, or that he walks on concrete/grass ground (to set his footsteps sound accordingly). If IsAboveTheGround then for sure GroundItemIndex <> NoItemIndex.

OctreeItemIndexToIgnore and ItemsToIgnoreFunc meaning is just like for RayCollision.

Public procedure GetCameraHeightZ( const CameraPos: TVector3Single; out IsAboveTheGround: boolean; out HeightAboveTheGround: Single; out GroundItemIndex: Integer; const OctreeItemIndexToIgnore: Integer; const ItemsToIgnoreFunc: TOctreeItemIgnoreFunc);

This is just like GetCameraHeight, but it assumes that GravityUp = (0, 0, 1) and it returns the actual HeightAboveTheGround (not it's square). Thanks to the fact that calculating HeightAboveTheGround doesn't require costly Sqrt operation in case of such simple GravityUp.

Public class function IgnoreTransparentItem( Octree: TVRMLTriangleOctree; OctreeItemIndex: Integer): boolean;

This makes transparent triangles (with material with Transparency > 0) ignored (i.e. returns True for them). This is a prepared function compatible with TOctreeItemIgnoreFunc function type.

Public constructor Create(const ARootBox: TBox3d); overload;
 
Public constructor Create(AMaxDepth, AMaxLeafItemsCount: integer; const ARootBox: TBox3d); overload;
 
Public destructor Destroy; override;
 

Generated by PasDoc 0.10.0 on 2008-02-25 00:00:46