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

Revision 2074, 13.7 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. These libaries are all part of the {\em NonGtp} directory
66of the repository.%Next the preprocessor must be build
67
68\begin{itemize}
69\item {\em Preprocessor.lib }
70\item {\em zdll.lib }
71\item {\em zziplib.lib }
72\item {\em xerces\-c\_2.lib }
73\item {\em devil.lib }
74\item {\em glut32.lib }
75\item {\em OpenGL32.Lib }
76\item {\em glu32.lib }
77\item {\em glew32.lib }
78\item {\em glew32s.lib }
79\end{itemize}
80
81In order to employ the preprocessor in a target engine we must make
82the visibility solution (PVS data) available in the engine.
83For this purpose we associate the entities of the engine with the PVS
84entries from the visibility solution.
85For this purposse the user must implement a small number of interface classes
86of the preprocessor.
87We demonstrate this on a small example, which shows how to access preprocessed visibility
88in the popular rendering engine Ogre3D. Of course, the implementation has to be adapted
89to the requirements of a particular target engine.
90
91\begin{verbatim}
92// this class associates PVS entries
93// with the entities of the engine.
94OctreeBoundingBoxConverter bconverter(this);
95         
96// a vector of intersectables
97ObjectContainer objects;
98
99// load the view cells and their PVS
100GtpVisibilityPreprocessor::ViewCellsManager *viewCellsManager =
101         GtpVisibilityPreprocessor::ViewCellsManager::LoadViewCells
102                                   (filename, &objects, &bconverter);
103\end{verbatim}
104
105This piece of code is loading the view cells into the engine.
106Let's analyze this code. There are two constructs that need explanation, the
107BoundingBoxConverter and the ObjectContainer, and the view cells manager.
108
109\paragraph{BoundingBoxConverter}
110\label{sec:BoundingBoxConverter}
111
112This is one of the interfaces that must be implemented
113In this case, we implemented an OctreeBoundingBoxConverter for the Ogre OctreeSceneManager.
114The bounding box converter is used to associate one or more entities (objects)
115in the engine with each pvs entry of the visibility solution. This is done by
116geometric comparison of the bounding boxes.
117
118In the current setting we compare not for equality but for intersection.
119All entities of the engine intersecting a bounding box of a PVS entry are
120associated with this PVS entry. This means that often more than one entity in the
121engine will map to a particular pvs entry. This gives a slight overestimation of
122PVS but yields a very robust solution.
123
124\paragraph{ObjectContainer}
125\label{sec:ObjectContainer}
126
127The object container is basicly a vector of {\em Intersectable *}. It contains all
128static entities of the scene.
129A PVS entry must be derived from this class. To get access to the PVS of a view cell,
130the user must implement this interface as a wrapper for the entities in the
131particular engine.
132
133\paragraph{ViewCellsManager}
134\label{sec:Loading}
135
136A view cells manager is returned from the loading call. It will be used to access and
137manage the view cells from now on. For example, it can be applied to locate the current view cell.
138For loading, the user has to provide the filename of the visibility solution, an ObjectContainer
139containing all the static entities of the scene, and a bounding box converter.
140After this step the view cells should be loaded and accessable in the engine.
141
142\section{Example Implementation}
143\label{sec:implementation}
144
145In this section we show an example implementation for the interface classes in Ogre3D.
146
147\subsection{Intersectable}
148\label{sec:intersectable}
149
150In our current setting we said that we test for intersection other than equality when
151assigning the pvs entries to engine entites. Hence there can be more than one matching object
152per PVS entry, and there is a 1:n relationship. The typical wrapper for
153an {\em Intersectable} will therefore contain an array of entities corresponding to this PVS entry.
154In order to use the entities of the target engine instead of Ogre3D entities,
155replace {\em Entity} with the entity representation of the target engine.
156
157\begin{verbatim}
158
159// a vector of engine entities
160typedef vector<Entity *> EntityContainer;
161
162class EngineIntersectable: public GtpVisibilityPreprocessor::
163                                IntersectableWrapper<EntityContainer *>
164{
165public:
166   EngineIntersectable(EntityContainer *item): GtpVisibilityPreprocessor::
167      IntersectableWrapper<EntityContainer *>(item)
168   {}
169
170   EngineIntersectable::~EngineIntersectable()
171   {
172       delete mItem;
173   }
174
175   int Type() const
176   {
177       return Intersectable::ENGINE_INTERSECTABLE;
178   }
179};
180
181\end{verbatim}
182
183
184\subsection{Bounding Box Converter}
185\label{sec:Converter}
186
187This is maybe the most tricky part of the integration. The bounding box converter
188is necessary because we have to associate the objects of the visibility solution with
189the objects from the engine without having unique ids.
190
191We give an example for a Bounding Box Converter
192for Ogre. It is templated in order to works with any Ogre SceneManager.
193Again, the implementation of this interface must be adapted for the requirements
194of the particular engine.
195
196\begin{verbatim}
197
198/**     Class which converts preprocessor entites to Ogre3D entities
199*/
200template<typename T> PlatFormBoundingBoxConverter:
201    public GtpVisibilityPreprocessor::BoundingBoxConverter
202{
203public:
204  PlatFormBoundingBoxConverter(T *sm);
205       
206  /** Takes a vector of indexed bounding boxes and uses it to
207      identify objects with a similar bounding box
208      and assigns them the proper index (id).
209      The objects are returned in the object container.
210               
211      @returns true if conversion was successful
212  */
213  bool IdentifyObjects(const GtpVisibilityPreprocessor::
214         IndexedBoundingBoxContainer &iboxes,
215               GtpVisibilityPreprocessor::ObjectContainer &objects) const;
216
217protected:
218
219  /** find objects which are intersected by this box
220  */
221  void FindIntersectingObjects(const AxisAlignedBox &box,
222                               vector<Entity *> &objects) const;
223
224  T *mSceneMgr;
225};
226
227typedef PlatFormBoundingBoxConverter<OctreeSceneManager>
228          OctreeBoundingBoxConverter;
229
230\end{verbatim}
231
232This class is inherited from {\em BoundingBoxConverter}.
233{\em BoundingBoxConverters} has only one virtual function {\em IdentifyObjects} that must
234be implemented. Additionally we
235use a helper function {\em FindIntersectingObjects} that is responsible for locating the
236corresponding objects in the scene. Let's now have a look at the
237implementation of {\em IdentifyObjects} for Ogre3D.
238
239\begin{verbatim}
240template<typename T>
241bool PlatFormBoundingBoxConverter<T>::IdentifyObjects(
242       const GtpVisibilityPreprocessor::IndexedBoundingBoxContainer &iboxes,
243       GtpVisibilityPreprocessor::ObjectContainer &objects) const
244{
245  GtpVisibilityPreprocessor::IndexedBoundingBoxContainer::
246          const_iterator iit, iit_end = iboxes.end();
247 
248  for (iit = iboxes.begin(); iit != iit_end; ++ iit)
249  {
250    const AxisAlignedBox box =
251      OgreTypeConverter::ConvertToOgre((*iit).second);
252               
253    EntityContainer *entryObjects = new EntityContainer();
254
255    // find all objects that intersect the bounding box
256    FindIntersectingObjects(box, *entryObjects);
257
258    EngineIntersectable *entry = new EngineIntersectable(entryObjects);
259    entry->SetId((*iit).first);
260
261    objects.push_back(entry);
262  }
263  return true;
264}
265\end{verbatim}
266
267The function just loops over the bounding boxes of the PVS entries and finds the entities that
268are intersected by the bouding boxes. Let's have a look now at the function {\em FindIntersectingObjects}, which
269is searching the intersections for each individual box.
270
271
272\begin{verbatim}
273template<typename T>
274void PlatFormBoundingBoxConverter<T>::FindIntersectingObjects(
275       const AxisAlignedBox &box,
276       EntityContainer &objects) const
277{
278  list<SceneNode *> sceneNodeList;
279                       
280  // find intersecting scene nodes to get candidates for intersection
281  // note: this function has to be provided by scene manager
282  mSceneMgr->findNodesIn(box, sceneNodeList, NULL);
283
284  // convert the bounding box to preprocessor format
285  GtpVisibilityPreprocessor::AxisAlignedBox3 nodeBox =
286    OgreTypeConverter::ConvertFromOgre(box);
287       
288  // loop through the intersecting scene nodes
289  for (sit = sceneNodeList.begin(); sit != sceneNodeList.end(); ++ sit)
290  {
291    SceneNode *sn = *sit;
292    SceneNode::ObjectIterator oit = sn->getAttachedObjectIterator();
293
294    // find the objects that intersect the box
295    while (oit.hasMoreElements())
296    {
297      MovableObject *mo = oit.getNext();
298
299      // we are only interested in scene entities
300      if (mo->getMovableType() != "Entity")
301        continue;
302                       
303      // get the bounding box of the objects
304      AxisAlignedBox bbox = mo->getWorldBoundingBox();
305                       
306      // test for intersection (note: function provided of preprocessor)
307      if (Overlap(nodeBox, OgreTypeConverter::ConvertFromOgre(bbox)))
308      {
309        objects.push_back(static_cast<Entity *>(mo));
310      }
311    }
312  }
313}
314\end{verbatim}
315
316Note that the implementation of this function is maybe the one that differs the most
317for another engine, as it is highly depending on the particular engine design.
318For the Ogre3D implementation, we use a two stage approach. First we find the intersecting scene nodes.
319We apply a search function that is optimized for this engine.
320In the Ogre3D case, this is the function {\em findNodesIn}.
321The engine is responsible to provide a function for fast geometric search in the scene,
322in order to quickly find the objects intersecting the bounding box of a PVS entry.
323A spatial data structure like Octree or Kd tree is very useful in this regard.
324Second we traverse through the list of entities attached to the scene node. The intersection
325test is then applied for each indiviual bounding box.
326
327\section{View Cells Usage}
328\label{sec:usage}
329
330By now the view cells should be accessible within the target engine. This happens through
331the view cells manager. In order to query the current view cell, use the following code.
332
333\begin{verbatim}
334ViewCell *currentViewCell = viewCellsManager->GetViewCell(viewPoint);
335
336\end{verbatim}
337
338where {\em viewPoint} contains the current location of the player. It must be of type
339{\em GtpVisibilityPreprocessor::Vector3}. In order to traverse the PVS of this view cell, we
340apply a PVS iterator, like in the following example.
341For the implementation in another engine, { \em Entity} from Ogre3D must be replaced by the
342target engine entities.
343
344\begin{verbatim}
345GtpVisibilityPreprocessor::ObjectPvsIterator pit =
346  currentViewCell->GetPvs().GetIterator();
347                       
348while (pit.HasMoreEntries())
349{               
350  GtpVisibilityPreprocessor::ObjectPvsEntry entry = pit.Next();
351  GtpVisibilityPreprocessor::Intersectable *obj = entry.mObject;
352
353  EngineIntersectable *oi = static_cast<EngineIntersectable *>(obj);
354  EntityContainer *entries = oi->GetItem();
355 
356  EntityContainer::const_iterator eit, eit_end = entries->end();
357
358  for (eit = entries->begin(); eit != eit_end; ++ eit)
359  {
360    Entity *ent = *eit;
361                   
362    // do something, e.g., set objects visible
363  }     
364}
365
366\end{verbatim}
367
Note: See TracBrowser for help on using the repository browser.