forestRender.cpp
Engine/source/forest/forestRender.cpp
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