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 ); }
void TSLastDetail::render( TSRenderState &rdata, F32 alpha ) { #if 0 // Early out if we have nothing to render. if ( alpha < 0.01f || !mMatInstance || mMaterial->mImposterUVs.size() == 0 ) return; const MatrixF &mat = GFX->getWorldMatrix(); // Post a render instance for this imposter... the special // imposter render manager will do the magic! RenderPassManager *renderPass = rdata.getSceneState()->getRenderPass(); ImposterRenderInst *ri = renderPass->allocInst<ImposterRenderInst>(); ri->mat = rdata.getSceneState()->getOverrideMaterial( mMatInstance ); ri->state.alpha = alpha; // Store the up and right vectors of the rotation // and we'll generate the up vector in the shader. // // This is faster than building a quat on the // CPU and then rebuilding the matrix on the GPU. // // NOTE: These vector include scale. // mat.getColumn( 2, &ri->state.upVec ); mat.getColumn( 0, &ri->state.rightVec ); // We send the unscaled size and the vertex shader // will use the orientation vectors above to scale it. ri->state.halfSize = mRadius; // We use the center of the object bounds for // the center of the billboard quad. mat.mulP( mCenter, &ri->state.center ); // We sort by the imposter type first so that RIT_Imposter and s // RIT_ImposterBatches do not get mixed together. // // We then sort by material. // ri->defaultKey = 1; ri->defaultKey2 = ri->mat->getStateHint(); renderPass->addInst( ri ); #endif }
RenderPrePassMgr* LightManager::_findPrePassRenderBin() { RenderPassManager* rpm = getSceneManager()->getDefaultRenderPass(); for( U32 i = 0; i < rpm->getManagerCount(); i++ ) { RenderBinManager *bin = rpm->getManager( i ); if( bin->getRenderInstType() == RenderPrePassMgr::RIT_PrePass ) { return ( RenderPrePassMgr* ) bin; } } return NULL; }
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 EditTSCtrl::renderWorld(const RectI & updateRect) { // Make sure that whatever the editor does, it doesn't // dirty the GFX transform state. GFXTransformSaver saver; updateGizmo(); gClientSceneGraph->setDisplayTargetResolution(getExtent()); // Use a render instance to do editor 3D scene // rendering after HDR is processed and while the depth // buffer is still intact. RenderPassManager *rpm = gClientSceneGraph->getDefaultRenderPass(); ObjectRenderInst *inst = rpm->allocInst<ObjectRenderInst>(); inst->type = RenderPassManager::RIT_Editor; inst->renderDelegate.bind(this, &EditTSCtrl::_renderScene); rpm->addInst(inst); if( mDisplayType == DisplayTypePerspective ) gClientSceneGraph->renderScene( SPT_Diffuse ); else { // If we are in an orthographic mode, do a special render // with AL, fog, and PostFX disabled. FogData savedFogData = gClientSceneGraph->getFogData(); gClientSceneGraph->setFogData( FogData() ); SceneRenderState renderState ( gClientSceneGraph, SPT_Diffuse ); gClientSceneGraph->renderScene( &renderState ); gClientSceneGraph->setFogData( savedFogData ); } }
void SceneManager::renderScene( ScenePassType passType, U32 objectMask ) { SceneCameraState cameraState = SceneCameraState::fromGFX(); // Handle frustum locking. const bool lockedFrustum = ( smLockDiffuseFrustum && passType == SPT_Diffuse ); if( lockedFrustum ) cameraState = smLockedDiffuseCamera; else if( passType == SPT_Diffuse ) { // Store the camera state so if we lock, this will become the // locked state. if( passType == SPT_Diffuse ) smLockedDiffuseCamera = cameraState; } // Create the render state. SceneRenderState renderState( this, passType, cameraState ); // If we have locked the frustum, reset the view transform // on the render pass which the render state has just set // to the view matrix corresponding to the locked frustum. For // rendering, however, we need the true view matrix from the // GFX state. if( lockedFrustum ) { RenderPassManager* rpm = renderState.getRenderPass(); rpm->assignSharedXform( RenderPassManager::View, GFX->getWorldMatrix() ); } // Render. renderScene( &renderState, objectMask ); }
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 TSStatic::prepRenderImage( SceneRenderState* state ) { if( !mShapeInstance ) return; Point3F cameraOffset; getRenderTransform().getColumn(3,&cameraOffset); cameraOffset -= state->getDiffuseCameraPosition(); F32 dist = cameraOffset.len(); if (dist < 0.01f) dist = 0.01f; if (mUseAlphaFade) { mAlphaFade = 1.0f; if ((mAlphaFadeStart < mAlphaFadeEnd) && mAlphaFadeStart > 0.1f) { if (mInvertAlphaFade) { if (dist <= mAlphaFadeStart) { return; } if (dist < mAlphaFadeEnd) { mAlphaFade = ((dist - mAlphaFadeStart) / (mAlphaFadeEnd - mAlphaFadeStart)); } } else { if (dist >= mAlphaFadeEnd) { return; } if (dist > mAlphaFadeStart) { mAlphaFade -= ((dist - mAlphaFadeStart) / (mAlphaFadeEnd - mAlphaFadeStart)); } } } } F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z)); // If we're currently rendering our own reflection we // don't want to render ourselves into it. if ( mCubeReflector.isRendering() ) return; if ( mForceDetail == -1 ) mShapeInstance->setDetailFromDistance( state, dist * invScale ); else mShapeInstance->setCurrentDetail( mForceDetail ); if ( mShapeInstance->getCurrentDetail() < 0 ) return; GFXTransformSaver saver; // Set up our TS render state. TSRenderState rdata; rdata.setSceneState( state ); rdata.setFadeOverride( 1.0f ); rdata.setOriginSort( mUseOriginSort ); if ( mCubeReflector.isEnabled() ) rdata.setCubemap( mCubeReflector.getCubemap() ); // Acculumation rdata.setAccuTex(mAccuTex); // If we have submesh culling enabled then prepare // the object space frustum to pass to the shape. Frustum culler; if ( mMeshCulling ) { culler = state->getCullingFrustum(); MatrixF xfm( true ); xfm.scale( Point3F::One / getScale() ); xfm.mul( getRenderWorldTransform() ); xfm.mul( culler.getTransform() ); culler.setTransform( xfm ); rdata.setCuller( &culler ); } // We might have some forward lit materials // so pass down a query to gather lights. LightQuery query; query.init( getWorldSphere() ); rdata.setLightQuery( &query ); MatrixF mat = getRenderTransform(); mat.scale( mObjScale ); GFX->setWorldMatrix( mat ); if ( state->isDiffusePass() && mCubeReflector.isEnabled() && mCubeReflector.getOcclusionQuery() ) { RenderPassManager *pass = state->getRenderPass(); OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>(); ri->type = RenderPassManager::RIT_Occluder; ri->query = mCubeReflector.getOcclusionQuery(); mObjToWorld.mulP( mObjBox.getCenter(), &ri->position ); ri->scale.set( mObjBox.getExtents() ); ri->orientation = pass->allocUniqueXform( mObjToWorld ); ri->isSphere = false; state->getRenderPass()->addInst( ri ); } mShapeInstance->animate(); if(mShapeInstance) { if (mUseAlphaFade) { mShapeInstance->setAlphaAlways(mAlphaFade); S32 s = mShapeInstance->mMeshObjects.size(); for(S32 x = 0; x < s; x++) { mShapeInstance->mMeshObjects[x].visible = mAlphaFade; } } } mShapeInstance->render( rdata ); if ( mRenderNormalScalar > 0 ) { ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); ri->renderDelegate.bind( this, &TSStatic::_renderNormals ); ri->type = RenderPassManager::RIT_Editor; state->getRenderPass()->addInst( ri ); } }
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 RenderTranslucentMgr::render( SceneRenderState *state ) { PROFILE_SCOPE(RenderTranslucentMgr_render); // Early out if nothing to draw. if(!mElementList.size()) return; GFXDEBUGEVENT_SCOPE(RenderTranslucentMgr_Render, ColorI::BLUE); // Find the particle render manager (if we don't have it) if(mParticleRenderMgr == NULL) { RenderPassManager *rpm = state->getRenderPass(); for( U32 i = 0; i < rpm->getManagerCount(); i++ ) { RenderBinManager *bin = rpm->getManager(i); if( bin->getRenderInstType() == RenderParticleMgr::RIT_Particles ) { mParticleRenderMgr = reinterpret_cast<RenderParticleMgr *>(bin); break; } } } GFXTransformSaver saver; SceneData sgData; sgData.init( state ); GFXVertexBuffer * lastVB = NULL; GFXPrimitiveBuffer * lastPB = NULL; // Restore transforms MatrixSet &matrixSet = getRenderPass()->getMatrixSet(); matrixSet.restoreSceneViewProjection(); U32 binSize = mElementList.size(); for( U32 j=0; j<binSize; ) { RenderInst *baseRI = mElementList[j].inst; U32 matListEnd = j; // render these separately... if ( baseRI->type == RenderPassManager::RIT_ObjectTranslucent ) { ObjectRenderInst* objRI = static_cast<ObjectRenderInst*>(baseRI); objRI->renderDelegate( objRI, state, NULL ); lastVB = NULL; lastPB = NULL; j++; continue; } //Volumetric Fog Add else if (baseRI->type == RenderPassManager::RIT_VolumetricFog) { ObjectRenderInst* objRI = static_cast<ObjectRenderInst*>(baseRI); objRI->renderDelegate(objRI,state,NULL); lastVB = NULL; lastPB = NULL; j++; continue; } //Volumetric Fog Add else if ( baseRI->type == RenderPassManager::RIT_Particle ) { ParticleRenderInst *ri = static_cast<ParticleRenderInst*>(baseRI); // Tell Particle RM to draw the system. (This allows the particle render manager // to manage drawing offscreen particle systems, and allows the systems // to be composited back into the scene with proper translucent // sorting order) mParticleRenderMgr->renderInstance(ri, state); lastVB = NULL; // no longer valid, null it lastPB = NULL; // no longer valid, null it j++; continue; } else if ( baseRI->type == RenderPassManager::RIT_Translucent ) { MeshRenderInst* ri = static_cast<MeshRenderInst*>(baseRI); BaseMatInstance *mat = ri->matInst; setupSGData( ri, sgData ); while( mat->setupPass( state, sgData ) ) { U32 a; for( a=j; a<binSize; a++ ) { RenderInst* nextRI = mElementList[a].inst; if ( nextRI->type != RenderPassManager::RIT_Translucent ) break; MeshRenderInst *passRI = static_cast<MeshRenderInst*>(nextRI); // Check to see if we need to break this batch. if ( newPassNeeded( ri, passRI ) ) break; // Z sorting and stuff is still not working in this mgr... setupSGData( passRI, sgData ); mat->setSceneInfo(state, sgData); matrixSet.setWorld(*passRI->objectToWorld); matrixSet.setView(*passRI->worldToCamera); matrixSet.setProjection(*passRI->projection); mat->setTransforms(matrixSet, state); // If we're instanced then don't render yet. if ( mat->isInstanced() ) { // Let the material increment the instance buffer, but // break the batch if it runs out of room for more. if ( !mat->stepInstance() ) { a++; break; } continue; } // Setup the vertex and index buffers. mat->setBuffers( passRI->vertBuff, passRI->primBuff ); // Render this sucker. if ( passRI->prim ) GFX->drawPrimitive( *passRI->prim ); else GFX->drawPrimitive( passRI->primBuffIndex ); } // Draw the instanced batch. if ( mat->isInstanced() ) { // Sets the buffers including the instancing stream. mat->setBuffers( ri->vertBuff, ri->primBuff ); // Render the instanced stream. if ( ri->prim ) GFX->drawPrimitive( *ri->prim ); else GFX->drawPrimitive( ri->primBuffIndex ); } matListEnd = a; } // force increment if none happened, otherwise go to end of batch j = ( j == matListEnd ) ? j+1 : matListEnd; } } }
void LightFlareData::prepRender( SceneState *state, LightFlareState *flareState ) { PROFILE_SCOPE( LightFlareData_prepRender ); // No elements then nothing to render. if ( mElementCount == 0 ) return; // We need these all over the place later. const Point3F &camPos = state->getCameraPosition(); const RectI &viewport = GFX->getViewport(); const Point3F &lightPos = flareState->lightMat.getPosition(); LightInfo *lightInfo = flareState->lightInfo; bool isVectorLight = lightInfo->getType() == LightInfo::Vector; // Perform visibility testing on the light... // Project the light position from world to screen space, we need this // position later, and it tells us if it is actually onscreen. Point3F lightPosSS; bool onscreen = MathUtils::mProjectWorldToScreen( lightPos, &lightPosSS, viewport, GFX->getWorldMatrix(), gClientSceneGraph->getNonClipProjection() ); U32 visDelta = U32_MAX; U32 fadeOutTime = 20; U32 fadeInTime = 125; // Fade factor based on amount of occlusion. F32 occlusionFade = 1.0f; bool lightVisible = true; if ( !state->isReflectPass() ) { // It is onscreen, so raycast as a simple occlusion test. U32 losMask = STATIC_COLLISION_MASK | ShapeBaseObjectType | StaticTSObjectType | ItemObjectType | PlayerObjectType; GameConnection *conn = GameConnection::getConnectionToServer(); if ( !conn ) return; bool needsRaycast = true; // NOTE: if hardware does not support HOQ it will return NULL // and we will retry every time but there is not currently a good place // for one-shot initialization of LightFlareState if ( flareState->occlusionQuery == NULL ) flareState->occlusionQuery = GFX->createOcclusionQuery(); if ( flareState->fullPixelQuery == NULL ) flareState->fullPixelQuery = GFX->createOcclusionQuery(); if ( flareState->occlusionQuery && ( ( isVectorLight && flareState->worldRadius > 0.0f ) || ( !isVectorLight && mOcclusionRadius > 0.0f ) ) ) { // Always treat light as onscreen if using HOQ // it will be faded out if offscreen anyway. onscreen = true; U32 pixels = -1; GFXOcclusionQuery::OcclusionQueryStatus status = flareState->occlusionQuery->getStatus( true, &pixels ); String str = flareState->occlusionQuery->statusToString( status ); Con::setVariable( "$Flare::OcclusionStatus", str.c_str() ); Con::setIntVariable( "$Flare::OcclusionVal", pixels ); if ( status == GFXOcclusionQuery::Occluded ) occlusionFade = 0.0f; if ( status != GFXOcclusionQuery::Unset ) needsRaycast = false; RenderPassManager *pass = state->getRenderPass(); OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>(); Point3F scale( Point3F::One ); if ( isVectorLight && flareState->worldRadius > 0.0f ) scale *= flareState->worldRadius; else scale *= mOcclusionRadius; ri->type = RenderPassManager::RIT_Occluder; ri->query = flareState->occlusionQuery; ri->query2 = flareState->fullPixelQuery; ri->position = lightPos; ri->scale = scale; ri->orientation = pass->allocUniqueXform( lightInfo->getTransform() ); ri->isSphere = true; state->getRenderPass()->addInst( ri ); if ( status == GFXOcclusionQuery::NotOccluded ) { U32 fullPixels; flareState->fullPixelQuery->getStatus( true, &fullPixels ); occlusionFade = (F32)pixels / (F32)fullPixels; // Approximation of the full pixel count rather than doing // two queries, but it is not very accurate. /* F32 dist = ( camPos - lightPos ).len(); F32 radius = scale.x; radius = ( radius / dist ) * state->getWorldToScreenScale().y; occlusionFade = (F32)pixels / (4.0f * radius * radius); occlusionFade = mClampF( occlusionFade, 0.0f, 1.0f ); */ } } Con::setFloatVariable( "$Flare::OcclusionFade", occlusionFade ); if ( needsRaycast ) { // Use a raycast to determine occlusion. bool fps = conn->isFirstPerson(); GameBase *control = conn->getControlObject(); if ( control && fps ) control->disableCollision(); RayInfo rayInfo; if ( gClientContainer.castRayRendered( camPos, lightPos, losMask, &rayInfo ) ) occlusionFade = 0.0f; if ( control && fps ) control->enableCollision(); } lightVisible = onscreen && occlusionFade > 0.0f; // To perform a fade in/out when we gain or lose visibility // we must update/store the visibility state and time. U32 currentTime = Sim::getCurrentTime(); if ( lightVisible != flareState->visible ) { flareState->visible = lightVisible; flareState->visChangedTime = currentTime; } // Save this in the state so that we have it during the reflect pass. flareState->occlusion = occlusionFade; visDelta = currentTime - flareState->visChangedTime; } else // state->isReflectPass() { occlusionFade = flareState->occlusion; lightVisible = flareState->visible; visDelta = Sim::getCurrentTime() - flareState->visChangedTime; } // We can only skip rendering if the light is not visible, and it // has elapsed the fadeOutTime. if ( !lightVisible && visDelta > fadeOutTime ) return; // In a reflection we only render the elements with zero distance. U32 elementCount = mElementCount; if ( state->isReflectPass() ) { elementCount = 0; for ( ; elementCount < mElementCount; elementCount++ ) { if ( mElementDist[elementCount] > 0.0f ) break; } } if ( elementCount == 0 ) return; // A bunch of preparatory math before generating verts... const Point2I &vpExtent = viewport.extent; Point3F viewportExtent( vpExtent.x, vpExtent.y, 1.0f ); Point2I halfViewportExtentI( viewport.extent / 2 ); Point3F halfViewportExtentF( (F32)halfViewportExtentI.x * 0.5f, (F32)halfViewportExtentI.y, 0.0f ); Point3F screenCenter( 0,0,0 ); Point3F oneOverViewportExtent( 1.0f / viewportExtent.x, 1.0f / viewportExtent.y, 1.0f ); lightPosSS.y -= viewport.point.y; lightPosSS *= oneOverViewportExtent; lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One; lightPosSS.y = -lightPosSS.y; lightPosSS.z = 0.0f; Point3F flareVec( screenCenter - lightPosSS ); F32 flareLength = flareVec.len(); flareVec.normalizeSafe(); Point3F basePoints[4]; basePoints[0] = Point3F( -0.5, 0.5, 0.0 ); basePoints[1] = Point3F( -0.5, -0.5, 0.0 ); basePoints[2] = Point3F( 0.5, -0.5, 0.0 ); basePoints[3] = Point3F( 0.5, 0.5, 0.0 ); Point3F rotatedBasePoints[4]; rotatedBasePoints[0] = basePoints[0]; rotatedBasePoints[1] = basePoints[1]; rotatedBasePoints[2] = basePoints[2]; rotatedBasePoints[3] = basePoints[3]; Point3F fvec( -1, 0, 0 ); F32 rot = mAcos( mDot( fvec, flareVec ) ); Point3F rvec( 0, -1, 0 ); rot *= mDot( rvec, flareVec ) > 0.0f ? 1.0f : -1.0f; vectorRotateZAxis( rotatedBasePoints[0], rot ); vectorRotateZAxis( rotatedBasePoints[1], rot ); vectorRotateZAxis( rotatedBasePoints[2], rot ); vectorRotateZAxis( rotatedBasePoints[3], rot ); // Here we calculate a the light source's influence on the effect's size // and brightness... // Scale based on the current light brightness compared to its normal output. F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness; // Scale based on world space distance from camera to light source. F32 lightSourceWSDistanceScale = ( isVectorLight ) ? 1.0f : getMin( 10.0f / ( lightPos - camPos ).len(), 1.5f ); // Scale based on screen space distance from screen position of light source to the screen center. F32 lightSourceSSDistanceScale = ( 1.5f - ( lightPosSS - screenCenter ).len() ) / 1.5f; // Scale based on recent visibility changes, fading in or out. F32 fadeInOutScale = 1.0f; if ( lightVisible && visDelta < fadeInTime && flareState->occlusion ) fadeInOutScale = (F32)visDelta / (F32)fadeInTime; else if ( !lightVisible && visDelta < fadeOutTime ) fadeInOutScale = 1.0f - (F32)visDelta / (F32)fadeOutTime; // This combined scale influences the size of all elements this effect renders. // Note we also add in a scale that is user specified in the Light. F32 lightSourceIntensityScale = lightSourceBrightnessScale * lightSourceWSDistanceScale * lightSourceSSDistanceScale * fadeInOutScale * flareState->scale * occlusionFade; // The baseColor which modulates the color of all elements. ColorF baseColor; if ( flareState->fullBrightness == 0.0f ) baseColor = ColorF::BLACK; else // These are the factors which affect the "alpha" of the flare effect. // Modulate more in as appropriate. baseColor = ColorF::WHITE * lightSourceBrightnessScale * occlusionFade; // Fill in the vertex buffer... const U32 vertCount = 4 * elementCount; if ( flareState->vertBuffer.isNull() || flareState->vertBuffer->mNumVerts != vertCount ) flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic ); GFXVertexPCT *pVert = flareState->vertBuffer.lock(); const Point2I &widthHeightI = mFlareTexture.getWidthHeight(); Point2F oneOverTexSize( 1.0f / (F32)widthHeightI.x, 1.0f / (F32)widthHeightI.y ); for ( U32 i = 0; i < elementCount; i++ ) { Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : basePoints; ColorF elementColor( baseColor * mElementTint[i] ); if ( mElementUseLightColor[i] ) elementColor *= lightInfo->getColor(); Point3F elementPos; elementPos = lightPosSS + flareVec * mElementDist[i] * flareLength; elementPos.z = 0.0f; F32 maxDist = 1.5f; F32 elementDist = mSqrt( ( elementPos.x * elementPos.x ) + ( elementPos.y * elementPos.y ) ); F32 distanceScale = ( maxDist - elementDist ) / maxDist; distanceScale = 1.0f; const RectF &elementRect = mElementRect[i]; Point3F elementSize( elementRect.extent.x, elementRect.extent.y, 1.0f ); elementSize *= mElementScale[i] * distanceScale * mScale * lightSourceIntensityScale; if ( elementSize.x < 100.0f ) { F32 alphaScale = mPow( elementSize.x / 100.0f, 2 ); elementColor *= alphaScale; } elementColor.clamp(); Point2F texCoordMin, texCoordMax; texCoordMin = elementRect.point * oneOverTexSize; texCoordMax = ( elementRect.point + elementRect.extent ) * oneOverTexSize; pVert->color = elementColor; pVert->point = ( basePos[0] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMin.x, texCoordMax.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[1] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMax.x, texCoordMax.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[2] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMax.x, texCoordMin.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[3] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMin.x, texCoordMin.y ); pVert++; } flareState->vertBuffer.unlock(); // Create and submit the render instance... RenderPassManager *renderManager = state->getRenderPass(); ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>(); ri->vertBuff = &flareState->vertBuffer; ri->primBuff = &mFlarePrimBuffer; ri->translucentSort = true; ri->type = RenderPassManager::RIT_Particle; ri->sortDistSq = ( lightPos - camPos ).lenSquared(); ri->modelViewProj = &MatrixF::Identity; ri->bbModelViewProj = ri->modelViewProj; ri->count = elementCount; // Only draw the light flare in high-res mode, never off-screen mode ri->systemState = ParticleRenderInst::AwaitingHighResDraw; ri->blendStyle = ParticleRenderInst::BlendGreyscale; ri->diffuseTex = &*(mFlareTexture); ri->softnessDistance = 1.0f; // Sort by texture too. ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff; renderManager->addInst( ri ); }
void ScatterSky::prepRenderImage( SceneRenderState *state ) { // Only render into diffuse and reflect passes. if( !state->isDiffusePass() && !state->isReflectPass() ) return; // Regular sky render instance. RenderPassManager* renderPass = state->getRenderPass(); ObjectRenderInst *ri = renderPass->allocInst<ObjectRenderInst>(); ri->renderDelegate.bind( this, &ScatterSky::_render ); ri->type = RenderPassManager::RIT_Sky; ri->defaultKey = 10; ri->defaultKey2 = 0; renderPass->addInst(ri); // Debug render instance. /* if ( Con::getBoolVariable( "$ScatterSky::debug", false ) ) { ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); ri->renderDelegate.bind( this, &ScatterSky::_debugRender ); ri->type = RenderPassManager::RIT_Editor; state->getRenderPass()->addInst( ri ); } */ // Light flare effect render instance. if ( mFlareData && mNightInterpolant != 1.0f ) { mFlareState.fullBrightness = mBrightness; mFlareState.scale = mFlareScale; mFlareState.lightInfo = mLight; Point3F lightPos = state->getCameraPosition() - state->getFarPlane() * mLight->getDirection() * 0.9f; mFlareState.lightMat.identity(); mFlareState.lightMat.setPosition( lightPos ); F32 dist = ( lightPos - state->getCameraPosition( ) ).len( ); F32 coronaScale = 0.5f; F32 screenRadius = GFX->getViewport( ).extent.y * coronaScale * 0.5f; mFlareState.worldRadius = screenRadius * dist / state->getWorldToScreenScale( ).y; mFlareData->prepRender( state, &mFlareState ); } // Render instances for Night effects. if ( mNightInterpolant <= 0.0f ) return; // Render instance for Moon sprite. if ( mMoonEnabled && mMoonMatInst ) { mMatrixSet->setSceneView(GFX->getWorldMatrix()); mMatrixSet->setSceneProjection(GFX->getProjectionMatrix()); mMatrixSet->setWorld(GFX->getWorldMatrix()); ObjectRenderInst *ri = renderPass->allocInst<ObjectRenderInst>(); ri->renderDelegate.bind( this, &ScatterSky::_renderMoon ); ri->type = RenderPassManager::RIT_Sky; // Render after sky objects and before CloudLayer! ri->defaultKey = 5; ri->defaultKey2 = 0; renderPass->addInst(ri); } }
void ProjectedShadow::_renderToTexture( F32 camDist, const TSRenderState &rdata ) { PROFILE_SCOPE( ProjectedShadow_RenderToTexture ); GFXDEBUGEVENT_SCOPE( ProjectedShadow_RenderToTexture, ColorI( 255, 0, 0 ) ); RenderPassManager *renderPass = _getRenderPass(); if ( !renderPass ) return; GFXTransformSaver saver; // NOTE: GFXTransformSaver does not save/restore the frustum // so we must save it here before we modify it. F32 l, r, b, t, n, f; bool ortho; GFX->getFrustum( &l, &r, &b, &t, &n, &f, &ortho ); // Set the orthographic projection // matrix up, to be based on the radius // generated based on our shape. GFX->setOrtho( -mRadius, mRadius, -mRadius, mRadius, 0.001f, (mRadius * 2) * smDepthAdjust, true ); // Set the world to light space // matrix set up in shouldRender(). GFX->setWorldMatrix( mWorldToLight ); // Get the shapebase datablock if we have one. ShapeBaseData *data = NULL; if ( mShapeBase ) data = static_cast<ShapeBaseData*>( mShapeBase->getDataBlock() ); // Init or update the shadow texture size. if ( mShadowTexture.isNull() || ( data && data->shadowSize != mShadowTexture.getWidth() ) ) { U32 texSize = getNextPow2( data ? data->shadowSize : 256 * LightShadowMap::smShadowTexScalar ); mShadowTexture.set( texSize, texSize, GFXFormatR8G8B8A8, &PostFxTargetProfile, "BLShadow" ); } GFX->pushActiveRenderTarget(); if ( !mRenderTarget ) mRenderTarget = GFX->allocRenderToTextureTarget(); mRenderTarget->attachTexture( GFXTextureTarget::DepthStencil, _getDepthTarget( mShadowTexture->getWidth(), mShadowTexture->getHeight() ) ); mRenderTarget->attachTexture( GFXTextureTarget::Color0, mShadowTexture ); GFX->setActiveRenderTarget( mRenderTarget ); GFX->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, ColorI( 0, 0, 0, 0 ), 1.0f, 0 ); const SceneRenderState *diffuseState = rdata.getSceneState(); SceneManager *sceneManager = diffuseState->getSceneManager(); SceneRenderState baseState ( sceneManager, SPT_Shadow, SceneCameraState::fromGFXWithViewport( diffuseState->getViewport() ), renderPass ); baseState.getMaterialDelegate().bind( &ProjectedShadow::_getShadowMaterial ); baseState.setDiffuseCameraTransform( diffuseState->getCameraTransform() ); baseState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() ); baseState.getCullingState().disableZoneCulling( true ); mParentObject->prepRenderImage( &baseState ); renderPass->renderPass( &baseState ); // Delete the SceneRenderState we allocated. mRenderTarget->resolve(); GFX->popActiveRenderTarget(); // If we're close enough then filter the shadow. if ( camDist < BasicLightManager::getShadowFilterDistance() ) { if ( !smShadowFilter ) { PostEffect *filter = NULL; if ( !Sim::findObject( "BL_ShadowFilterPostFx", filter ) ) Con::errorf( "ProjectedShadow::_renderToTexture() - 'BL_ShadowFilterPostFx' not found!" ); smShadowFilter = filter; } if ( smShadowFilter ) smShadowFilter->process( NULL, mShadowTexture ); } // Restore frustum if (!ortho) GFX->setFrustum(l, r, b, t, n, f); else GFX->setOrtho(l, r, b, t, n, f); // Set the last render time. mLastRenderTime = Platform::getVirtualMilliseconds(); // HACK: Will remove in future release! mDecalInstance->mCustomTex = &mShadowTexture; }
bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareState *flareState, U32 *outVisDelta, F32 *outOcclusionFade, Point3F *outLightPosSS) { // Reflections use the results from the last forward // render so we don't need multiple queries. if ( state->isReflectPass() ) { *outOcclusionFade = flareState->occlusion; *outVisDelta = Sim::getCurrentTime() - flareState->visChangedTime; return flareState->visible; } // Initialize it to something first. *outOcclusionFade = 0; // First check to see if the flare point // is on scren at all... if not then return // the last result. const Point3F &lightPos = flareState->lightMat.getPosition(); const RectI &viewport = GFX->getViewport(); MatrixF projMatrix; state->getCameraFrustum().getProjectionMatrix(&projMatrix); if( state->isReflectPass() ) projMatrix = state->getSceneManager()->getNonClipProjection(); bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), projMatrix ); // It is onscreen, so raycast as a simple occlusion test. const LightInfo *lightInfo = flareState->lightInfo; const bool isVectorLight = lightInfo->getType() == LightInfo::Vector; const bool useOcclusionQuery = isVectorLight ? flareState->worldRadius > 0.0f : mOcclusionRadius > 0.0f; bool needsRaycast = true; // NOTE: if hardware does not support HOQ it will return NULL // and we will retry every time but there is not currently a good place // for one-shot initialization of LightFlareState if ( useOcclusionQuery ) { // Always treat light as onscreen if using HOQ // it will be faded out if offscreen anyway. onScreen = true; needsRaycast = false; // Test the hardware queries for rendered pixels. U32 pixels = 0, fullPixels = 0; GFXOcclusionQuery::OcclusionQueryStatus status; flareState->occlusionQuery.getLastStatus( false, &status, &pixels ); flareState->fullPixelQuery.getLastStatus( false, NULL, &fullPixels ); if ( status == GFXOcclusionQuery::NotOccluded && fullPixels != 0 ) *outOcclusionFade = mClampF( (F32)pixels / (F32)fullPixels, 0.0f, 1.0f ); if( !flareState->occlusionQuery.isWaiting() ) { // Setup the new queries. RenderPassManager *rpm = state->getRenderPass(); OccluderRenderInst *ri = rpm->allocInst<OccluderRenderInst>(); ri->type = RenderPassManager::RIT_Occluder; ri->query = flareState->occlusionQuery.getQuery(); ri->query2 = flareState->fullPixelQuery.getQuery(); ri->isSphere = true; ri->position = lightPos; if ( isVectorLight && flareState->worldRadius > 0.0f ) ri->scale.set( flareState->worldRadius ); else ri->scale.set( mOcclusionRadius ); ri->orientation = rpm->allocUniqueXform( lightInfo->getTransform() ); // Submit the queries. state->getRenderPass()->addInst( ri ); } } const Point3F &camPos = state->getCameraPosition(); if ( needsRaycast ) { // Use a raycast to determine occlusion. GameConnection *conn = GameConnection::getConnectionToServer(); if ( !conn ) return false; const bool fps = conn->isFirstPerson(); GameBase *control = conn->getControlObject(); if ( control && fps ) control->disableCollision(); RayInfo rayInfo; if ( !gClientContainer.castRay( camPos, lightPos, LosMask, &rayInfo ) ) *outOcclusionFade = 1.0f; if ( control && fps ) control->enableCollision(); } // The raycast and hardware occlusion query only calculate if // the flare is on screen... if does not account for being // partially offscreen. // // The code here clips a box against the viewport to // get an approximate percentage of onscreen area. // F32 worldRadius = flareState->worldRadius > 0 ? flareState->worldRadius : mOcclusionRadius; if ( worldRadius > 0.0f ) { F32 dist = ( camPos - lightPos ).len(); F32 pixelRadius = state->projectRadius(dist, worldRadius); RectI visRect( outLightPosSS->x - pixelRadius, outLightPosSS->y - pixelRadius, pixelRadius * 2.0f, pixelRadius * 2.0f ); F32 fullArea = visRect.area(); if ( visRect.intersect( viewport ) ) { F32 visArea = visRect.area(); *outOcclusionFade *= visArea / fullArea; onScreen = true; } else *outOcclusionFade = 0.0f; } const bool lightVisible = onScreen && *outOcclusionFade > 0.0f; // To perform a fade in/out when we gain or lose visibility // we must update/store the visibility state and time. const U32 currentTime = Sim::getCurrentTime(); if ( lightVisible != flareState->visible ) { flareState->visible = lightVisible; flareState->visChangedTime = currentTime; } // Return the visibility delta for time fading. *outVisDelta = currentTime - flareState->visChangedTime; // Store the final occlusion fade so that it can // be used in reflection rendering later. flareState->occlusion = *outOcclusionFade; return lightVisible; }
void GuiObjectView::renderWorld( const RectI& updateRect ) { if( !mModel ) return; GFXTransformSaver _saveTransforms; // Determine the camera position, and store off render state. MatrixF modelview; MatrixF mv; Point3F cp; modelview = GFX->getWorldMatrix(); mv = modelview; mv.inverse(); mv.getColumn( 3, &cp ); RenderPassManager* renderPass = gClientSceneGraph->getDefaultRenderPass(); S32 time = Platform::getVirtualMilliseconds(); S32 dt = time - mLastRenderTime; mLastRenderTime = time; LIGHTMGR->unregisterAllLights(); LIGHTMGR->setSpecialLight( LightManager::slSunLightType, mLight ); GFX->setStateBlock( mDefaultGuiSB ); F32 left, right, top, bottom, nearPlane, farPlane; bool isOrtho; GFX->getFrustum( &left, &right, &bottom, &top, &nearPlane, &farPlane, &isOrtho ); Frustum frust( false, left, right, top, bottom, nearPlane, farPlane, MatrixF::Identity ); SceneRenderState state ( gClientSceneGraph, SPT_Diffuse, SceneCameraState( GFX->getViewport(), frust, GFX->getWorldMatrix(), GFX->getProjectionMatrix() ), renderPass, false ); // Set up our TS render state here. TSRenderState rdata; rdata.setSceneState( &state ); // We might have some forward lit materials // so pass down a query to gather lights. LightQuery query; query.init( SphereF( Point3F::Zero, 1.0f ) ); rdata.setLightQuery( &query ); // Render primary model. if( mModel ) { if( mRunThread ) { mModel->advanceTime( dt / 1000.f, mRunThread ); mModel->animate(); } mModel->render( rdata ); } // Render mounted model. if( mMountedModel && mMountNode != -1 ) { GFX->pushWorldMatrix(); GFX->multWorld( mModel->mNodeTransforms[ mMountNode ] ); GFX->multWorld( mMountTransform ); mMountedModel->render( rdata ); GFX->popWorldMatrix(); } renderPass->renderPass( &state ); // Make sure to remove our fake sun. LIGHTMGR->unregisterAllLights(); }
void GuiMaterialPreview::renderWorld(const RectI &updateRect) { // nothing to render, punt if ( !mModel && !mMountedModel ) return; S32 time = Platform::getVirtualMilliseconds(); //S32 dt = time - lastRenderTime; lastRenderTime = time; F32 left, right, top, bottom, nearPlane, farPlane; bool isOrtho; GFX->getFrustum( &left, &right, &bottom, &top, &nearPlane, &farPlane, &isOrtho); Frustum frust( isOrtho, left, right, bottom, top, nearPlane, farPlane, MatrixF::Identity ); FogData savedFogData = gClientSceneGraph->getFogData(); gClientSceneGraph->setFogData( FogData() ); // no fog in preview window RenderPassManager* renderPass = gClientSceneGraph->getDefaultRenderPass(); SceneRenderState state ( gClientSceneGraph, SPT_Diffuse, SceneCameraState( GFX->getViewport(), frust, GFX->getWorldMatrix(), GFX->getProjectionMatrix() ), renderPass, true ); // Set up our TS render state here. TSRenderState rdata; rdata.setSceneState( &state ); // We might have some forward lit materials // so pass down a query to gather lights. LightQuery query; query.init( SphereF( Point3F::Zero, 1.0f ) ); rdata.setLightQuery( &query ); // Set up pass transforms renderPass->assignSharedXform(RenderPassManager::View, MatrixF::Identity); renderPass->assignSharedXform(RenderPassManager::Projection, GFX->getProjectionMatrix()); LIGHTMGR->unregisterAllLights(); LIGHTMGR->setSpecialLight( LightManager::slSunLightType, mFakeSun ); if ( mModel ) mModel->render( rdata ); if ( mMountedModel ) { // render a weapon /* MatrixF mat; GFX->pushWorldMatrix(); GFX->multWorld( mat ); GFX->popWorldMatrix(); */ } renderPass->renderPass( &state ); gClientSceneGraph->setFogData( savedFogData ); // restore fog setting // Make sure to remove our fake sun LIGHTMGR->unregisterAllLights(); }
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 ); }
void TerrainBlock::_renderBlock( SceneRenderState *state ) { PROFILE_SCOPE( TerrainBlock_RenderBlock ); // Prevent rendering shadows if feature is disabled if ( !mCastShadows && state->isShadowPass() ) return; MatrixF worldViewXfm = state->getWorldViewMatrix(); worldViewXfm.mul( getRenderTransform() ); MatrixF worldViewProjXfm = state->getProjectionMatrix(); worldViewProjXfm.mul( worldViewXfm ); const MatrixF &objectXfm = getRenderWorldTransform(); Point3F objCamPos = state->getDiffuseCameraPosition(); objectXfm.mulP( objCamPos ); // Get the shadow material. if ( !mDefaultMatInst ) mDefaultMatInst = TerrainCellMaterial::getShadowMat(); // Make sure we have a base material. if ( !mBaseMaterial ) { mBaseMaterial = new TerrainCellMaterial(); mBaseMaterial->init( this, 0, false, false, true ); } // Did the detail layers change? if ( mDetailsDirty ) { _updateMaterials(); mDetailsDirty = false; } // If the layer texture has been cleared or is // dirty then update it. if ( mLayerTex.isNull() || mLayerTexDirty ) _updateLayerTexture(); // If the layer texture is dirty or we lost the base // texture then regenerate it. if ( mLayerTexDirty || mBaseTex.isNull() ) { _updateBaseTexture( false ); mLayerTexDirty = false; } static Vector<TerrCell*> renderCells; renderCells.clear(); mCell->cullCells( state, objCamPos, &renderCells ); RenderPassManager *renderPass = state->getRenderPass(); MatrixF *riObjectToWorldXfm = renderPass->allocUniqueXform( getRenderTransform() ); const bool isColorDrawPass = state->isDiffusePass() || state->isReflectPass(); // This is here for shadows mostly... it allows the // proper shadow material to be generated. BaseMatInstance *defaultMatInst = state->getOverrideMaterial( mDefaultMatInst ); // Only pass and use the light manager if this is not a shadow pass. LightManager *lm = NULL; if ( isColorDrawPass ) lm = LIGHTMGR; for ( U32 i=0; i < renderCells.size(); i++ ) { TerrCell *cell = renderCells[i]; // Ok this cell is fit to render. TerrainRenderInst *inst = renderPass->allocInst<TerrainRenderInst>(); // Setup lights for this cell. if ( lm ) { SphereF bounds = cell->getSphereBounds(); getRenderTransform().mulP( bounds.center ); LightQuery query; query.init( bounds ); query.getLights( inst->lights, 8 ); } GFXVertexBufferHandleBase vertBuff; GFXPrimitiveBufferHandle primBuff; cell->getRenderPrimitive( &inst->prim, &vertBuff, &primBuff ); inst->mat = defaultMatInst; inst->vertBuff = vertBuff.getPointer(); if ( primBuff.isValid() ) { // Use the cell's custom primitive buffer inst->primBuff = primBuff.getPointer(); } else { // Use the standard primitive buffer for this cell inst->primBuff = mPrimBuffer.getPointer(); } inst->objectToWorldXfm = riObjectToWorldXfm; // If we're not drawing to the shadow map then we need // to include the normal rendering materials. if ( isColorDrawPass ) { const SphereF &bounds = cell->getSphereBounds(); F32 sqDist = ( bounds.center - objCamPos ).lenSquared(); F32 radiusSq = mSquared( ( mMaxDetailDistance + bounds.radius ) * smDetailScale ); // If this cell is near enough to get detail textures then // use the full detail mapping material. Else we use the // simple base only material. if ( !state->isReflectPass() && sqDist < radiusSq ) inst->cellMat = cell->getMaterial(); else if ( state->isReflectPass() ) inst->cellMat = mBaseMaterial->getReflectMat(); else inst->cellMat = mBaseMaterial; } inst->defaultKey = (U32)cell->getMaterials(); // Submit it for rendering. renderPass->addInst( inst ); } // Trigger the debug rendering. if ( state->isDiffusePass() && !renderCells.empty() && smDebugRender ) { // Store the render cells for later. mDebugCells = renderCells; ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); ri->renderDelegate.bind( this, &TerrainBlock::_renderDebug ); ri->type = RenderPassManager::RIT_Editor; state->getRenderPass()->addInst( ri ); } }
void RenderGlowMgr::render( SceneRenderState *state ) { PROFILE_SCOPE( RenderGlowMgr_Render ); if ( !isGlowEnabled() ) return; const U32 binSize = mElementList.size(); // If this is a non-diffuse pass or we have no objects to // render then tell the effect to skip rendering. if ( !state->isDiffusePass() || binSize == 0 ) { getGlowEffect()->setSkip( true ); return; } GFXDEBUGEVENT_SCOPE( RenderGlowMgr_Render, ColorI::GREEN ); GFXTransformSaver saver; // Respect the current viewport mNamedTarget.setViewport(GFX->getViewport()); // Tell the superclass we're about to render, preserve contents const bool isRenderingToTarget = _onPreRender( state, true ); // Clear all the buffers to black. GFX->clear( GFXClearTarget, ColorI::BLACK, 1.0f, 0); // Restore transforms MatrixSet &matrixSet = getRenderPass()->getMatrixSet(); matrixSet.restoreSceneViewProjection(); // init loop data SceneData sgData; sgData.init( state, SceneData::GlowBin ); for( U32 j=0; j<binSize; ) { RenderInst *_ri = mElementList[j].inst; if(_ri->type == RenderPassManager::RIT_Particle) { // Find the particle render manager (if we don't have it) if(mParticleRenderMgr == NULL) { RenderPassManager *rpm = state->getRenderPass(); for( U32 i = 0; i < rpm->getManagerCount(); i++ ) { RenderBinManager *bin = rpm->getManager(i); if( bin->getRenderInstType() == RenderParticleMgr::RIT_Particles ) { mParticleRenderMgr = reinterpret_cast<RenderParticleMgr *>(bin); break; } } } ParticleRenderInst *ri = static_cast<ParticleRenderInst*>(_ri); GFX->setStateBlock(mParticleRenderMgr->_getHighResStateBlock(ri)); mParticleRenderMgr->_getShaderConsts().mShaderConsts->setSafe(mParticleRenderMgr->_getShaderConsts().mModelViewProjSC, *ri->modelViewProj); mParticleRenderMgr->renderParticle(ri, state); j++; continue; } MeshRenderInst *ri = static_cast<MeshRenderInst*>(_ri); setupSGData( ri, sgData ); BaseMatInstance *mat = ri->matInst; GlowMaterialHook *hook = mat->getHook<GlowMaterialHook>(); if ( !hook ) { hook = new GlowMaterialHook( ri->matInst ); ri->matInst->addHook( hook ); } BaseMatInstance *glowMat = hook->getMatInstance(); U32 matListEnd = j; while( glowMat && glowMat->setupPass( state, sgData ) ) { U32 a; for( a=j; a<binSize; a++ ) { if (mElementList[a].inst->type == RenderPassManager::RIT_Particle) break; MeshRenderInst *passRI = static_cast<MeshRenderInst*>(mElementList[a].inst); if ( newPassNeeded( ri, passRI ) ) break; matrixSet.setWorld(*passRI->objectToWorld); matrixSet.setView(*passRI->worldToCamera); matrixSet.setProjection(*passRI->projection); glowMat->setTransforms(matrixSet, state); glowMat->setSceneInfo(state, sgData); glowMat->setBuffers(passRI->vertBuff, passRI->primBuff); if ( passRI->prim ) GFX->drawPrimitive( *passRI->prim ); else GFX->drawPrimitive( passRI->primBuffIndex ); } matListEnd = a; setupSGData( ri, sgData ); } // force increment if none happened, otherwise go to end of batch j = ( j == matListEnd ) ? j+1 : matListEnd; } // Finish up. if ( isRenderingToTarget ) _onPostRender(); // Make sure the effect is gonna render. getGlowEffect()->setSkip( false ); }
void LightFlareData::prepRender( SceneRenderState *state, LightFlareState *flareState ) { PROFILE_SCOPE( LightFlareData_prepRender ); const LightInfo *lightInfo = flareState->lightInfo; if ( mIsZero( flareState->fullBrightness ) || mIsZero( lightInfo->getBrightness() ) ) return; // Figure out the element count to render. U32 elementCount = mElementCount; const bool isReflectPass = state->isReflectPass(); if ( isReflectPass ) { // Then we don't render anything this pass. if ( !mRenderReflectPass ) return; // Find the zero distance elements which make // up the corona of the light flare. elementCount = 0.0f; for ( U32 i=0; i < mElementCount; i++ ) if ( mIsZero( mElementDist[i] ) ) elementCount++; } // Better have something to render. if ( elementCount == 0 ) return; U32 visDelta = U32_MAX; F32 occlusionFade = 1.0f; Point3F lightPosSS; bool lightVisible = _testVisibility( state, flareState, &visDelta, &occlusionFade, &lightPosSS ); // We can only skip rendering if the light is not // visible, and it has elapsed the fade out time. if ( mIsZero( occlusionFade ) || !lightVisible && visDelta > FadeOutTime ) return; const RectI &viewport = GFX->getViewport(); Point3F oneOverViewportExtent( 1.0f / (F32)viewport.extent.x, 1.0f / (F32)viewport.extent.y, 0.0f ); // Really convert it to screen space. lightPosSS.x -= viewport.point.x; lightPosSS.y -= viewport.point.y; lightPosSS *= oneOverViewportExtent; lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One; lightPosSS.y = -lightPosSS.y; lightPosSS.z = 0.0f; // Take any projection offset into account so that the point where the flare's // elements converge is at the 'eye' point rather than the center of the viewport. const Point2F& projOffset = state->getCameraFrustum().getProjectionOffset(); Point3F flareVec( -lightPosSS + Point3F(projOffset.x, projOffset.y, 0.0f) ); const F32 flareLength = flareVec.len(); if ( flareLength > 0.0f ) flareVec *= 1.0f / flareLength; // Setup the flare quad points. Point3F rotatedBasePoints[4]; dMemcpy(rotatedBasePoints, sBasePoints, sizeof( sBasePoints )); // Rotate the flare quad. F32 rot = mAcos( -1.0f * flareVec.x ); rot *= flareVec.y > 0.0f ? -1.0f : 1.0f; MathUtils::vectorRotateZAxis( rot, rotatedBasePoints, 4 ); // Here we calculate a the light source's influence on // the effect's size and brightness. // Scale based on the current light brightness compared to its normal output. F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness; const Point3F &camPos = state->getCameraPosition(); const Point3F &lightPos = flareState->lightMat.getPosition(); const bool isVectorLight = lightInfo->getType() == LightInfo::Vector; // Scale based on world space distance from camera to light source. F32 distToCamera = ( camPos - lightPos ).len(); F32 lightSourceWSDistanceScale = isVectorLight && distToCamera > 0.0f ? 1.0f : getMin( 10.0f / distToCamera, 10.0f ); // Scale based on screen space distance from screen position of light source to the screen center. F32 lightSourceSSDistanceScale = getMax( ( 1.5f - flareLength ) / 1.5f, 0.0f ); // Scale based on recent visibility changes, fading in or out. F32 fadeInOutScale = 1.0f; if ( lightVisible && visDelta < FadeInTime && flareState->occlusion > 0.0f ) fadeInOutScale = (F32)visDelta / (F32)FadeInTime; else if ( !lightVisible && visDelta < FadeOutTime ) fadeInOutScale = 1.0f - (F32)visDelta / (F32)FadeOutTime; // This combined scale influences the size of all elements this effect renders. // Note we also add in a scale that is user specified in the Light. F32 lightSourceIntensityScale = lightSourceBrightnessScale * lightSourceWSDistanceScale * lightSourceSSDistanceScale * fadeInOutScale * flareState->scale * occlusionFade; if ( mIsZero( lightSourceIntensityScale ) ) return; // The baseColor which modulates the color of all elements. // // These are the factors which affect the "alpha" of the flare effect. // Modulate more in as appropriate. ColorF baseColor = ColorF::WHITE * lightSourceBrightnessScale * occlusionFade; // Setup the vertex buffer for the maximum flare elements. const U32 vertCount = 4 * mElementCount; if ( flareState->vertBuffer.isNull() || flareState->vertBuffer->mNumVerts != vertCount ) flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic ); GFXVertexPCT *vert = flareState->vertBuffer.lock(); const Point2F oneOverTexSize( 1.0f / (F32)mFlareTexture.getWidth(), 1.0f / (F32)mFlareTexture.getHeight() ); for ( U32 i = 0; i < mElementCount; i++ ) { // Skip non-zero elements for reflections. if ( isReflectPass && mElementDist[i] > 0.0f ) continue; Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : sBasePoints; ColorF color( baseColor * mElementTint[i] ); if ( mElementUseLightColor[i] ) color *= lightInfo->getColor(); color.clamp(); Point3F pos( lightPosSS + flareVec * mElementDist[i] * flareLength ); const RectF &rect = mElementRect[i]; Point3F size( rect.extent.x, rect.extent.y, 1.0f ); size *= mElementScale[i] * mScale * lightSourceIntensityScale; AssertFatal( size.x >= 0.0f, "LightFlareData::prepRender - Got a negative element size?" ); if ( size.x < 100.0f ) { F32 alphaScale = mPow( size.x / 100.0f, 2 ); color *= alphaScale; } Point2F texCoordMin, texCoordMax; texCoordMin = rect.point * oneOverTexSize; texCoordMax = ( rect.point + rect.extent ) * oneOverTexSize; size.x = getMax( size.x, 1.0f ); size.y = getMax( size.y, 1.0f ); size *= oneOverViewportExtent; vert->color = color; vert->point = ( basePos[0] * size ) + pos; vert->texCoord.set( texCoordMin.x, texCoordMax.y ); vert++; vert->color = color; vert->point = ( basePos[1] * size ) + pos; vert->texCoord.set( texCoordMax.x, texCoordMax.y ); vert++; vert->color = color; vert->point = ( basePos[2] * size ) + pos; vert->texCoord.set( texCoordMax.x, texCoordMin.y ); vert++; vert->color = color; vert->point = ( basePos[3] * size ) + pos; vert->texCoord.set( texCoordMin.x, texCoordMin.y ); vert++; } flareState->vertBuffer.unlock(); RenderPassManager *rpm = state->getRenderPass(); // Create and submit the render instance. ParticleRenderInst *ri = rpm->allocInst<ParticleRenderInst>(); ri->type = RenderPassManager::RIT_Particle; ri->vertBuff = &flareState->vertBuffer; ri->primBuff = &mFlarePrimBuffer; ri->translucentSort = true; ri->sortDistSq = ( lightPos - camPos ).lenSquared(); ri->modelViewProj = &MatrixF::Identity; ri->bbModelViewProj = &MatrixF::Identity; ri->count = elementCount; ri->blendStyle = ParticleRenderInst::BlendGreyscale; ri->diffuseTex = mFlareTexture; ri->softnessDistance = 1.0f; ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff; // Sort by texture too. // NOTE: Offscreen partical code is currently disabled. ri->systemState = PSS_AwaitingHighResDraw; rpm->addInst( ri ); }
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 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; } }
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 ); } }