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 PxCloth::prepRenderImage( SceneRenderState *state ) { if ( mIsVBDirty ) _updateVBIB(); // Recreate the material if we need to. if ( !mMatInst ) _initMaterial(); // 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; MeshRenderInst *ri = state->getRenderPass()->allocInst<MeshRenderInst>(); // If we need lights then set them up. if ( matInst->isForwardLit() ) { LightQuery query; query.init( getWorldSphere() ); query.getLights( ri->lights, 8 ); } ri->projection = state->getRenderPass()->allocSharedXform(RenderPassManager::Projection); ri->objectToWorld = &MatrixF::Identity; ri->worldToCamera = state->getRenderPass()->allocSharedXform(RenderPassManager::View); ri->type = RenderPassManager::RIT_Mesh; ri->primBuff = &mPrimBuffer; ri->vertBuff = &mVB; ri->matInst = matInst; ri->prim = state->getRenderPass()->allocPrim(); ri->prim->type = GFXTriangleList; ri->prim->minIndex = 0; ri->prim->startIndex = 0; ri->prim->numPrimitives = mNumIndices / 3; ri->prim->startVertex = 0; ri->prim->numVertices = mNumVertices; ri->defaultKey = matInst->getStateHint(); ri->defaultKey2 = (U32)ri->vertBuff; 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 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 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 ProjectedShadow::_updateDecal( const SceneRenderState *state ) { PROFILE_SCOPE( ProjectedShadow_UpdateDecal ); if ( !LIGHTMGR ) return false; // Get the position of the decal first. const Box3F &objBox = mParentObject->getObjBox(); const Point3F boxCenter = objBox.getCenter(); Point3F decalPos = boxCenter; const MatrixF &renderTransform = mParentObject->getRenderTransform(); { // Set up the decal position. // We use the object space box center // multiplied by the render transform // of the object to ensure we benefit // from interpolation. MatrixF t( renderTransform ); t.setColumn(2,Point3F::UnitZ); t.mulP( decalPos ); } if ( mDecalInstance ) { mDecalInstance->mPosition = decalPos; if ( !shouldRender( state ) ) return false; } // Get the sunlight for the shadow projection. // We want the LightManager to return NULL if it can't // get the "real" sun, so we specify false for the useDefault parameter. LightInfo *lights[4] = {0}; LightQuery query; query.init( mParentObject->getWorldSphere() ); query.getLights( lights, 4 ); Point3F pos = renderTransform.getPosition(); Point3F lightDir( 0, 0, 0 ); Point3F tmp( 0, 0, 0 ); F32 weight = 0; F32 range = 0; U32 lightCount = 0; F32 dist = 0; F32 fade = 0; for ( U32 i = 0; i < 4; i++ ) { // If we got a NULL light, // we're at the end of the list. if ( !lights[i] ) break; if ( !lights[i]->getCastShadows() ) continue; if ( lights[i]->getType() != LightInfo::Point ) tmp = lights[i]->getDirection(); else tmp = pos - lights[i]->getPosition(); range = lights[i]->getRange().x; dist = ( (tmp.lenSquared()) / ((range * range) * 0.5f)); weight = mClampF( 1.0f - ( tmp.lenSquared() / (range * range)), 0.00001f, 1.0f ); if ( lights[i]->getType() == LightInfo::Vector ) fade = getMax( fade, 1.0f ); else fade = getMax( fade, mClampF( 1.0f - dist, 0.00001f, 1.0f ) ); lightDir += tmp * weight; lightCount++; } lightDir.normalize(); // No light... no shadow. if ( !lights[0] ) return false; // Has the light direction // changed since last update? bool lightDirChanged = !mLastLightDir.equal( lightDir ); // Has the parent object moved // or scaled since the last update? bool hasMoved = !mLastObjectPosition.equal( mParentObject->getRenderPosition() ); bool hasScaled = !mLastObjectScale.equal( mParentObject->getScale() ); // Set the last light direction // to the current light direction. mLastLightDir = lightDir; mLastObjectPosition = mParentObject->getRenderPosition(); mLastObjectScale = mParentObject->getScale(); // Temps used to generate // tangent vector for DecalInstance below. VectorF right( 0, 0, 0 ); VectorF fwd( 0, 0, 0 ); VectorF tmpFwd( 0, 0, 0 ); U32 idx = lightDir.getLeastComponentIndex(); tmpFwd[idx] = 1.0f; right = mCross( tmpFwd, lightDir ); fwd = mCross( lightDir, right ); right = mCross( fwd, lightDir ); right.normalize(); // Set up the world to light space // matrix, along with proper position // and rotation to be used as the world // matrix for the render to texture later on. static MatrixF sRotMat(EulerF( 0.0f, -(M_PI_F/2.0f), 0.0f)); mWorldToLight.identity(); MathUtils::getMatrixFromForwardVector( lightDir, &mWorldToLight ); mWorldToLight.setPosition( ( pos + boxCenter ) - ( ( (mRadius * smDepthAdjust) + 0.001f ) * lightDir ) ); mWorldToLight.mul( sRotMat ); mWorldToLight.inverse(); // Get the shapebase datablock if we have one. ShapeBaseData *data = NULL; if ( mShapeBase ) data = static_cast<ShapeBaseData*>( mShapeBase->getDataBlock() ); // We use the object box's extents multiplied // by the object's scale divided by 2 for the radius // because the object's worldsphere radius is not // rotationally invariant. mRadius = (objBox.getExtents() * mParentObject->getScale()).len() * 0.5f; if ( data ) mRadius *= data->shadowSphereAdjust; // Create the decal if we don't have one yet. if ( !mDecalInstance ) mDecalInstance = gDecalManager->addDecal( decalPos, lightDir, right, mDecalData, 1.0f, 0, PermanentDecal | ClipDecal | CustomDecal ); if ( !mDecalInstance ) return false; mDecalInstance->mVisibility = fade; // Setup decal parameters. mDecalInstance->mSize = mRadius * 2.0f; mDecalInstance->mNormal = -lightDir; mDecalInstance->mTangent = -right; mDecalInstance->mRotAroundNormal = 0; mDecalInstance->mPosition = decalPos; mDecalInstance->mDataBlock = mDecalData; // If the position of the world // space box center is the same // as the decal's position, and // the light direction has not // changed, we don't need to clip. bool shouldClip = lightDirChanged || hasMoved || hasScaled; // Now, check and see if the object is visible. const Frustum &frust = state->getCullingFrustum(); if ( frust.isCulled( SphereF( mDecalInstance->mPosition, mDecalInstance->mSize * mDecalInstance->mSize ) ) && !shouldClip ) return false; F32 shadowLen = 10.0f; if ( data ) shadowLen = data->shadowProjectionDistance; const Point3F &boxExtents = objBox.getExtents(); mShadowLength = shadowLen * mParentObject->getScale().z; // Set up clip depth, and box half // offset for decal clipping. Point2F clipParams( mShadowLength, (boxExtents.x + boxExtents.y) * 0.25f ); bool render = false; bool clipSucceeded = true; // Clip! if ( shouldClip ) { clipSucceeded = gDecalManager->clipDecal( mDecalInstance, NULL, &clipParams ); } // If the clip failed, // we'll return false in // order to keep from // unnecessarily rendering // into the texture. If // there was no reason to clip // on this update, we'll assume we // should update the texture. render = clipSucceeded; // Tell the DecalManager we've changed this decal. gDecalManager->notifyDecalModified( mDecalInstance ); return render; }