Class TVRMLFlatScene

DescriptionHierarchyFieldsMethodsProperties

Unit

Declaration

type TVRMLFlatScene = class(TObject)

Description

This class represents a VRML scene (that is, graph of VRML nodes rooted in RootNode) deconstructed to a list of TVRMLShapeState objects. The basic idea is to "have" at the same time hierarchical view of the scene (in RootNode) and a flattened view of the same scene (in ShapeStates list).

Unfortunately this means that things get a little more complicated if you want to dynamically change the scene. Although whole TVRMLNode class works very nicely and you can freely change any part of it, add, delete and move nodes around and change their properties, this is no longer so easy with TVRMLFlatScene. Basically you can just call ChangedAll after changing some things inside RootNode, but you should also take a look at other Changed* methods defined here.

In exchange, this class provides many functionality and most things work very quickly if the scene is more-or-less static. E.g. methods [Local]BoundingBox, Vertices/TrianglesCount cache their results so after the first call to TrianglesCount next calls to the same method will return instantly (assuming that scene did not changed much). And the ShapeStates list is the key to various processing of the scene, most important it's the key to write a flexible OpenGL renderer of the VRML scene.

Also, VRML2ActiveLights are magically updated for all states in ShapeStates list. This is crucial for lights rendering in VRML 2.0.

Hierarchy

Overview

Methods

Public constructor Create(ARootNode: TVRMLNode; AOwnsRootNode: boolean);
Public destructor Destroy; override;
Public function BoundingBox: TBox3d;
Public function VerticesCount(OverTriangulate: boolean): Cardinal;
Public function TrianglesCount(OverTriangulate: boolean): Cardinal;
Public procedure ChangedAll; virtual;
Public procedure ChangedShapeStateFields(ShapeStateNum: Integer); virtual;
Public procedure ChangedFields(Node: TVRMLNode);
Public function Info(InfoTriVertCounts, InfoBoundingBox: boolean): string;
Public procedure WritelnInfoNodes;
Public function CreateTriangleOctree(const ProgressTitle: string): TVRMLTriangleOctree; overload;
Public function CreateTriangleOctree(AMaxDepth, AMaxLeafItemsCount: integer; const ProgressTitle: string): TVRMLTriangleOctree; overload;
Public function CreateShapeStateOctree(const ProgressTitle: string): TVRMLShapeStateOctree; overload;
Public function CreateShapeStateOctree(AMaxDepth, AMaxLeafItemsCount: integer; const ProgressTitle: string): TVRMLShapeStateOctree; overload;
Public function GetViewpoint( out CamKind: TVRMLCameraKind; out CamPos, CamDir, CamUp, GravityUp: TVector3Single; const ViewpointDescription: string = ''): TNodeGeneralViewpoint;
Public function GetPerspectiveViewpoint( out CamPos, CamDir, CamUp, GravityUp: TVector3Single; const ViewpointDescription: string = ''): TNodeGeneralViewpoint;
Public procedure EnumerateViewpoints(ViewpointFunction: TViewpointFunction);
Public function FogNode: TNodeFog;
Public function FogDistanceScaling: Single;
Public function CreateTrianglesList(OverTriangulate: boolean): TDynTriangle3SingleArray;
Public function TrianglesList(OverTriangulate: boolean): TDynTriangle3SingleArray;
Public function ManifoldEdges: TDynManifoldEdgeArray;
Public function BorderEdges: TDynBorderEdgeArray;
Public procedure ShareManifoldAndBorderEdges( ManifoldShared: TDynManifoldEdgeArray; BorderShared: TDynBorderEdgeArray);
Public procedure FreeResources(Resources: TVRMLSceneFreeResources);

Properties

Public property ShapeStates: TVRMLShapeStatesList read FShapeStates;
Public property RootNode: TVRMLNode read FRootNode write FRootNode;
Public property OwnsRootNode: boolean read FOwnsRootNode write FOwnsRootNode;
Public property DefaultTriangleOctree: TVRMLTriangleOctree read FDefaultTriangleOctree write FDefaultTriangleOctree;
Public property DefaultShapeStateOctree: TVRMLShapeStateOctree read FDefaultShapeStateOctree write FDefaultShapeStateOctree;
Public property OwnsDefaultTriangleOctree: boolean read FOwnsDefaultTriangleOctree write FOwnsDefaultTriangleOctree default true;
Public property OwnsDefaultShapeStateOctree: boolean read FOwnsDefaultShapeStateOctree write FOwnsDefaultShapeStateOctree default true;

Description

Methods

Public constructor Create(ARootNode: TVRMLNode; AOwnsRootNode: boolean);
 
Public destructor Destroy; override;
 
Public function BoundingBox: TBox3d;

Calculate bounding box, number of triangls and vertexes of all shapa states. For detailed specification of what these functions do (and what does OverTriangulate mean) see appropriate VRMLNodes.TNodeGenaralShape methods. Here, we just sum results of TNodeGenaralShape methods for all shapes.

Public function VerticesCount(OverTriangulate: boolean): Cardinal;
 
Public function TrianglesCount(OverTriangulate: boolean): Cardinal;
 
Public procedure ChangedAll; virtual;

ta klasa zapamietuje sobie pewne przeliczone rzeczy w swoich polach, w zwiazku z czym musi byc powiadamiana gdy dokonasz jakichs zmian w strukturze RootNode.

Wywolaj ChangedAll gdy zmieniles po prostu cokolwiek - zupelnie cala scene VRML'a zapisana w RootNode (dodales/usunales/przesunales jakies node'y), zupelnie dowolne pola dowolnych node'ow.

Wywolaj ChangedShapeStateFields(i) gdy zmieniles tylko zawartosci pol node'a ShapeList[i].ShapeNode, node'ow ShapeList[i].State.Last* i node'ow ShapeList[i].State.Active*. (i jestes PEWIEN ze node ktorego pole zmieniles nie wystepuje w innych ShapeState'ach).

Wywolaj ChangedFields gdy zmieniles pola danego Node'a. Mozesz podac Node ktory jest lub ktorego nie ma w aktualnym grafie VRML'a zaczepionym w RootNode, moze byc w czesci aktywnej lub nieaktywnej (takiej do ktorej nie dociera Traverse) tego grafu, moze byc Node'm dowolnej klasy, moze byc takze jednym z Node'ow StateDefaultNodes ktory wziales z jakiegos State.LastNodes[] - to wszystko tutaj uwzglednimy i wywolanie ChangedFields rozlozy sie na wywolania innych Changed. To jest prawdopodobnie najwygodniejsze sposrod Changed*.

Notka dla implementatorow podklas : jak widac ChangedAll i ChangedShapeStateFields sa wirtualne i moga byc pokryte. Oczywiscie musisz wywolac inherited w podklasie. ChangedAll jest wywolywane pod koniec konstruktora w tej klasie, wiec wystarczy ze cala inicjalizacje umiescisz w ChangedAll.

Public procedure ChangedShapeStateFields(ShapeStateNum: Integer); virtual;
 
Public procedure ChangedFields(Node: TVRMLNode);
 
Public function Info(InfoTriVertCounts, InfoBoundingBox: boolean): string;

Returns short information about the scene. This consists of a few lines, separated by KambiUtils.NL. Last line also ends with KambiUtils.NL.

Public procedure WritelnInfoNodes;

Write contents of all VRML "Info" nodes. Also write how many Info nodes there are in the scene.

Public function CreateTriangleOctree(const ProgressTitle: string): TVRMLTriangleOctree; overload;

Creates triangle octree and inits it with our BoundingBox and adds all triangles from our ShapeStates. (generated using ShapeNode.Triangulate(State, false, ...) (note : OverTriangulate = false because it's not necessary for collision detection))

If ProgressTitle <> '' then it uses Progress while building octree.

Remember that such octree has a reference to Shape nodes inside RootNode vrml tree and to State objects inside our ShapeStates list. So you must not use this octree after freeing this object. Also you must rebuild such octree when this object changes.

Note: remember that this is a function and it returns created octree object. It does *not* set value of property DefaultTriangleOctree. But of course you can use it (and you often will) in code like Scene.DefaultTriangleOctree := Scene.CreateTriangleOctree(...)

Public function CreateTriangleOctree(AMaxDepth, AMaxLeafItemsCount: integer; const ProgressTitle: string): TVRMLTriangleOctree; overload;
 
Public function CreateShapeStateOctree(const ProgressTitle: string): TVRMLShapeStateOctree; overload;

Creates shapestate octree and inits it with our BoundingBox and adds all our ShapeStates.

If ProgressTitle <> '' then it uses Progress while building octree.

Remember that such octree has a reference to our ShapeStates list. So you must not use this octree after freeing this object. Also you must rebuild such octree when this object changes.

Note: remember that this is a function and it returns created octree object. It does *not* set value of property DefaultShapeStateOctree. But of course you can use it (and you often will) in code like Scene.DefaultShapeStateOctree := Scene.CreateShapeStateOctree(...)

Public function CreateShapeStateOctree(AMaxDepth, AMaxLeafItemsCount: integer; const ProgressTitle: string): TVRMLShapeStateOctree; overload;
 
Public function GetViewpoint( out CamKind: TVRMLCameraKind; out CamPos, CamDir, CamUp, GravityUp: TVector3Single; const ViewpointDescription: string = ''): TNodeGeneralViewpoint;

GetViewpoint and GetPerspectiveViewpoint return the properties of the defined Viewpoint in VRML file, or some default viewpoint properties if no viewpoint is defined in file. They seek for nodes Viewpoint (for VRML 2.0), PerspectiveCamera and OrthographicCamera (for VRML 1.0) in scene graph.

GetPerspectiveViewpoint omits OrthographicCamera.

If ViewpointDescription = '', they return the first found Viewpoint. Otherwise, they look for Viewpoint with description field mathing given string.

Jezeli VRML posiada node kamery zdefiniowany w aktywnej czesci swojego grafu to oblicza swoje zmienne "out" na podstawie tego node'a, wpp. zwraca domyslne ulozenia kamery w VRMLu, zgodnie ze specyfik. VRMLa (tzn. CamPos = (0, 0, 1), CamDir = (0, 0, -1), CamUp = GravityUp = (0, 1, 0), CamType = ctPerspective (ze domyslna kamera jest ctPerspective to juz sam sobie dopowiedzialem)).

If camera properties were found in some node, it returns this node. Otherwise it returns nil. This way you can optionally extract some additional info from used viewpoint node, or do something special if default values were used. Often you will just ignore result of this function — after all, the most important feature of this function is that you don't have to care about details of dealing with camera node.

Zwraca zawsze znormalizowane CamDir i CamUp i GravityUp — powody takie same jak dla TNodeGeneralViewpoint.GetCameraVectors.

Public function GetPerspectiveViewpoint( out CamPos, CamDir, CamUp, GravityUp: TVector3Single; const ViewpointDescription: string = ''): TNodeGeneralViewpoint;
 
Public procedure EnumerateViewpoints(ViewpointFunction: TViewpointFunction);

This enumerates all viewpoint nodes (Viewpoint (for VRML 2.0), PerspectiveCamera and OrthographicCamera (for VRML 1.0)) in scene graph. For each such node, it calls ViewpointFunction.

Essentially, this is a trivial wrapper over RootNode.Traverse that returns only TNodeGeneralViewpoint.

Public function FogNode: TNodeFog;

FogNode zwraca aktualny node Fog w tym modelu VRMLa, lub nil jesli nie ma aktywnego node'u fog.

FogDistanceScaling zwraca skalowanie tego node'a, wziete z transformacji w miejscu gdzie sie znajduje node Fog w hierarchii VRMLa. You should always multiply FogNode.FdVisibilityRange.Value by FogDistanceScaling when applying (rendering etc.) this fog node. Value of FogDistanceScaling is undefined if FogNode = nil.

Wyniki tych funkcji sa "cachowane" wiec nie ma strachu - mozna uzywac tych funkcji czesto, dopoki nie bedziesz w miedzyczasie zmienial modelu VRMLa to te funkcje beda prosto zwracaly juz przeliczone wyniki, bez zadnej straty czasu.

Public function FogDistanceScaling: Single;
 
Public function CreateTrianglesList(OverTriangulate: boolean): TDynTriangle3SingleArray;

This returns an array of all triangles of this scene. I.e. it triangulates the scene, adding all non-degenerated (see IsValidTriangles) triangles to the list.

It's your responsibility what to do with resulting object, when to free it etc.

Public function TrianglesList(OverTriangulate: boolean): TDynTriangle3SingleArray;

Just like CreateTrianglesList, but results of this function are cached, and returned object is read-only for you. Don't modify it, don't free it.

Public function ManifoldEdges: TDynManifoldEdgeArray;

ManifoldEdges is a list of edges that have exactly two neighbor triangles, and BorderEdges is a list of edges that have exactly one neighbor triangle. These are crucial for rendering shadows using shadow volumes.

Edges with more than two neighbors are allowed. If an edge has an odd number of neighbors, it will be placed in BorderEdges. Every other pair of neighbors will be "paired" and placed as one manifold edge inside ManifoldEdges. So actually edge with exactly 1 neighbor (odd number, so makes one BorderEdges item) and edge with exactly 2 neighbors (even number, one pair of triangles, makes one item in ManifoldEdges) — they are just a special case of a general rule, that allows any neighbors number.

Note that vertexes must be consistently ordered in triangles. For two neighboring triangles, if one triangle's edge has order V0, V1, then on the neighbor triangle the order must be reversed (V1, V0). This is true in almost all situations, for example if you have a closed solid object and all outside faces are ordered consistently (all CCW or all CW). Failure to order consistently will result in edges not being "paired", i.e. we will not recognize that some 2 edges are in fact one edge between two neighboring triangles — and this will result in more edges in BorderEdges.

Both of these lists are calculated at once, i.e. when you call ManifoldEdges or BorderEdges for the 1st time, actually both ManifoldEdges and BorderEdges are calculated at once. If all edges are in ManifoldEdges, then the scene is a correct closed manifold, or rather it's composed from any number of closed manifolds.

Results of these functions are cached, and are also owned by this object. So don't modify it, don't free it.

This uses TrianglesList(false).

Public function BorderEdges: TDynBorderEdgeArray;
 
Public procedure ShareManifoldAndBorderEdges( ManifoldShared: TDynManifoldEdgeArray; BorderShared: TDynBorderEdgeArray);

This allows you to "share" ManifoldEdges and BorderEdges values between TVRMLFlatScene instances, to conserve memory and preparation time. The values set here will be returned by following ManifoldEdges and BorderEdges calls. The values passed here will not be owned by this object — you gave this, you're responsible for freeing it.

This is handy if you know that this scene has the same ManifoldEdges and BorderEdges contents as some other scene. In particular, this is extremely handy in cases of animations in TVRMLGLAnimation, where all scenes actually need only a single instance of TDynManifoldEdgeArray and TDynBorderEdgeArray, this greatly speeds up TVRMLGLAnimation loading and reduces memory use.

Note that passing here as values the same references that are already returned by ManifoldEdges / BorderEdges is always guaranteed to be a harmless operation. If ManifoldEdges / BorderEdges was owned by this object, it will remain owned in this case (while in normal sharing situation, values set here are assumed to be owned by something else).

Public procedure FreeResources(Resources: TVRMLSceneFreeResources);
 

Properties

Public property ShapeStates: TVRMLShapeStatesList read FShapeStates;

ShapeStates contents are read-only from outside.

Note that the only place where ShapeStates length is changed in this class is ChangedAll procedure. So e.g. if you want to do something after each change of ShapeStates length, you can simply override ChangedAll and do your work after calling "inherited".

Public property RootNode: TVRMLNode read FRootNode write FRootNode;

This class can be viewed as a wrapper around specified RootNode.

As such it is allowed to change contents of RootNode (however, this object requires notification of such changes via ChangedXxx methods, see their docs). Moreover it is allowed to change value of RootNode and even to set RootNode to nil for some time.

This is useful for programs like view3dscene, that want to have one TVRMLFlatScene for all the lifetime and only replace RootNode value from time to time. This is useful because it allows to change viewed model (by changing RootNode) while preserving values of things like Attributes properties in subclass TVRMLFlatSceneGL.

That's why it is possible to change RootNode and it is even possible to set it to nil. And when When RootNode = nil everything should work – you can query such scene (with RootNode = nil) for Vecrtices/TrianglesCount (answer will be 0), for BoundingBox (answer will be EmptyBox3d), you can render such scene (nothing will be rendered) etc. Scene RootNode = nil will act quite like a Scene with e.g. no TNodeGeneralShape nodes.

Always call ChangedAll when you changed RootNode.

Note that there is also a trick to conserve memory use. After you've done PrepareRender some things are precalculated here, and RootNode is actually not used. So you can free RootNode (and set it to nil here) without calling ChangedAll and some things will just continue to work, unaware of the fact that the underlying RootNode structure is lost. Note that this is still considered a "trick", and you will have to be extra-careful then about what methods/properties from this class. Generally, use only things that you prepared with PrepareRender. So e.g. calling Render or using BoundingBox. If all your needs are that simple, then you can use this trick to save some memory. This is actually useful when using TVRMLGLAnimation, as it creates a lot of intermediate node structures and TVRMLFlatScene instances.

Public property OwnsRootNode: boolean read FOwnsRootNode write FOwnsRootNode;

jezeli OwnsRootNode to zwolni go w destruktorze

Public property DefaultTriangleOctree: TVRMLTriangleOctree read FDefaultTriangleOctree write FDefaultTriangleOctree;

Notes for both DefaultTriangleOctree and DefaultShapeStateOctree:

Everything in my units is done in the spirit that you can create as many octrees as you want for a given scene (both octrees based on triangles and based on shapestates). Also, in some special cases an octree may be constructed in some special way (not only using CreateShapeStateOctree or CreateTriangleOctree) so that it doesn't contain the whole scene from some TVRMLFlatScene object, or it contains the scene from many TVRMLFlatScene objects, or something else.

What I want to say is that it's generally wrong to think of an octree as something that maps 1-1 to some TVRMLFlatScene object. Octrees, as implemented here, are a lot more flexible.

That said, it's very often the case that you actually want to create exactly one octree of each kind (one TVRMLTriangleOctree and one TVRMLShapeStateOctree) for each scene. Properties below make it easier for you. Basically you can use them however you like. They can simply serve for you as some variables inside TVRMLFlatSceneGL that you can use however you like, so that you don't have to declare two additional variables like SceneTriangleOctree and SceneShapeStateOctree each time you define variable Scene: TVRMLFlatScene.

Also, some methods in this class that take an octree from you as a parameter may have some overloaded versions that implicitly use octree objects stored in properties below, e.g. see TVRMLFlatSceneGL.RenderFrustumOctree.

This class modifies these properties in *only* one case: if OwnsDefaultTriangleOctree is true (default value) then at destruction this class calls FreeAndNil(DefaultTriangleOctree). Similar for DefaultShapeStateOctree.

In any case, these properties are not managed by this object. E.g. these octrees are not automaticaly rebuild when you call ChangedAll.

Public property DefaultShapeStateOctree: TVRMLShapeStateOctree read FDefaultShapeStateOctree write FDefaultShapeStateOctree;
 
Public property OwnsDefaultTriangleOctree: boolean read FOwnsDefaultTriangleOctree write FOwnsDefaultTriangleOctree default true;
 
Public property OwnsDefaultShapeStateOctree: boolean read FOwnsDefaultShapeStateOctree write FOwnsDefaultShapeStateOctree default true;
 

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