Torque3D Documentation / _generateds / forestRender.cpp

forestRender.cpp

Engine/source/forest/forestRender.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25
 26#include "forest/forest.h"
 27#include "forest/forestCell.h"
 28#include "forest/forestDataFile.h"
 29
 30#include "gfx/gfxTransformSaver.h"
 31#include "renderInstance/renderPassManager.h"
 32#include "scene/sceneManager.h"
 33#include "scene/sceneRenderState.h"
 34#include "lighting/lightManager.h"
 35#include "ts/tsMesh.h"
 36#include "ts/tsRenderState.h"
 37#include "ts/tsShapeInstance.h"
 38
 39#include "gfx/primBuilder.h"
 40#include "gfx/gfxDrawUtil.h"
 41#include "math/mathUtils.h"
 42
 43
 44U32   Forest::smTotalCells = 0;
 45U32   Forest::smCellsRendered = 0;
 46U32   Forest::smCellItemsRendered = 0;
 47U32   Forest::smCellsBatched = 0;
 48U32   Forest::smCellItemsBatched = 0;
 49F32   Forest::smAverageItemsPerCell = 0.0f;
 50
 51void Forest::_clearStats(bool beginFrame)
 52{
 53   // Reset the rendering stats!
 54   if (beginFrame)
 55   {
 56      smTotalCells = 0;
 57      smCellsRendered = 0;
 58      smCellItemsRendered = 0;
 59      smCellsBatched = 0;
 60      smCellItemsBatched = 0;
 61      smAverageItemsPerCell = 0.0f;
 62   }
 63}
 64
 65void Forest::prepRenderImage( SceneRenderState *state )
 66{
 67   PROFILE_SCOPE(Forest_RenderCells);
 68
 69   // TODO: Fix stats.
 70   /*
 71   ForestCellVector &theCells = mData->getCells();
 72   smTotalCells += theCells.size();
 73
 74   // Don't render if we don't have a grid!
 75   if ( theCells.empty() )
 76      return false;
 77   */
 78
 79   // Prepare to render.
 80   GFXTransformSaver saver;
 81
 82   // Figure out the grid range in the viewing area.
 83   const bool isReflectPass = state->isReflectPass();
 84
 85   const F32 cullScale = isReflectPass ? mReflectionLodScalar : 1.0f;
 86
 87   // If we need to update our cached 
 88   // zone state then do it now.
 89   if ( mZoningDirty )
 90   {
 91      mZoningDirty = false;
 92
 93      Vector<ForestCell*> cells;
 94      mData->getCells(  &cells );
 95      for ( U32 i=0; i < cells.size(); i++ )
 96         cells[i]->_updateZoning( getSceneManager()->getZoneManager() );
 97   }
 98
 99   // TODO: Move these into the TSForestItemData as something we
100   // setup once and don't do per-instance.
101   
102   // Set up the TS render state.
103   TSRenderState rdata;
104   rdata.setSceneState( state );
105
106   // Use origin sort on all forest elements as
107   // its alot cheaper than the bounds sort.
108   rdata.setOriginSort( true );
109
110   // We may have some forward lit materials in
111   // the forest, so pass down a LightQuery for it.
112   LightQuery lightQuery;
113   rdata.setLightQuery( &lightQuery );
114   Frustum culler = state->getCullingFrustum();
115
116   // Adjust the far distance if the cull scale has changed.
117   if ( !mIsEqual( cullScale, 1.0f ) )
118   {
119      const F32 visFarDist = culler.getFarDist() * cullScale;
120      culler.setFarDist( visFarDist );
121   }
122
123   Box3F worldBox;
124
125   // Used for debug drawing.
126   GFXDrawUtil* drawer = GFX->getDrawUtil();
127   drawer->clearBitmapModulation();
128
129   // Go thru the visible cells.
130   const Box3F &cullerBounds = culler.getBounds();
131   const Point3F &camPos = state->getDiffuseCameraPosition();
132   
133   U32 clipMask;
134   smAverageItemsPerCell = 0.0f;
135   U32 cellsProcessed = 0;
136   ForestCell *cell;
137   
138   // First get all the top level cells which 
139   // intersect the frustum.
140   Vector<ForestCell*> cellStack;
141   mData->getCells( culler, &cellStack );
142
143   // Get the culling zone state.
144   const BitVector &zoneState = state->getCullingState().getZoneVisibilityFlags();
145
146   // Now loop till we run out of cells.
147   while ( !cellStack.empty() )
148   {
149      // Pop off the next cell.
150      cell = cellStack.last();
151      cellStack.pop_back();
152
153      const Box3F &cellBounds = cell->getBounds();
154
155      // If the cell is empty or its bounds is outside the frustum
156      // bounds then we have nothing nothing more to do.
157      if ( cell->isEmpty() || !cullerBounds.isOverlapped( cellBounds ) )
158         continue;
159
160      // Can we cull this cell entirely?
161      clipMask = culler.testPlanes( cellBounds, Frustum::PlaneMaskAll );
162      if ( clipMask == -1 )
163         continue;
164
165      // Test cell visibility for interior zones.      
166      const bool visibleInside = !cell->getZoneOverlap().empty() ? zoneState.testAny( cell->getZoneOverlap() ) : false;
167
168      // Test cell visibility for outdoor zone, but only
169      // if we need to.
170      bool visibleOutside = false;
171      if( !cell->mIsInteriorOnly && !visibleInside )
172      {         
173         U32 outdoorZone = SceneZoneSpaceManager::RootZoneId;
174         visibleOutside = !state->getCullingState().isCulled( cellBounds, &outdoorZone, 1 );
175      }
176
177      // Skip cell if neither visible indoors nor outdoors.
178      if( !visibleInside && !visibleOutside )
179         continue;
180
181      // Update the stats.
182      smAverageItemsPerCell += cell->getItems().size();
183      ++cellsProcessed;
184      //if ( cell->isLeaf() )
185         //++leafCellsProcessed;
186
187      // Get the distance from the camera to the cell bounds.
188      F32 dist = cellBounds.getDistanceToPoint( camPos );
189
190      // If the largest item in the cell can be billboarded
191      // at the cell distance to the camera... then the whole
192      // cell can be billboarded.
193      //
194      if (  smForceImposters || 
195            ( dist > 0.0f && cell->getLargestItem().canBillboard( state, dist ) ) )
196      {
197         // If imposters are disabled then skip out.
198         if ( smDisableImposters )
199            continue;
200
201         // if cell are to far for largest item, then skip out.
202         if( TSShapeInstance::smLastPixelSize < TSShapeInstance::smSmallestVisiblePixelSize )
203            continue;
204
205         PROFILE_SCOPE(Forest_RenderBatches);
206
207         // Keep track of how many cells were batched.
208         ++smCellsBatched;
209
210         // Ok... everything in this cell should be batched.  First
211         // create the batches if we don't have any.
212         if ( !cell->hasBatches() )
213            cell->buildBatches();
214
215         //if ( drawCells )
216            //mCellRenderFlag[ cellIter - theCells.begin() ] = 1;
217
218         // TODO: Light queries for batches?
219
220         // Now render the batches... we pass the culler if the
221         // cell wasn't fully visible so that each batch can be culled.
222         smCellItemsBatched += cell->renderBatches( state, clipMask != 0 ? &culler : NULL );
223         continue;
224      }
225
226      // If this isn't a leaf then recurse.
227      if ( !cell->isLeaf() )
228      {
229         cell->getChildren( &cellStack );
230         continue;
231      }
232
233      // This cell has mixed billboards and mesh based items.
234      ++smCellsRendered;
235
236      PROFILE_SCOPE(Forest_RenderItems);
237
238      //if ( drawCells )
239         //mCellRenderFlag[ cellIter - theCells.begin() ] = 2;
240
241      // Use the cell bounds as the light query volume.
242      //
243      // This means all forward lit items in this cell will 
244      // get the same lights, but it performs much better.
245      lightQuery.init( cellBounds );
246
247      // This cell is visible... have it render its items.
248      smCellItemsRendered += cell->render( &rdata, clipMask != 0 ? &culler : NULL );
249   }
250
251   // Keep track of the average items per cell.
252   if ( cellsProcessed > 0 )
253      smAverageItemsPerCell /= (F32)cellsProcessed;
254
255   // Got debug drawing to do?
256   if ( smDrawCells && state->isDiffusePass() )
257   {
258      ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
259      ri->renderDelegate.bind( this, &Forest::_renderCellBounds );
260      ri->type = RenderPassManager::RIT_Editor;
261      state->getRenderPass()->addInst( ri );
262   }
263}
264
265
266void Forest::_renderCellBounds( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat )
267{
268   PROFILE_SCOPE( Forest_RenderCellBounds );
269
270   if ( overrideMat )
271      return;
272
273   GFXTransformSaver saver;
274
275   MatrixF projBias(true);
276   const Frustum frustum = GFX->getFrustum();
277   MathUtils::getZBiasProjectionMatrix( 0.001f, frustum, &projBias );
278   GFX->setProjectionMatrix( projBias );
279
280   VectorF extents;
281   Point3F pos;
282
283   // Get top level cells
284   Vector<ForestCell*> cellStack;
285   mData->getCells( &cellStack );
286
287   // Holds child cells we need to render as we encounter them.
288   Vector<ForestCell*> frontier;   
289   
290   GFXDrawUtil *drawer = GFX->getDrawUtil();
291
292   GFXStateBlockDesc desc;
293   desc.setZReadWrite( true, false );
294   desc.setBlend( true );
295   desc.setFillModeWireframe();
296
297   while ( !cellStack.empty() )
298   {
299      while ( !cellStack.empty() )
300      {      
301         const ForestCell *cell = cellStack.last();
302         cellStack.pop_back();
303         
304         Box3F box = cell->getBounds();
305
306         drawer->drawCube( desc, box, ColorI( 0, 255, 0 ) );
307
308         RectF rect = cell->getRect();
309
310         box.minExtents.set( rect.point.x, rect.point.y, box.minExtents.z );
311         box.maxExtents.set( rect.point.x + rect.extent.x, rect.point.y + rect.extent.y, box.minExtents.z );         
312
313         drawer->drawCube( desc, box, ColorI::RED );
314
315         // If this cell has children, add them to the frontier.
316         if ( !cell->isLeaf() )      
317            cell->getChildren( &frontier );      
318      }
319
320      // Now the frontier becomes the cellStack and we empty the frontier.
321      cellStack = frontier;
322      frontier.clear();
323   }
324}
325