[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.
|
---|
| 10 | A snapshot of Vienna is shown, with the rendered PVS shown in the lower right corner. Note
|
---|
| 11 | how the PVS closely fits to the geometry actually seen.}
|
---|
| 12 |
|
---|
[2066] | 13 | This manual provides a guide to apply preprocessed visibility in a particular target engine. It
|
---|
| 14 | will start with instruction for building the preprocessor, describes the integration of the
|
---|
| 15 | preprocessor and the generated visibility solution, and last but not least the usage of
|
---|
| 16 | the view cells within the target engine.
|
---|
| 17 |
|
---|
| 18 | \section{Build Project}
|
---|
| 19 | \label{sec:build}
|
---|
| 20 |
|
---|
| 21 | Open the {\em GtpVisibility.sln} with {\em Visual Studio 2003} (2005 might work, but we did not test it recently).
|
---|
| 22 | Set the build target to {\em Release}. Build the project {\em TestPreprocessor}. Now there should be a newly built
|
---|
| 23 | executable {\em Preprocessor.exe} in {\em bin{/}release} and a library {\em Preprocessor.lib}
|
---|
| 24 | in {\em lib{/}release}.
|
---|
| 25 |
|
---|
| 26 | \section{Generate Visibility Solution}
|
---|
| 27 | \label{sec:visibility}
|
---|
| 28 |
|
---|
[2068] | 29 | All necessary scripts are located in the {\em Preprocessor/scripts} directory.
|
---|
| 30 | The easiest way to use the scripts is with Cygwin.
|
---|
| 31 | First some meaningful view cells must be generated for the current scene.
|
---|
| 32 | The script {\em generate\_viewcells.sh} is responsible for view cell generation.
|
---|
| 33 | It takes the parameters from the file {\em generate\_viewcells.env}.
|
---|
| 34 | To specify the input scene, the parameter
|
---|
[2066] | 35 |
|
---|
| 36 | \begin{verbatim}Scene.filename\end{verbatim}
|
---|
| 37 |
|
---|
[2068] | 38 | must be set to the file name of the new scene. Our preprocessor supports the formats obj and x3d.
|
---|
[2066] | 39 | Important 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] | 47 | Hierarchy.Construction.samples
|
---|
[2072] | 48 | VspTree.Termination.maxLeaves
|
---|
[2068] | 49 | \end{verbatim}
|
---|
[2066] | 50 |
|
---|
[2068] | 51 | The first parameter sets the number of samples that is used for view cell construction. Less samples
|
---|
| 52 | means faster computation, but maybe slightly less optimized view cells. The second
|
---|
| 53 | parameter 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] | 56 | Running the script will generate a visibility solution with empty view cells.
|
---|
| 57 | Now we must compute visibility for these view cells.
|
---|
| 58 | In the preprocessor script {\em generate\_visibility.sh}, set the following parameter to the
|
---|
| 59 | newly generated visibility solution.
|
---|
[2066] | 60 |
|
---|
| 61 | \begin{verbatim}ViewCells.filename\end{verbatim}
|
---|
| 62 |
|
---|
[2068] | 63 | This script starts the preprocessor and generates the full visibility solution. This solution contains
|
---|
[2066] | 64 | view cells and the corresponding Potentially Visible Set (PVS). Next we explain how this visibility
|
---|
| 65 | solution 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] | 74 | Add 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] | 89 | The 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] | 98 | The 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] | 104 | In order to employ the preprocessor in a target engine we must make
|
---|
| 105 | the visibility solution (PVS data) available in the engine.
|
---|
| 106 | For this purpose we associate the entities of the engine with the PVS
|
---|
| 107 | entries from the visibility solution.
|
---|
[2177] | 108 | For this purpose the user must implement a small number of interface classes
|
---|
[2066] | 109 | of the preprocessor.
|
---|
| 110 | We demonstrate this on a small example, which shows how to access preprocessed visibility
|
---|
[2068] | 111 | in the popular rendering engine Ogre3D. Of course, the implementation has to be adapted
|
---|
| 112 | to 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.
|
---|
| 117 | OctreeBoundingBoxConverter bconverter(this);
|
---|
[2066] | 118 |
|
---|
[2068] | 119 | // a vector of intersectables
|
---|
| 120 | ObjectContainer objects;
|
---|
[2066] | 121 |
|
---|
[2068] | 122 | // load the view cells and their PVS
|
---|
| 123 | GtpVisibilityPreprocessor::ViewCellsManager *viewCellsManager =
|
---|
[2066] | 124 | GtpVisibilityPreprocessor::ViewCellsManager::LoadViewCells
|
---|
| 125 | (filename, &objects, &bconverter);
|
---|
| 126 | \end{verbatim}
|
---|
| 127 |
|
---|
[2068] | 128 | This piece of code is loading the view cells into the engine.
|
---|
[2177] | 129 | Let's analyze this code. There are three constructs that need explanation, the
|
---|
| 130 | BoundingBoxConverter and the ObjectContainer, and the ViewCellsManager.
|
---|
[2066] | 131 |
|
---|
[2068] | 132 | \paragraph{BoundingBoxConverter}
|
---|
[2066] | 133 | \label{sec:BoundingBoxConverter}
|
---|
| 134 |
|
---|
[2068] | 135 | This is one of the interfaces that must be implemented
|
---|
| 136 | In this case, we implemented an OctreeBoundingBoxConverter for the Ogre OctreeSceneManager.
|
---|
[2066] | 137 | The bounding box converter is used to associate one or more entities (objects)
|
---|
[2068] | 138 | in the engine with each pvs entry of the visibility solution. This is done by
|
---|
| 139 | geometric comparison of the bounding boxes.
|
---|
| 140 |
|
---|
[2066] | 141 | In the current setting we compare not for equality but for intersection.
|
---|
[2068] | 142 | All entities of the engine intersecting a bounding box of a PVS entry are
|
---|
| 143 | associated with this PVS entry. This means that often more than one entity in the
|
---|
| 144 | engine will map to a particular pvs entry. This gives a slight overestimation of
|
---|
| 145 | PVS but yields a very robust solution.
|
---|
[2066] | 146 |
|
---|
| 147 | \paragraph{ObjectContainer}
|
---|
| 148 | \label{sec:ObjectContainer}
|
---|
| 149 |
|
---|
[2177] | 150 | An object container is a vector of {\em Intersectable *}. It contains all
|
---|
[2066] | 151 | static entities of the scene.
|
---|
[2068] | 152 | A PVS entry must be derived from this class. To get access to the PVS of a view cell,
|
---|
[2066] | 153 | the user must implement this interface as a wrapper for the entities in the
|
---|
| 154 | particular engine.
|
---|
| 155 |
|
---|
[2068] | 156 | \paragraph{ViewCellsManager}
|
---|
[2066] | 157 | \label{sec:Loading}
|
---|
| 158 |
|
---|
[2177] | 159 | The loading function returns a view cells manager.
|
---|
[2111] | 160 |
|
---|
| 161 | \begin{verbatim}
|
---|
| 162 | static ViewCellsManager *LoadViewCells(const string &filename,
|
---|
[2177] | 163 | ObjectContainer *objects,
|
---|
| 164 | bool finalizeViewCells = false,
|
---|
| 165 | BoundingBoxConverter *bconverter = NULL);
|
---|
[2111] | 166 | \end{verbatim}
|
---|
| 167 |
|
---|
| 168 | The user has to provide the filename of the visibility solution, an ObjectContainer
|
---|
[2068] | 169 | containing all the static entities of the scene, and a bounding box converter.
|
---|
[2111] | 170 | From now on, the view cells manager is used to access and
|
---|
| 171 | manage the view cells. For example, it can be applied to locate the current view cell.
|
---|
[2068] | 172 | After 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] | 177 | In this section we show an example implementation for the interface classes in Ogre3D.
|
---|
[2177] | 178 | First 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] | 184 | In our current setting we said that we test for intersection other than equality when
|
---|
| 185 | assigning the pvs entries to engine entites. Hence there can be more than one matching object
|
---|
| 186 | per PVS entry, and there is a 1:n relationship. The typical wrapper for
|
---|
| 187 | an {\em Intersectable} will therefore contain an array of entities corresponding to this PVS entry.
|
---|
| 188 | In order to use the entities of the target engine instead of Ogre3D entities,
|
---|
| 189 | replace {\em Entity} with the entity representation of the target engine.
|
---|
[2066] | 190 |
|
---|
| 191 | \begin{verbatim}
|
---|
| 192 | // a vector of engine entities
|
---|
| 193 | typedef vector<Entity *> EntityContainer;
|
---|
| 194 |
|
---|
| 195 | class EngineIntersectable: public GtpVisibilityPreprocessor::
|
---|
| 196 | IntersectableWrapper<EntityContainer *>
|
---|
| 197 | {
|
---|
| 198 | public:
|
---|
| 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] | 220 | This is the most involved part of the integration, but it shouldn't be too difficult, either.
|
---|
| 221 | A bounding box converter is necessary because we have to associate the objects of the
|
---|
| 222 | visibility solution with the objects from the engine without having unique ids. This is the
|
---|
| 223 | interface 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 | */
|
---|
| 229 | class BoundingBoxConverter
|
---|
| 230 | {
|
---|
| 231 | public:
|
---|
| 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] | 250 | We give an example of implementation of a {\em BoundingBoxConverter }
|
---|
| 251 | for 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] | 253 | Again, the implementation of this interface must be adapted for the requirements
|
---|
| 254 | of the particular engine.
|
---|
[2066] | 255 |
|
---|
| 256 | \begin{verbatim}
|
---|
[2111] | 257 | /** This class converts preprocessor entites to Ogre3D entities
|
---|
[2066] | 258 | */
|
---|
| 259 | template<typename T> PlatFormBoundingBoxConverter:
|
---|
| 260 | public GtpVisibilityPreprocessor::BoundingBoxConverter
|
---|
| 261 | {
|
---|
| 262 | public:
|
---|
[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 |
|
---|
| 271 | protected:
|
---|
| 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] | 281 | typedef PlatFormBoundingBoxConverter<OctreeSceneManager>
|
---|
| 282 | OctreeBoundingBoxConverter;
|
---|
[2066] | 283 | \end{verbatim}
|
---|
| 284 |
|
---|
[2068] | 285 | This class is inherited from {\em BoundingBoxConverter}.
|
---|
[2177] | 286 | This class has only one virtual function {\em IdentifyObjects} that must
|
---|
[2111] | 287 | be implemented. Additionally we use a helper function {\em FindIntersectingObjects} that
|
---|
| 288 | is responsible for locating the corresponding objects in the scene. Let's now have a look
|
---|
| 289 | at the implementation of {\em IdentifyObjects} for Ogre3D.
|
---|
[2066] | 290 |
|
---|
| 291 | \begin{verbatim}
|
---|
| 292 | template<typename T>
|
---|
| 293 | bool 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 |
|
---|
| 319 | The function just loops over the bounding boxes of the PVS entries and finds the entities that
|
---|
[2177] | 320 | are intersected by the bounding boxes. Additionally we introduce a new class, the { \em OgreTypeConverter }.
|
---|
| 321 | This class is just responsible for converting basic classes like {\em Vector3 } or { \em AxisAlignedBox }
|
---|
| 322 | betwen 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}
|
---|
| 326 | template<typename T>
|
---|
| 327 | void 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] | 369 | Note that the implementation of this function is maybe the one that differs the most
|
---|
[2177] | 370 | for other engines, as it is highly depending on the particular engine design.
|
---|
[2111] | 371 | For the Ogre3D implementation, we use a two stage approach. First we find the
|
---|
| 372 | intersecting scene nodes. We apply a search function that is optimized for this engine.
|
---|
| 373 | In case of Ogre3D, this is the function {\em findNodesIn}.
|
---|
[2066] | 374 | The engine is responsible to provide a function for fast geometric search in the scene,
|
---|
| 375 | in order to quickly find the objects intersecting the bounding box of a PVS entry.
|
---|
[2177] | 376 | A spatial data structure like octree or kd-tree is very useful in this regard.
|
---|
[2066] | 377 | Second we traverse through the list of entities attached to the scene node. The intersection
|
---|
| 378 | test is then applied for each indiviual bounding box.
|
---|
| 379 |
|
---|
| 380 | \section{View Cells Usage}
|
---|
| 381 | \label{sec:usage}
|
---|
| 382 |
|
---|
[2177] | 383 | At this point the view cells should be accessible within the target engine. The
|
---|
[2111] | 384 | view cells manager provides the necessary functionality to handle the view cells.
|
---|
| 385 | In order to query the current view cell, use the following function of the
|
---|
| 386 | view cells manager.
|
---|
[2066] | 387 |
|
---|
| 388 | \begin{verbatim}
|
---|
[2111] | 389 | ViewCell *GetViewCell(const Vector3 &point, const bool active = false) const;
|
---|
| 390 | \end{verbatim}
|
---|
| 391 |
|
---|
[2177] | 392 | In the target engine, the function is envoked like this.
|
---|
[2111] | 393 |
|
---|
| 394 | \begin{verbatim}
|
---|
[2066] | 395 | ViewCell *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
|
---|
| 400 | apply a PVS iterator, like in the following example.
|
---|
| 401 | For the implementation in another engine, { \em Entity} from Ogre3D must be replaced by the
|
---|
| 402 | target engine entities.
|
---|
[2066] | 403 |
|
---|
| 404 | \begin{verbatim}
|
---|
[2068] | 405 | GtpVisibilityPreprocessor::ObjectPvsIterator pit =
|
---|
| 406 | currentViewCell->GetPvs().GetIterator();
|
---|
| 407 |
|
---|
[2066] | 408 | while (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 |
|
---|