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

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