source: GTP/trunk/Lib/Vis/Preprocessing/manual/integration.tex @ 2111

Revision 2111, 15.0 KB checked in by mattausch, 17 years ago (diff)
Line 
1\section{Introduction}
2\label{sec:introduction}
3
4This manual provides a guide to apply preprocessed visibility in a particular target engine. It
5will start with instruction for building the preprocessor, describes the integration of the
6preprocessor and the generated visibility solution, and last but not least the usage of
7the view cells within the target engine.
8
9\section{Build Project}
10\label{sec:build}
11
12Open the {\em GtpVisibility.sln} with {\em Visual Studio 2003} (2005 might work, but we did not test it recently).
13Set the build target to {\em Release}. Build the project {\em TestPreprocessor}. Now there should be a newly built
14executable {\em Preprocessor.exe} in {\em bin{/}release} and a library {\em Preprocessor.lib}
15in {\em lib{/}release}.
16
17\section{Generate Visibility Solution}
18\label{sec:visibility}
19
20All necessary scripts are located in the {\em Preprocessor/scripts} directory.
21The easiest way to use the scripts is with Cygwin.
22First some meaningful view cells must be generated for the current scene.
23The script {\em generate\_viewcells.sh} is responsible for view cell generation.
24It takes the parameters from the file {\em generate\_viewcells.env}.
25To specify the input scene, the parameter
26
27\begin{verbatim}Scene.filename\end{verbatim}
28
29must be set to the file name of the new scene. Our preprocessor supports the formats obj and x3d.
30Important options for performance are
31
32%\begin{verbatim}
33%VspBspTree.Construction.samples
34%VspBspTree.Termination.maxViewCells
35%\end{verbatim}
36
37\begin{verbatim}
38Hierarchy.Construction.samples
39VspTree.Termination.maxLeaves
40\end{verbatim}
41
42The first parameter sets the number of samples that is used for view cell construction. Less samples
43means faster computation, but maybe slightly less optimized view cells. The second
44parameter sets the maximal number of view cells.
45%The easiest way to use the file is with Cygwin, but a windows command line will also do the job
46
47Running the script will generate a visibility solution with empty view cells.
48Now we must compute visibility for these view cells.
49In the preprocessor script {\em generate\_visibility.sh}, set the following parameter to the
50newly generated visibility solution.
51
52\begin{verbatim}ViewCells.filename\end{verbatim}
53
54This script starts the preprocessor and generates the full visibility solution. This solution contains
55view cells and the corresponding Potentially Visible Set (PVS). Next we explain how this visibility
56solution can be used in a target engine.
57
58 
59\section{Integration of Preprocessed Visibility}
60\label{sec:integration}
61
62\subsection{Requirements}
63\label{sec:requirements}
64
65Add the following libraries to your application.
66
67\begin{itemize}
68\item {\em Preprocessor.lib }
69\item {\em zdll.lib }
70\item {\em zziplib.lib }
71\item {\em xerces\-c\_2.lib }
72\item {\em devil.lib }
73\item {\em glut32.lib }
74\item {\em OpenGL32.Lib }
75\item {\em glu32.lib }
76\item {\em glew32.lib }
77\item {\em glew32s.lib }
78\end{itemize}
79
80The libraries can be found in the following directories.
81
82\begin{itemize}
83\item {\em trunk/Lib/Vis/Preprocessing/lib/Release }
84\item {\em GTP/trunk/Lib/Vis/Preprocessing/src/GL }
85\item {\em NonGTP/Xerces/xercesc/lib }
86\item {\em NonGTP/Zlib/lib }
87\end{itemize}
88
89This include directory must be added to your Solution.
90
91\begin{itemize}
92\item {\em GTP/trunk/Lib/Vis/Preprocessing/src }
93\end{itemize}
94
95In order to employ the preprocessor in a target engine we must make
96the visibility solution (PVS data) available in the engine.
97For this purpose we associate the entities of the engine with the PVS
98entries from the visibility solution.
99For this purposse the user must implement a small number of interface classes
100of the preprocessor.
101We demonstrate this on a small example, which shows how to access preprocessed visibility
102in the popular rendering engine Ogre3D. Of course, the implementation has to be adapted
103to the requirements of a particular target engine.
104
105\begin{verbatim}
106// this class associates PVS entries
107// with the entities of the engine.
108OctreeBoundingBoxConverter bconverter(this);
109         
110// a vector of intersectables
111ObjectContainer objects;
112
113// load the view cells and their PVS
114GtpVisibilityPreprocessor::ViewCellsManager *viewCellsManager =
115         GtpVisibilityPreprocessor::ViewCellsManager::LoadViewCells
116                                   (filename, &objects, &bconverter);
117\end{verbatim}
118
119This piece of code is loading the view cells into the engine.
120Let's analyze this code. There are two constructs that need explanation, the
121BoundingBoxConverter and the ObjectContainer, and the view cells manager.
122
123\paragraph{BoundingBoxConverter}
124\label{sec:BoundingBoxConverter}
125
126This is one of the interfaces that must be implemented
127In this case, we implemented an OctreeBoundingBoxConverter for the Ogre OctreeSceneManager.
128The bounding box converter is used to associate one or more entities (objects)
129in the engine with each pvs entry of the visibility solution. This is done by
130geometric comparison of the bounding boxes.
131
132In the current setting we compare not for equality but for intersection.
133All entities of the engine intersecting a bounding box of a PVS entry are
134associated with this PVS entry. This means that often more than one entity in the
135engine will map to a particular pvs entry. This gives a slight overestimation of
136PVS but yields a very robust solution.
137
138\paragraph{ObjectContainer}
139\label{sec:ObjectContainer}
140
141The object container is basicly a vector of {\em Intersectable *}. It contains all
142static entities of the scene.
143A PVS entry must be derived from this class. To get access to the PVS of a view cell,
144the user must implement this interface as a wrapper for the entities in the
145particular engine.
146
147\paragraph{ViewCellsManager}
148\label{sec:Loading}
149
150The loading function returns a view cells.
151
152\begin{verbatim}
153static ViewCellsManager *LoadViewCells(const string &filename,
154                                                                                   ObjectContainer *objects,
155                                                                                   bool finalizeViewCells = false,
156                                                                                   BoundingBoxConverter *bconverter = NULL);
157\end{verbatim}
158
159The user has to provide the filename of the visibility solution, an ObjectContainer
160containing all the static entities of the scene, and a bounding box converter.
161From now on, the view cells manager is used to access and
162manage the view cells. For example, it can be applied to locate the current view cell.
163After this step the view cells should be loaded and accessable in the engine.
164
165\section{Example Implementation}
166\label{sec:implementation}
167
168In this section we show an example implementation for the interface classes in Ogre3D.
169
170\subsection{Intersectable}
171\label{sec:intersectable}
172
173In our current setting we said that we test for intersection other than equality when
174assigning the pvs entries to engine entites. Hence there can be more than one matching object
175per PVS entry, and there is a 1:n relationship. The typical wrapper for
176an {\em Intersectable} will therefore contain an array of entities corresponding to this PVS entry.
177In order to use the entities of the target engine instead of Ogre3D entities,
178replace {\em Entity} with the entity representation of the target engine.
179
180\begin{verbatim}
181// a vector of engine entities
182typedef vector<Entity *> EntityContainer;
183
184class EngineIntersectable: public GtpVisibilityPreprocessor::
185                                IntersectableWrapper<EntityContainer *>
186{
187public:
188   EngineIntersectable(EntityContainer *item): GtpVisibilityPreprocessor::
189      IntersectableWrapper<EntityContainer *>(item)
190   {}
191
192   EngineIntersectable::~EngineIntersectable()
193   {
194       delete mItem;
195   }
196
197   int Type() const
198   {
199       return Intersectable::ENGINE_INTERSECTABLE;
200   }
201};
202
203\end{verbatim}
204
205
206\subsection{Bounding Box Converter}
207\label{sec:Converter}
208
209This is maybe the most tricky part of the integration. The bounding box converter
210is necessary because we have to associate the objects of the visibility solution with
211the objects from the engine without having unique ids. This is the interface
212of the {\em BoundingBoxConverter }.
213
214\begin{verbatim}
215/** This class assigns unique indices to objects by
216    comparing bounding boxes.
217*/
218class BoundingBoxConverter
219{
220public:
221        /** Takes a vector of indexed bounding boxes and
222            identify objects with a similar bounding box
223      It will then assign the bounding box id to the objects.
224      The objects are returned in the object container.
225               
226      @returns true if conversion was successful
227  */
228  virtual bool IdentifyObjects(
229                 const IndexedBoundingBoxContainer &iboxes,
230                 ObjectContainer &objects) const
231  {
232    // default: do nothing as we assume that a unique id is
233    // already assigned to the objects.
234    return true;
235  }
236};
237\end{verbatim}
238
239We give an example of implementation of a Bounding Box Converter
240for Ogre3D rendering engine. It is templated in order to works with any Ogre SceneManager.
241Again, the implementation of this interface must be adapted for the requirements
242of the particular engine.
243
244\begin{verbatim}
245/**     This class converts preprocessor entites to Ogre3D entities
246*/
247template<typename T> PlatFormBoundingBoxConverter:
248    public GtpVisibilityPreprocessor::BoundingBoxConverter
249{
250public:
251  /** This constructor takes a scene manager template as parameter.
252  */
253  PlatFormBoundingBoxConverter(T *sm);
254       
255  bool IdentifyObjects(const GtpVisibilityPreprocessor::
256         IndexedBoundingBoxContainer &iboxes,
257         GtpVisibilityPreprocessor::ObjectContainer &objects) const;
258
259protected:
260
261  /** find objects which are intersected by this box
262  */
263  void FindIntersectingObjects(const AxisAlignedBox &box,
264                               vector<Entity *> &objects) const;
265
266  T *mSceneMgr;
267};
268
269typedef PlatFormBoundingBoxConverter<OctreeSceneManager>
270          OctreeBoundingBoxConverter;
271\end{verbatim}
272
273This class is inherited from {\em BoundingBoxConverter}.
274{\em BoundingBoxConverters} has only one virtual function {\em IdentifyObjects} that must
275be implemented. Additionally we use a helper function {\em FindIntersectingObjects} that
276is responsible for locating the corresponding objects in the scene. Let's now have a look
277at the implementation of {\em IdentifyObjects} for Ogre3D.
278
279\begin{verbatim}
280template<typename T>
281bool PlatFormBoundingBoxConverter<T>::IdentifyObjects(
282       const GtpVisibilityPreprocessor::IndexedBoundingBoxContainer &iboxes,
283       GtpVisibilityPreprocessor::ObjectContainer &objects) const
284{
285  GtpVisibilityPreprocessor::IndexedBoundingBoxContainer::
286          const_iterator iit, iit_end = iboxes.end();
287 
288  for (iit = iboxes.begin(); iit != iit_end; ++ iit)
289  {
290    const AxisAlignedBox box =
291      OgreTypeConverter::ConvertToOgre((*iit).second);
292               
293    EntityContainer *entryObjects = new EntityContainer();
294
295    // find all objects that intersect the bounding box
296    FindIntersectingObjects(box, *entryObjects);
297
298    EngineIntersectable *entry = new EngineIntersectable(entryObjects);
299    entry->SetId((*iit).first);
300
301    objects.push_back(entry);
302  }
303  return true;
304}
305\end{verbatim}
306
307The function just loops over the bounding boxes of the PVS entries and finds the entities that
308are intersected by the bouding boxes. Let's have a look now at the function
309{\em FindIntersectingObjects}, which is searching the intersections for each individual box.
310
311\begin{verbatim}
312template<typename T>
313void PlatFormBoundingBoxConverter<T>::FindIntersectingObjects(
314       const AxisAlignedBox &box,
315       EntityContainer &objects) const
316{
317  list<SceneNode *> sceneNodeList;
318                       
319  // find intersecting scene nodes to get candidates for intersection
320  // note: this function has to be provided by scene manager
321  mSceneMgr->findNodesIn(box, sceneNodeList, NULL);
322
323  // convert the bounding box to preprocessor format
324  GtpVisibilityPreprocessor::AxisAlignedBox3 nodeBox =
325    OgreTypeConverter::ConvertFromOgre(box);
326       
327  // loop through the intersecting scene nodes
328  for (sit = sceneNodeList.begin(); sit != sceneNodeList.end(); ++ sit)
329  {
330    SceneNode *sn = *sit;
331    SceneNode::ObjectIterator oit = sn->getAttachedObjectIterator();
332
333    // find the objects that intersect the box
334    while (oit.hasMoreElements())
335    {
336      MovableObject *mo = oit.getNext();
337
338      // we are only interested in scene entities
339      if (mo->getMovableType() != "Entity")
340        continue;
341                       
342      // get the bounding box of the objects
343      AxisAlignedBox bbox = mo->getWorldBoundingBox();
344                       
345      // test for intersection (note: function provided of preprocessor)
346      if (Overlap(nodeBox, OgreTypeConverter::ConvertFromOgre(bbox)))
347      {
348        objects.push_back(static_cast<Entity *>(mo));
349      }
350    }
351  }
352}
353\end{verbatim}
354
355Note that the implementation of this function is maybe the one that differs the most
356for another engine, as it is highly depending on the particular engine design.
357For the Ogre3D implementation, we use a two stage approach. First we find the
358intersecting scene nodes. We apply a search function that is optimized for this engine.
359In case of Ogre3D, this is the function {\em findNodesIn}.
360The engine is responsible to provide a function for fast geometric search in the scene,
361in order to quickly find the objects intersecting the bounding box of a PVS entry.
362A spatial data structure like Octree or Kd tree is very useful in this regard.
363Second we traverse through the list of entities attached to the scene node. The intersection
364test is then applied for each indiviual bounding box.
365
366\section{View Cells Usage}
367\label{sec:usage}
368
369By now the view cells should be accessible within the target engine. The
370view cells manager provides the necessary functionality to handle the view cells.
371In order to query the current view cell, use the following function of the
372view cells manager.
373
374\begin{verbatim}
375ViewCell *GetViewCell(const Vector3 &point, const bool active = false) const;
376\end{verbatim}
377
378In your engine, the function will called like this.
379
380\begin{verbatim}
381ViewCell *currentViewCell = viewCellsManager->GetViewCell(viewPoint);
382\end{verbatim}
383
384{\em viewPoint} contains the current location of the player. It must be of type
385{\em GtpVisibilityPreprocessor::Vector3}. In order to traverse the PVS of this view cell, we
386apply a PVS iterator, like in the following example.
387For the implementation in another engine, { \em Entity} from Ogre3D must be replaced by the
388target engine entities.
389
390\begin{verbatim}
391GtpVisibilityPreprocessor::ObjectPvsIterator pit =
392  currentViewCell->GetPvs().GetIterator();
393                       
394while (pit.HasMoreEntries())
395{               
396  GtpVisibilityPreprocessor::ObjectPvsEntry entry = pit.Next();
397  GtpVisibilityPreprocessor::Intersectable *obj = entry.mObject;
398
399  EngineIntersectable *oi = static_cast<EngineIntersectable *>(obj);
400  EntityContainer *entries = oi->GetItem();
401 
402  EntityContainer::const_iterator eit, eit_end = entries->end();
403
404  for (eit = entries->begin(); eit != eit_end; ++ eit)
405  {
406    Entity *ent = *eit;
407                   
408    // do something, e.g., set objects visible
409  }     
410}
411\end{verbatim}
412
Note: See TracBrowser for help on using the repository browser.