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

Revision 2177, 15.9 KB checked in by mattausch, 17 years ago (diff)
RevLine 
[2066]1\section{Introduction}
2\label{sec:introduction}
3
[2177]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
[2066]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
[2068]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
[2066]35
36\begin{verbatim}Scene.filename\end{verbatim}
37
[2068]38must be set to the file name of the new scene. Our preprocessor supports the formats obj and x3d.
[2066]39Important options for performance are
40
[2072]41%\begin{verbatim}
42%VspBspTree.Construction.samples
43%VspBspTree.Termination.maxViewCells
44%\end{verbatim}
45
[2068]46\begin{verbatim}
[2074]47Hierarchy.Construction.samples
[2072]48VspTree.Termination.maxLeaves
[2068]49\end{verbatim}
[2066]50
[2068]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.
[2066]54%The easiest way to use the file is with Cygwin, but a windows command line will also do the job
55
[2068]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.
[2066]60
61\begin{verbatim}ViewCells.filename\end{verbatim}
62
[2068]63This script starts the preprocessor and generates the full visibility solution. This solution contains
[2066]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
[2104]74Add the following libraries to your application.
[2066]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
[2104]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
[2177]98The following include directory must be added to your Solution.
[2104]99
100\begin{itemize}
101\item {\em GTP/trunk/Lib/Vis/Preprocessing/src }
102\end{itemize}
103
[2066]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.
[2177]108For this purpose the user must implement a small number of interface classes
[2066]109of the preprocessor.
110We demonstrate this on a small example, which shows how to access preprocessed visibility
[2068]111in the popular rendering engine Ogre3D. Of course, the implementation has to be adapted
112to the requirements of a particular target engine.
[2066]113
114\begin{verbatim}
[2068]115// this class associates PVS entries
116// with the entities of the engine.
117OctreeBoundingBoxConverter bconverter(this);
[2066]118         
[2068]119// a vector of intersectables
120ObjectContainer objects;
[2066]121
[2068]122// load the view cells and their PVS
123GtpVisibilityPreprocessor::ViewCellsManager *viewCellsManager =
[2066]124         GtpVisibilityPreprocessor::ViewCellsManager::LoadViewCells
125                                   (filename, &objects, &bconverter);
126\end{verbatim}
127
[2068]128This piece of code is loading the view cells into the engine.
[2177]129Let's analyze this code. There are three constructs that need explanation, the
130BoundingBoxConverter and the ObjectContainer, and the ViewCellsManager.
[2066]131
[2068]132\paragraph{BoundingBoxConverter}
[2066]133\label{sec:BoundingBoxConverter}
134
[2068]135This is one of the interfaces that must be implemented
136In this case, we implemented an OctreeBoundingBoxConverter for the Ogre OctreeSceneManager.
[2066]137The bounding box converter is used to associate one or more entities (objects)
[2068]138in the engine with each pvs entry of the visibility solution. This is done by
139geometric comparison of the bounding boxes.
140
[2066]141In the current setting we compare not for equality but for intersection.
[2068]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.
[2066]146
147\paragraph{ObjectContainer}
148\label{sec:ObjectContainer}
149
[2177]150An object container is a vector of {\em Intersectable *}. It contains all
[2066]151static entities of the scene.
[2068]152A PVS entry must be derived from this class. To get access to the PVS of a view cell,
[2066]153the user must implement this interface as a wrapper for the entities in the
154particular engine.
155
[2068]156\paragraph{ViewCellsManager}
[2066]157\label{sec:Loading}
158
[2177]159The loading function returns a view cells manager.
[2111]160
161\begin{verbatim}
162static ViewCellsManager *LoadViewCells(const string &filename,
[2177]163                                       ObjectContainer *objects,
164                                       bool finalizeViewCells = false,
165                                       BoundingBoxConverter *bconverter = NULL);
[2111]166\end{verbatim}
167
168The user has to provide the filename of the visibility solution, an ObjectContainer
[2068]169containing all the static entities of the scene, and a bounding box converter.
[2111]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.
[2068]172After this step the view cells should be loaded and accessable in the engine.
[2066]173
[2068]174\section{Example Implementation}
175\label{sec:implementation}
[2066]176
[2068]177In this section we show an example implementation for the interface classes in Ogre3D.
[2177]178First for the object class of the preprocessor, {\em Intersectable}, then for the converter class
179{\em BoundingBoxConverter }.
[2068]180
[2177]181\subsection{Class Intersectable}
[2066]182\label{sec:intersectable}
183
[2068]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.
[2066]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
[2177]217\subsection{Class BoundingBoxConverter}
[2066]218\label{sec:Converter}
219
[2177]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 }.
[2066]224
[2111]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
[2177]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).
[2068]253Again, the implementation of this interface must be adapted for the requirements
254of the particular engine.
[2066]255
256\begin{verbatim}
[2111]257/**     This class converts preprocessor entites to Ogre3D entities
[2066]258*/
259template<typename T> PlatFormBoundingBoxConverter:
260    public GtpVisibilityPreprocessor::BoundingBoxConverter
261{
262public:
[2111]263  /** This constructor takes a scene manager template as parameter.
264  */
[2066]265  PlatFormBoundingBoxConverter(T *sm);
266       
267  bool IdentifyObjects(const GtpVisibilityPreprocessor::
[2068]268         IndexedBoundingBoxContainer &iboxes,
[2111]269         GtpVisibilityPreprocessor::ObjectContainer &objects) const;
[2066]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
[2068]281typedef PlatFormBoundingBoxConverter<OctreeSceneManager>
282          OctreeBoundingBoxConverter;
[2066]283\end{verbatim}
284
[2068]285This class is inherited from {\em BoundingBoxConverter}.
[2177]286This class has only one virtual function {\em IdentifyObjects} that must
[2111]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.
[2066]290
291\begin{verbatim}
292template<typename T>
293bool PlatFormBoundingBoxConverter<T>::IdentifyObjects(
[2068]294       const GtpVisibilityPreprocessor::IndexedBoundingBoxContainer &iboxes,
295       GtpVisibilityPreprocessor::ObjectContainer &objects) const
[2066]296{
[2068]297  GtpVisibilityPreprocessor::IndexedBoundingBoxContainer::
298          const_iterator iit, iit_end = iboxes.end();
[2066]299 
[2068]300  for (iit = iboxes.begin(); iit != iit_end; ++ iit)
301  {
302    const AxisAlignedBox box =
303      OgreTypeConverter::ConvertToOgre((*iit).second);
[2066]304               
[2068]305    EntityContainer *entryObjects = new EntityContainer();
[2066]306
[2068]307    // find all objects that intersect the bounding box
308    FindIntersectingObjects(box, *entryObjects);
[2066]309
[2068]310    EngineIntersectable *entry = new EngineIntersectable(entryObjects);
311    entry->SetId((*iit).first);
[2066]312
[2068]313    objects.push_back(entry);
314  }
315  return true;
[2066]316}
317\end{verbatim}
318
319The function just loops over the bounding boxes of the PVS entries and finds the entities that
[2177]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.
[2066]324
325\begin{verbatim}
326template<typename T>
327void PlatFormBoundingBoxConverter<T>::FindIntersectingObjects(
[2068]328       const AxisAlignedBox &box,
329       EntityContainer &objects) const
[2066]330{
331  list<SceneNode *> sceneNodeList;
332                       
[2068]333  // find intersecting scene nodes to get candidates for intersection
[2066]334  // note: this function has to be provided by scene manager
[2068]335  mSceneMgr->findNodesIn(box, sceneNodeList, NULL);
[2066]336
337  // convert the bounding box to preprocessor format
[2068]338  GtpVisibilityPreprocessor::AxisAlignedBox3 nodeBox =
339    OgreTypeConverter::ConvertFromOgre(box);
[2066]340       
341  // loop through the intersecting scene nodes
[2068]342  for (sit = sceneNodeList.begin(); sit != sceneNodeList.end(); ++ sit)
343  {
344    SceneNode *sn = *sit;
345    SceneNode::ObjectIterator oit = sn->getAttachedObjectIterator();
[2066]346
347    // find the objects that intersect the box
348    while (oit.hasMoreElements())
[2068]349    {
350      MovableObject *mo = oit.getNext();
[2066]351
[2068]352      // we are only interested in scene entities
353      if (mo->getMovableType() != "Entity")
354        continue;
[2066]355                       
[2068]356      // get the bounding box of the objects
357      AxisAlignedBox bbox = mo->getWorldBoundingBox();
[2066]358                       
[2068]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  }
[2066]366}
367\end{verbatim}
368
[2068]369Note that the implementation of this function is maybe the one that differs the most
[2177]370for other engines, as it is highly depending on the particular engine design.
[2111]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}.
[2066]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.
[2177]376A spatial data structure like octree or kd-tree is very useful in this regard.
[2066]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
[2177]383At this point the view cells should be accessible within the target engine. The
[2111]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.
[2066]387
388\begin{verbatim}
[2111]389ViewCell *GetViewCell(const Vector3 &point, const bool active = false) const;
390\end{verbatim}
391
[2177]392In the target engine, the function is envoked like this.
[2111]393
394\begin{verbatim}
[2066]395ViewCell *currentViewCell = viewCellsManager->GetViewCell(viewPoint);
396\end{verbatim}
397
[2111]398{\em viewPoint} contains the current location of the player. It must be of type
[2068]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.
[2066]403
404\begin{verbatim}
[2068]405GtpVisibilityPreprocessor::ObjectPvsIterator pit =
406  currentViewCell->GetPvs().GetIterator();
407                       
[2066]408while (pit.HasMoreEntries())
409{               
410  GtpVisibilityPreprocessor::ObjectPvsEntry entry = pit.Next();
[2068]411  GtpVisibilityPreprocessor::Intersectable *obj = entry.mObject;
[2066]412
[2068]413  EngineIntersectable *oi = static_cast<EngineIntersectable *>(obj);
414  EntityContainer *entries = oi->GetItem();
415 
416  EntityContainer::const_iterator eit, eit_end = entries->end();
[2066]417
[2068]418  for (eit = entries->begin(); eit != eit_end; ++ eit)
419  {
420    Entity *ent = *eit;
[2066]421                   
[2068]422    // do something, e.g., set objects visible
423  }     
[2066]424}
425\end{verbatim}
426
Note: See TracBrowser for help on using the repository browser.