void GroundPlane::prepRenderImage( SceneRenderState* state ) { PROFILE_SCOPE( GroundPlane_prepRenderImage ); // TODO: Should we skip rendering the ground plane into // the shadows? Its not like you can ever get under it. if ( !mMaterial ) return; // If we don't have a material instance after the override then // we can skip rendering all together. BaseMatInstance *matInst = state->getOverrideMaterial( mMaterial ); if ( !matInst ) return; PROFILE_SCOPE( GroundPlane_prepRender ); // Update the geometry. createGeometry( state->getCullingFrustum() ); if( mVertexBuffer.isNull() ) return; // Add a render instance. RenderPassManager* pass = state->getRenderPass(); MeshRenderInst* ri = pass->allocInst< MeshRenderInst >(); ri->type = RenderPassManager::RIT_Mesh; ri->vertBuff = &mVertexBuffer; ri->primBuff = &mPrimitiveBuffer; ri->prim = &mPrimitive; ri->matInst = matInst; ri->objectToWorld = pass->allocUniqueXform( MatrixF::Identity ); ri->worldToCamera = pass->allocSharedXform( RenderPassManager::View ); ri->projection = pass->allocSharedXform( RenderPassManager::Projection ); ri->visibility = 1.0f; ri->translucentSort = matInst->getMaterial()->isTranslucent(); ri->defaultKey = matInst->getStateHint(); if( ri->translucentSort ) ri->type = RenderPassManager::RIT_Translucent; // If we need lights then set them up. if ( matInst->isForwardLit() ) { LightQuery query; query.init( getWorldSphere() ); query.getLights( ri->lights, 8 ); } pass->addInst( ri ); }
bool GroundPlane::prepRenderImage( SceneState* state, const U32 stateKey, const U32, const bool ) { PROFILE_SCOPE( GroundPlane_prepRenderImage ); if( isLastState( state, stateKey ) ) return false; setLastState( state, stateKey ); if( !state->isObjectRendered( this ) || !mMaterial ) return false; PROFILE_SCOPE( GroundPlane_prepRender ); // Update the geometry. createGeometry( state->getFrustum() ); if( mVertexBuffer.isNull() ) return false; // Add a render instance. RenderPassManager* pass = state->getRenderPass(); MeshRenderInst* ri = pass->allocInst< MeshRenderInst >(); ri->type = RenderPassManager::RIT_Mesh; ri->vertBuff = &mVertexBuffer; ri->primBuff = &mPrimitiveBuffer; ri->prim = &mPrimitive; ri->matInst = mMaterial; ri->objectToWorld = pass->allocUniqueXform( mRenderObjToWorld ); ri->worldToCamera = pass->allocSharedXform(RenderPassManager::View); ri->projection = pass->allocSharedXform(RenderPassManager::Projection); ri->visibility = 1.0f; ri->translucentSort = ( ri->matInst->getMaterial()->isTranslucent() ); // NOTICE: SFXBB is removed and refraction is disabled! //ri->backBuffTex = GFX->getSfxBackBuffer(); ri->defaultKey = ( U32 ) mMaterial; // TODO: Get the best lights for the plane in a better // way.... maybe the same way as we do for terrain? ri->lights[0] = state->getLightManager()->getDefaultLight(); if( ri->translucentSort ) ri->type = RenderPassManager::RIT_Translucent; pass->addInst( ri ); return true; }
void DecalRoad::prepRenderImage( SceneRenderState* state ) { PROFILE_SCOPE( DecalRoad_prepRenderImage ); if ( mNodes.size() <= 1 || mBatches.size() == 0 || !mMatInst || state->isShadowPass() ) return; // If we don't have a material instance after the override then // we can skip rendering all together. BaseMatInstance *matInst = state->getOverrideMaterial( mMatInst ); if ( !matInst ) return; RenderPassManager *renderPass = state->getRenderPass(); // Debug RenderInstance // Only when editor is open. if ( smEditorOpen ) { ObjectRenderInst *ri = renderPass->allocInst<ObjectRenderInst>(); ri->type = RenderPassManager::RIT_Editor; ri->renderDelegate.bind( this, &DecalRoad::_debugRender ); state->getRenderPass()->addInst( ri ); } // Normal Road RenderInstance // Always rendered when the editor is not open // otherwise obey the smShowRoad flag if ( !smShowRoad && smEditorOpen ) return; const Frustum &frustum = state->getCameraFrustum(); MeshRenderInst coreRI; coreRI.clear(); coreRI.objectToWorld = &MatrixF::Identity; coreRI.worldToCamera = renderPass->allocSharedXform(RenderPassManager::View); MatrixF *tempMat = renderPass->allocUniqueXform( MatrixF( true ) ); MathUtils::getZBiasProjectionMatrix( gDecalBias, frustum, tempMat ); coreRI.projection = tempMat; coreRI.type = RenderPassManager::RIT_Decal; coreRI.vertBuff = &mVB; coreRI.primBuff = &mPB; coreRI.matInst = matInst; // Make it the sort distance the max distance so that // it renders after all the other opaque geometry in // the prepass bin. coreRI.sortDistSq = F32_MAX; // If we need lights then set them up. if ( matInst->isForwardLit() ) { LightQuery query; query.init( getWorldSphere() ); query.getLights( coreRI.lights, 8 ); } U32 startBatchIdx = -1; U32 endBatchIdx = 0; for ( U32 i = 0; i < mBatches.size(); i++ ) { const RoadBatch &batch = mBatches[i]; const bool isVisible = !frustum.isCulled( batch.bounds ); if ( isVisible ) { // If this is the start of a set of batches. if ( startBatchIdx == -1 ) endBatchIdx = startBatchIdx = i; // Else we're extending the end batch index. else ++endBatchIdx; // If this isn't the last batch then continue. if ( i < mBatches.size()-1 ) continue; } // We we still don't have a start batch, so skip. if ( startBatchIdx == -1 ) continue; // Render this set of batches. const RoadBatch &startBatch = mBatches[startBatchIdx]; const RoadBatch &endBatch = mBatches[endBatchIdx]; U32 startVert = startBatch.startVert; U32 startIdx = startBatch.startIndex; U32 vertCount = endBatch.endVert - startVert; U32 idxCount = ( endBatch.endIndex - startIdx ) + 1; U32 triangleCount = idxCount / 3; AssertFatal( startVert + vertCount <= mVertCount, "DecalRoad, bad draw call!" ); AssertFatal( startIdx + triangleCount < mTriangleCount * 3, "DecalRoad, bad draw call!" ); MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>(); *ri = coreRI; ri->prim = renderPass->allocPrim(); ri->prim->type = GFXTriangleList; ri->prim->minIndex = 0; ri->prim->startIndex = startIdx; ri->prim->numPrimitives = triangleCount; ri->prim->startVertex = 0; ri->prim->numVertices = endBatch.endVert + 1; // For sorting we first sort by render priority // and then by objectId. // // Since a road can submit more than one render instance, we want all // draw calls for a single road to occur consecutively, since they // could use the same vertex buffer. ri->defaultKey = mRenderPriority << 0 | mId << 16; ri->defaultKey2 = 0; renderPass->addInst( ri ); // Reset the batching. startBatchIdx = -1; } }
bool DecalManager::prepRenderImage(SceneState* state, const U32 stateKey, const U32 /*startZone*/, const bool /*modifyBaseState*/) { PROFILE_SCOPE( DecalManager_RenderDecals ); if ( !smDecalsOn || !mData ) return false; if (isLastState(state, stateKey)) return false; setLastState(state, stateKey); if ( !state->isDiffusePass() && !state->isReflectPass() ) return false; PROFILE_START( DecalManager_RenderDecals_SphereTreeCull ); // Grab this before anything here changes it. mCuller = state->getFrustum(); // Populate vector of decal instances to be rendered with all // decals from visible decal spheres. mDecalQueue.clear(); const Vector<DecalSphere*> &grid = mData->getGrid(); for ( U32 i = 0; i < grid.size(); i++ ) { const DecalSphere *decalSphere = grid[i]; const SphereF &worldSphere = decalSphere->mWorldSphere; if ( !mCuller.sphereInFrustum( worldSphere.center, worldSphere.radius ) ) continue; // TODO: If each sphere stored its largest decal instance we // could do an LOD step on it here and skip adding any of the // decals in the sphere. mDecalQueue.merge( decalSphere->mItems ); } PROFILE_END(); PROFILE_START( DecalManager_RenderDecals_Update ); const U32 &curSimTime = Sim::getCurrentTime(); const Point2I &viewportExtent = state->getViewportExtent(); Point3F cameraOffset; F32 decalSize, pixelRadius; U32 delta, diff; DecalInstance *dinst; // Loop through DecalQueue once for preRendering work. // 1. Update DecalInstance fade (over time) // 2. Clip geometry if flagged to do so. // 3. Calculate lod - if decal is far enough away it will not render. for ( U32 i = 0; i < mDecalQueue.size(); i++ ) { dinst = mDecalQueue[i]; // LOD calculation. // See TSShapeInstance::setDetailFromDistance for more // information on these calculations. decalSize = getMax( dinst->mSize, 0.001f ); pixelRadius = dinst->calcPixelRadius( state ); // Need to clamp here. if ( pixelRadius < dinst->calcEndPixRadius( viewportExtent ) ) { mDecalQueue.erase_fast( i ); i--; continue; } // We're gonna try to render this decal... so do any // final adjustments to it before rendering. // Update fade and delete expired. if ( !( dinst->mFlags & PermanentDecal || dinst->mFlags & CustomDecal ) ) { delta = ( curSimTime - dinst->mCreateTime ); if ( delta > dinst->mDataBlock->lifeSpan ) { diff = delta - dinst->mDataBlock->lifeSpan; dinst->mVisibility = 1.0f - (F32)diff / (F32)dinst->mDataBlock->fadeTime; if ( dinst->mVisibility <= 0.0f ) { mDecalQueue.erase_fast( i ); removeDecal( dinst ); i--; continue; } } } // Build clipped geometry for this decal if needed. if ( dinst->mFlags & ClipDecal/* && !( dinst->mFlags & CustomDecal ) */) { // Turn off the flag so we don't continually try to clip // if it fails. if(!clipDecal( dinst )) { dinst->mFlags = dinst->mFlags & ~ClipDecal; if ( !(dinst->mFlags & CustomDecal) ) { // Clipping failed to get any geometry... // Remove it from the render queue. mDecalQueue.erase_fast( i ); i--; // If the decal is one placed at run-time (not the editor) // then we should also permanently delete the decal instance. if ( !(dinst->mFlags & SaveDecal) ) { removeDecal( dinst ); } } // If this is a decal placed by the editor it will be // flagged to attempt clipping again the next time it is // modified. For now we just skip rendering it. continue; } } // If we get here and the decal still does not have any geometry // skip rendering it. It must be an editor placed decal that failed // to clip any geometry but has not yet been flagged to try again. if ( !dinst->mVerts || dinst->mVertCount == 0 || dinst->mIndxCount == 0 ) { mDecalQueue.erase_fast( i ); i--; continue; } // F32 alpha = pixelRadius / (dinst->mDataBlock->startPixRadius * decalSize) - 1.0f; if ( dinst->mFlags & CustomDecal ) { alpha = mClampF( alpha, 0.0f, 1.0f ); alpha *= dinst->mVisibility; } else alpha = mClampF( alpha * dinst->mVisibility, 0.0f, 1.0f ); // for ( U32 v = 0; v < dinst->mVertCount; v++ ) dinst->mVerts[v].color.set( 255, 255, 255, alpha * 255.0f ); } PROFILE_END(); if ( mDecalQueue.empty() ) return false; // Sort queued decals... // 1. Editor decals - in render priority order first, creation time second, and material third. // 2. Dynamic decals - in render priority order first and creation time second. // // With the constraint that decals with different render priority cannot // be rendered together in the same draw call. PROFILE_START( DecalManager_RenderDecals_Sort ); dQsort( mDecalQueue.address(), mDecalQueue.size(), sizeof(DecalInstance*), cmpDecalRenderOrder ); PROFILE_END(); PROFILE_SCOPE( DecalManager_RenderDecals_RenderBatch ); mPrimBuffs.clear(); mVBs.clear(); RenderPassManager *renderPass = state->getRenderPass(); // Base render instance for convenience we use for convenience. // Data shared by all instances we allocate below can be copied // from the base instance at the same time. MeshRenderInst baseRenderInst; baseRenderInst.clear(); MatrixF *tempMat = renderPass->allocUniqueXform( MatrixF( true ) ); MathUtils::getZBiasProjectionMatrix( gDecalBias, mCuller, tempMat ); baseRenderInst.projection = tempMat; baseRenderInst.objectToWorld = &MatrixF::Identity; baseRenderInst.worldToCamera = renderPass->allocSharedXform(RenderPassManager::View); baseRenderInst.type = RenderPassManager::RIT_Decal; // Make it the sort distance the max distance so that // it renders after all the other opaque geometry in // the prepass bin. baseRenderInst.sortDistSq = F32_MAX; // Get the best lights for the current camera position. LightManager *lm = state->getLightManager(); if ( lm ) { lm->setupLights( NULL, mCuller.getPosition(), mCuller.getTransform().getForwardVector(), mCuller.getFarDist() ); lm->getBestLights( baseRenderInst.lights, 4 ); lm->resetLights(); } Vector<DecalBatch> batches; DecalBatch *currentBatch = NULL; // Loop through DecalQueue collecting them into render batches. for ( U32 i = 0; i < mDecalQueue.size(); i++ ) { DecalInstance *decal = mDecalQueue[i]; DecalData *data = decal->mDataBlock; Material *mat = data->getMaterial(); if ( currentBatch == NULL ) { // Start a new batch, beginning with this decal. batches.increment(); currentBatch = &batches.last(); currentBatch->startDecal = i; currentBatch->decalCount = 1; currentBatch->iCount = decal->mIndxCount; currentBatch->vCount = decal->mVertCount; currentBatch->mat = mat; currentBatch->matInst = decal->mDataBlock->getMaterialInstance(); currentBatch->priority = decal->getRenderPriority(); currentBatch->dynamic = !(decal->mFlags & SaveDecal); continue; } if ( currentBatch->iCount + decal->mIndxCount >= smMaxIndices || currentBatch->vCount + decal->mVertCount >= smMaxVerts || currentBatch->mat != mat || currentBatch->priority != decal->getRenderPriority() || decal->mCustomTex ) { // End batch. currentBatch = NULL; i--; continue; } // Add on to current batch. currentBatch->decalCount++; currentBatch->iCount += decal->mIndxCount; currentBatch->vCount += decal->mVertCount; } // Loop through batches allocating buffers and submitting render instances. for ( U32 i = 0; i < batches.size(); i++ ) { DecalBatch ¤tBatch = batches[i]; // Allocate buffers... GFXVertexBufferHandle<DecalVertex> vb; vb.set( GFX, currentBatch.vCount, GFXBufferTypeDynamic ); DecalVertex *vpPtr = vb.lock(); GFXPrimitiveBufferHandle pb; pb.set( GFX, currentBatch.iCount, 0, GFXBufferTypeDynamic ); U16 *pbPtr; pb.lock( &pbPtr ); // Copy data into the buffers from all decals in this batch... U32 lastDecal = currentBatch.startDecal + currentBatch.decalCount; U32 voffset = 0; U32 ioffset = 0; // This is an ugly hack for ProjectedShadow! GFXTextureObject *customTex = NULL; for ( U32 j = currentBatch.startDecal; j < lastDecal; j++ ) { DecalInstance *dinst = mDecalQueue[j]; for ( U32 k = 0; k < dinst->mIndxCount; k++ ) { *( pbPtr + ioffset + k ) = dinst->mIndices[k] + voffset; } ioffset += dinst->mIndxCount; dMemcpy( vpPtr + voffset, dinst->mVerts, sizeof( DecalVertex ) * dinst->mVertCount ); voffset += dinst->mVertCount; // Ugly hack for ProjectedShadow! if ( (dinst->mFlags & CustomDecal) && dinst->mCustomTex != NULL ) customTex = *dinst->mCustomTex; } AssertFatal( ioffset == currentBatch.iCount, "bad" ); AssertFatal( voffset == currentBatch.vCount, "bad" ); pb.unlock(); vb.unlock(); // DecalManager must hold handles to these buffers so they remain valid, // we don't actually use them elsewhere. mPrimBuffs.push_back( pb ); mVBs.push_back( vb ); // Submit render inst... MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>(); *ri = baseRenderInst; ri->primBuff = &mPrimBuffs.last(); ri->vertBuff = &mVBs.last(); ri->matInst = currentBatch.matInst; ri->prim = renderPass->allocPrim(); ri->prim->type = GFXTriangleList; ri->prim->minIndex = 0; ri->prim->startIndex = 0; ri->prim->numPrimitives = currentBatch.iCount / 3; ri->prim->startVertex = 0; ri->prim->numVertices = currentBatch.vCount; // Ugly hack for ProjectedShadow! if ( customTex ) ri->miscTex = customTex; // The decal bin will contain render instances for both decals and decalRoad's. // Dynamic decals render last, then editor decals and roads in priority order. // DefaultKey is sorted in descending order. ri->defaultKey = currentBatch.dynamic ? 0xFFFFFFFF : (U32)currentBatch.priority; ri->defaultKey2 = 1;//(U32)lastDecal->mDataBlock; renderPass->addInst( ri ); } return false; }
void ConvexShape::prepRenderImage( SceneRenderState *state ) { /* if ( state->isDiffusePass() ) { ObjectRenderInst *ri2 = state->getRenderPass()->allocInst<ObjectRenderInst>(); ri2->renderDelegate.bind( this, &ConvexShape::_renderDebug ); ri2->type = RenderPassManager::RIT_Editor; state->getRenderPass()->addInst( ri2 ); } */ if ( mVertexBuffer.isNull() ) return; // If we don't have a material instance after the override then // we can skip rendering all together. BaseMatInstance *matInst = state->getOverrideMaterial( mMaterialInst ? mMaterialInst : MATMGR->getWarningMatInstance() ); if ( !matInst ) return; // Get a handy pointer to our RenderPassmanager RenderPassManager *renderPass = state->getRenderPass(); // Allocate an MeshRenderInst so that we can submit it to the RenderPassManager MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>(); // Set our RenderInst as a standard mesh render ri->type = RenderPassManager::RIT_Mesh; // Calculate our sorting point if ( state ) { // Calculate our sort point manually. const Box3F& rBox = getRenderWorldBox(); ri->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() ); } else ri->sortDistSq = 0.0f; // Set up our transforms MatrixF objectToWorld = getRenderTransform(); objectToWorld.scale( getScale() ); ri->objectToWorld = renderPass->allocUniqueXform( objectToWorld ); ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View); ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection); // If we need lights then set them up. if ( matInst->isForwardLit() ) { LightQuery query; query.init( getWorldSphere() ); query.getLights( ri->lights, 8 ); } // Make sure we have an up-to-date backbuffer in case // our Material would like to make use of it // NOTICE: SFXBB is removed and refraction is disabled! //ri->backBuffTex = GFX->getSfxBackBuffer(); // Set our Material ri->matInst = matInst; if ( matInst->getMaterial()->isTranslucent() ) { ri->translucentSort = true; ri->type = RenderPassManager::RIT_Translucent; } // Set up our vertex buffer and primitive buffer ri->vertBuff = &mVertexBuffer; ri->primBuff = &mPrimitiveBuffer; ri->prim = renderPass->allocPrim(); ri->prim->type = GFXTriangleList; ri->prim->minIndex = 0; ri->prim->startIndex = 0; ri->prim->numPrimitives = mPrimCount; ri->prim->startVertex = 0; ri->prim->numVertices = mVertCount; // We sort by the material then vertex buffer. ri->defaultKey = matInst->getStateHint(); ri->defaultKey2 = (U32)ri->vertBuff; // Not 64bit safe! // Submit our RenderInst to the RenderPassManager state->getRenderPass()->addInst( ri ); }
void RenderMeshExample::prepRenderImage( SceneRenderState *state ) { // Do a little prep work if needed if ( mVertexBuffer.isNull() ) createGeometry(); // If we have no material then skip out. if ( !mMaterialInst ) return; // If we don't have a material instance after the override then // we can skip rendering all together. BaseMatInstance *matInst = state->getOverrideMaterial( mMaterialInst ); if ( !matInst ) return; // Get a handy pointer to our RenderPassmanager RenderPassManager *renderPass = state->getRenderPass(); // Allocate an MeshRenderInst so that we can submit it to the RenderPassManager MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>(); // Set our RenderInst as a standard mesh render ri->type = RenderPassManager::RIT_Mesh; // Calculate our sorting point if ( state ) { // Calculate our sort point manually. const Box3F& rBox = getRenderWorldBox(); ri->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() ); } else ri->sortDistSq = 0.0f; // Set up our transforms MatrixF objectToWorld = getRenderTransform(); objectToWorld.scale( getScale() ); ri->objectToWorld = renderPass->allocUniqueXform( objectToWorld ); ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View); ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection); // If our material needs lights then fill the RIs // light vector with the best lights. if ( matInst->isForwardLit() ) { LightQuery query; query.init( getWorldSphere() ); query.getLights( ri->lights, 8 ); } // Make sure we have an up-to-date backbuffer in case // our Material would like to make use of it // NOTICE: SFXBB is removed and refraction is disabled! //ri->backBuffTex = GFX->getSfxBackBuffer(); // Set our Material ri->matInst = matInst; // Set up our vertex buffer and primitive buffer ri->vertBuff = &mVertexBuffer; ri->primBuff = &mPrimitiveBuffer; ri->prim = renderPass->allocPrim(); ri->prim->type = GFXTriangleList; ri->prim->minIndex = 0; ri->prim->startIndex = 0; ri->prim->numPrimitives = 12; ri->prim->startVertex = 0; ri->prim->numVertices = 36; // We sort by the material then vertex buffer ri->defaultKey = matInst->getStateHint(); ri->defaultKey2 = (U32)ri->vertBuff; // Not 64bit safe! // Submit our RenderInst to the RenderPassManager state->getRenderPass()->addInst( ri ); }
bool DecalRoad::prepRenderImage( SceneState* state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState) { if ( mNodes.size() <= 1 || isLastState(state, stateKey) || mBatches.size() == 0 || !mMatInst || state->isShadowPass() ) return false; // Set Last State. setLastState( state, stateKey ); // Is Object Rendered? if ( !state->isObjectRendered( this ) ) return false; RenderPassManager *renderPass = state->getRenderPass(); // Debug RenderInstance // Only when editor is open. if ( smEditorOpen ) { ObjectRenderInst *ri = renderPass->allocInst<ObjectRenderInst>(); ri->type = RenderPassManager::RIT_Object; ri->renderDelegate.bind( this, &DecalRoad::_debugRender ); state->getRenderPass()->addInst( ri ); } // Normal Road RenderInstance // Always rendered when the editor is not open // otherwise obey the smShowRoad flag if ( !smShowRoad && smEditorOpen ) return false; const Frustum &frustum = state->getFrustum(); MeshRenderInst coreRI; coreRI.clear(); coreRI.objectToWorld = &MatrixF::Identity; coreRI.worldToCamera = renderPass->allocSharedXform(RenderPassManager::View); MatrixF *tempMat = renderPass->allocUniqueXform( MatrixF( true ) ); MathUtils::getZBiasProjectionMatrix( gDecalBias, frustum, tempMat ); coreRI.projection = tempMat; coreRI.type = RenderPassManager::RIT_Decal; coreRI.matInst = mMatInst; coreRI.vertBuff = &mVB; coreRI.primBuff = &mPB; // Make it the sort distance the max distance so that // it renders after all the other opaque geometry in // the prepass bin. coreRI.sortDistSq = F32_MAX; // Get the light manager and setup lights LightManager *lm = state->getLightManager(); if ( lm ) { lm->setupLights( this, getWorldSphere() ); lm->getBestLights( coreRI.lights, 8 ); } U32 startBatchIdx = -1; U32 endBatchIdx = 0; for ( U32 i = 0; i < mBatches.size(); i++ ) { // TODO: visibility is bugged... must fix! //const RoadBatch &batch = mBatches[i]; //const bool isVisible = frustum.intersects( batch.bounds ); if ( true /*isVisible*/ ) { // If this is the start of a set of batches. if ( startBatchIdx == -1 ) endBatchIdx = startBatchIdx = i; // Else we're extending the end batch index. else ++endBatchIdx; // If this isn't the last batch then continue. if ( i < mBatches.size()-1 ) continue; } // We we still don't have a start batch, so skip. if ( startBatchIdx == -1 ) continue; // Render this set of batches. const RoadBatch &startBatch = mBatches[startBatchIdx]; // mBatches[0]; const RoadBatch &endBatch = mBatches[endBatchIdx]; // mBatches.last(); U32 startVert = startBatch.startVert; U32 startIdx = startBatch.startIndex; U32 vertCount = endBatch.endVert - startVert; U32 idxCount = ( endBatch.endIndex - startIdx ) + 1; U32 triangleCount = idxCount / 3; AssertFatal( startVert + vertCount <= mVertCount, "DecalRoad, bad draw call!" ); AssertFatal( startIdx + triangleCount < mTriangleCount * 3, "DecalRoad, bad draw call!" ); MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>(); *ri = coreRI; ri->prim = renderPass->allocPrim(); ri->prim->type = GFXTriangleList; ri->prim->minIndex = 0; ri->prim->startIndex = startIdx; ri->prim->numPrimitives = triangleCount; ri->prim->startVertex = startVert; ri->prim->numVertices = vertCount; // For sorting we first sort by render priority // and then by objectId. // // Since a road can submit more than one render instance, we want all // draw calls for a single road to occur consecutively, since they // could use the same vertex buffer. ri->defaultKey = mRenderPriority << 0 | mId << 16; ri->defaultKey2 = 0; renderPass->addInst( ri ); // Reset the batching. startBatchIdx = -1; } return false; }
void TSMesh::innerRender( TSMaterialList *materials, const TSRenderState &rdata, TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb ) { PROFILE_SCOPE( TSMesh_InnerRender ); if( vertsPerFrame <= 0 ) return; F32 meshVisibility = rdata.getFadeOverride() * mVisibility; if ( meshVisibility < VISIBILITY_EPSILON ) return; const SceneRenderState *state = rdata.getSceneState(); RenderPassManager *renderPass = state->getRenderPass(); MeshRenderInst *coreRI = renderPass->allocInst<MeshRenderInst>(); coreRI->type = RenderPassManager::RIT_Mesh; const MatrixF &objToWorld = GFX->getWorldMatrix(); // Sort by the center point or the bounds. if ( rdata.useOriginSort() ) coreRI->sortDistSq = ( objToWorld.getPosition() - state->getCameraPosition() ).lenSquared(); else { Box3F rBox = mBounds; objToWorld.mul( rBox ); coreRI->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() ); } if (getFlags(Billboard)) { Point3F camPos = state->getDiffuseCameraPosition(); Point3F objPos; objToWorld.getColumn(3, &objPos); Point3F targetVector = camPos - objPos; if(getFlags(BillboardZAxis)) targetVector.z = 0.0f; targetVector.normalize(); MatrixF orient = MathUtils::createOrientFromDir(targetVector); orient.setPosition(objPos); orient.scale(objToWorld.getScale()); coreRI->objectToWorld = renderPass->allocUniqueXform( orient ); } else coreRI->objectToWorld = renderPass->allocUniqueXform( objToWorld ); coreRI->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View); coreRI->projection = renderPass->allocSharedXform(RenderPassManager::Projection); AssertFatal( vb.isValid(), "TSMesh::innerRender() - Got invalid vertex buffer!" ); AssertFatal( pb.isValid(), "TSMesh::innerRender() - Got invalid primitive buffer!" ); coreRI->vertBuff = &vb; coreRI->primBuff = &pb; coreRI->defaultKey2 = (U32) coreRI->vertBuff; coreRI->materialHint = rdata.getMaterialHint(); coreRI->visibility = meshVisibility; coreRI->cubemap = rdata.getCubemap(); // NOTICE: SFXBB is removed and refraction is disabled! //coreRI->backBuffTex = GFX->getSfxBackBuffer(); for ( S32 i = 0; i < primitives.size(); i++ ) { const TSDrawPrimitive &draw = primitives[i]; // We need to have a material. if ( draw.matIndex & TSDrawPrimitive::NoMaterial ) continue; #ifdef TORQUE_DEBUG // for inspection if you happen to be running in a debugger and can't do bit // operations in your head. S32 triangles = draw.matIndex & TSDrawPrimitive::Triangles; S32 strip = draw.matIndex & TSDrawPrimitive::Strip; S32 fan = draw.matIndex & TSDrawPrimitive::Fan; S32 indexed = draw.matIndex & TSDrawPrimitive::Indexed; S32 type = draw.matIndex & TSDrawPrimitive::TypeMask; TORQUE_UNUSED(triangles); TORQUE_UNUSED(strip); TORQUE_UNUSED(fan); TORQUE_UNUSED(indexed); TORQUE_UNUSED(type); #endif const U32 matIndex = draw.matIndex & TSDrawPrimitive::MaterialMask; BaseMatInstance *matInst = materials->getMaterialInst( matIndex ); #ifndef TORQUE_OS_MAC // Get the instancing material if this mesh qualifies. if ( meshType != SkinMeshType && pb->mPrimitiveArray[i].numVertices < smMaxInstancingVerts ) matInst = InstancingMaterialHook::getInstancingMat( matInst ); #endif // If we don't have a material instance after the overload then // there is nothing to render... skip this primitive. matInst = state->getOverrideMaterial( matInst ); if ( !matInst || !matInst->isValid()) continue; // If the material needs lights then gather them // here once and set them on the core render inst. if ( matInst->isForwardLit() && !coreRI->lights[0] && rdata.getLightQuery() ) rdata.getLightQuery()->getLights( coreRI->lights, 8 ); MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>(); *ri = *coreRI; ri->matInst = matInst; ri->defaultKey = matInst->getStateHint(); ri->primBuffIndex = i; // Translucent materials need the translucent type. if ( matInst->getMaterial()->isTranslucent() ) { ri->type = RenderPassManager::RIT_Translucent; ri->translucentSort = true; } renderPass->addInst( ri ); } }