void RenderGlowMgr::addElement( RenderInst *inst ) { // Skip out if we don't have the glow post // effect enabled at this time. if ( !isGlowEnabled() ) return; // TODO: We need to get the scene state here in a more reliable // manner so we can skip glow in a non-diffuse render pass. //if ( !mParentManager->getSceneManager()->getSceneState()->isDiffusePass() ) //return RenderBinManager::arSkipped; ParticleRenderInst *particleInst = NULL; if(inst->type == RenderPassManager::RIT_Particle) particleInst = static_cast<ParticleRenderInst*>(inst); if(particleInst && particleInst->glow) { internalAddElement(inst); return; } // Skip it if we don't have a glowing material. BaseMatInstance *matInst = getMaterial( inst ); if ( !matInst || !matInst->hasGlow() ) return; internalAddElement(inst); }
void TSForestCellBatch::_render( const SceneRenderState *state ) { if ( !mVB.isValid() || ( state->isShadowPass() && !TSLastDetail::smCanShadow ) ) return; // Make sure we have a material to render with. BaseMatInstance *mat = state->getOverrideMaterial( mDetail->getMatInstance() ); if ( mat == NULL ) return; // We don't really render here... we submit it to // the render manager which collects all the batches // in the scene, sorts them by texture, sets up the // shader, and then renders them all at once. ImposterBatchRenderInst *inst = state->getRenderPass()->allocInst<ImposterBatchRenderInst>(); inst->mat = mat; inst->vertBuff = &mVB; // We sort by the imposter type first so that RIT_Imposter and // RIT_ImposterBatches do not get mixed together. // // We then sort by material. // inst->defaultKey = 0; inst->defaultKey2 = mat->getStateHint(); state->getRenderPass()->addInst( inst ); }
BaseMatInstance* InstancingMaterialHook::getInstancingMat( BaseMatInstance *matInst ) { PROFILE_SCOPE( InstancingMaterialHook_GetInstancingMat ); if ( matInst == NULL ) return NULL; InstancingMaterialHook *hook = matInst->getHook<InstancingMaterialHook>(); if ( hook == NULL ) { hook = new InstancingMaterialHook(); matInst->addHook( hook ); BaseMatInstance *instMat = matInst->getMaterial()->createMatInstance(); FeatureSet features( matInst->getRequestedFeatures() ); features.addFeature( MFT_UseInstancing ); if ( !instMat->init( features, matInst->getVertexFormat() ) ) SAFE_DELETE( instMat ); hook->mMatInst = instMat; } return hook->mMatInst; }
BaseMatInstance * MaterialManager::createMeshDebugMatInstance(const ColorF &meshColor) { String meshDebugStr = String::ToString( "Torque_MeshDebug_%d", meshColor.getRGBAPack() ); Material *debugMat; if (!Sim::findObject(meshDebugStr,debugMat)) { debugMat = allocateAndRegister( meshDebugStr ); debugMat->mDiffuse[0] = meshColor; debugMat->mEmissive[0] = true; } BaseMatInstance *debugMatInstance = NULL; if( debugMat != NULL ) { debugMatInstance = debugMat->createMatInstance(); GFXStateBlockDesc desc; desc.setCullMode(GFXCullNone); desc.fillMode = GFXFillWireframe; debugMatInstance->addStateBlockDesc(desc); // Disable fog and other stuff. FeatureSet debugFeatures; debugFeatures.addFeature( MFT_DiffuseColor ); debugMatInstance->init( debugFeatures, getGFXVertexFormat<GFXVertexPCN>() ); } return debugMatInstance; }
void ImposterCaptureMaterialHook::init( BaseMatInstance *inMat ) { // We cannot capture impostors on custom materials // as we don't know how to get just diffuse and just // normals rendering. if ( dynamic_cast<CustomMaterial*>( inMat->getMaterial() ) ) return; // Tweak the feature data to include just what we need. FeatureSet features; features.addFeature( MFT_VertTransform ); features.addFeature( MFT_DiffuseMap ); features.addFeature( MFT_OverlayMap ); features.addFeature( MFT_DetailMap ); features.addFeature( MFT_DiffuseColor ); features.addFeature( MFT_AlphaTest ); features.addFeature( MFT_IsTranslucent ); const String &matName = inMat->getMaterial()->getName(); mDiffuseMatInst = MATMGR->createMatInstance( matName ); mDiffuseMatInst->getFeaturesDelegate().bind( &ImposterCaptureMaterialHook::_overrideFeatures ); mDiffuseMatInst->init( features, inMat->getVertexFormat() ); features.addFeature( MFT_IsDXTnm ); features.addFeature( MFT_NormalMap ); features.addFeature( MFT_NormalsOut ); mNormalsMatInst = MATMGR->createMatInstance( matName ); mNormalsMatInst->getFeaturesDelegate().bind( &ImposterCaptureMaterialHook::_overrideFeatures ); mNormalsMatInst->init( features, inMat->getVertexFormat() ); }
void RenderTranslucentMgr::addElement( RenderInst *inst ) { // Right off the bat if its not translucent skip it. if ( !inst->translucentSort ) return; // What type of instance is this. const bool isMeshInst = inst->type == RenderPassManager::RIT_Translucent; // Get its material if its a mesh. BaseMatInstance* matInst = NULL; if ( isMeshInst ) matInst = static_cast<MeshRenderInst*>( inst )->matInst; // If the material isn't translucent the skip it. if ( matInst && !matInst->getMaterial()->isTranslucent() ) return; // We made it this far, add the instance. mElementList.increment(); MainSortElem& elem = mElementList.last(); elem.inst = inst; // Override the instances default key to be the sort distance. All // the pointer dereferencing is in there to prevent us from losing // information when converting to a U32. elem.key = *((U32*)&inst->sortDistSq); AssertFatal( inst->defaultKey != 0, "RenderTranslucentMgr::addElement() - Got null sort key... did you forget to set it?" ); // Then use the instances primary key as our secondary key elem.key2 = inst->defaultKey; }
// Returns true is the shape contains any materials with accumulation enabled. bool TSShapeInstance::hasAccumulation() { bool result = false; for ( U32 i = 0; i < mMaterialList->size(); ++i ) { BaseMatInstance* mat = mMaterialList->getMaterialInst(i); if ( mat->hasAccumulation() ) result = true; } return result; }
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 ); }
BaseMatInstance* MaterialManager::createMatInstance( const String &matName, const FeatureSet& features, const GFXVertexFormat *vertexFormat ) { BaseMatInstance* mat = createMatInstance(matName); if (mat) { mat->init( features, vertexFormat ); return mat; } return NULL; }
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 AtlasClipMapBatcher::renderClipMap( SceneGraphData& sgData, BaseMatInstance* overrideMat ) { PROFILE_START(AtlasClipMapBatcher_renderClipMap); for(S32 curBin=1; curBin<4; curBin++) { // If bin is empty, skip. if(mRenderList[curBin].size() == 0) continue; for(S32 i=0; i<mRenderList[curBin].size(); i++) { // Grab the render note. const RenderNote *rn = mRenderList[curBin][i]; // Set up clipmap levels. if( !mFixedFunction ) { BaseMatInstance* material = overrideMat; if( !material ) switch( rn->levelCount ) { case 2: material = mClipMap->getMaterialAndTextures( rn->levelEnd, rn->levelStart, -1, -1, false ); break; case 3: material = mClipMap->getMaterialAndTextures( rn->levelEnd, rn->levelStart + 1, rn->levelStart, -1, false ); break; case 4: material = mClipMap->getMaterialAndTextures( rn->levelEnd, rn->levelStart + 2, rn->levelStart + 1, rn->levelStart, false ); break; default: material = MaterialManager::get()->getWarningMatInstance(); } while( material->setupPass( mState, sgData ) ) rn->chunk->render(); } else { Point4F clipmapMapping; for( U32 curLayer = rn->levelEnd; curLayer >= rn->levelStart; -- curLayer ) { BaseMatInstance* material = overrideMat; if( !material ) material = mClipMap->bindTexturesFF( curLayer, clipmapMapping, curLayer == rn->levelEnd, false ); while( material->setupPass( mState, sgData ) ) rn->chunk->render(); } } } } PROFILE_END(); }
BaseMatInstance* TerrainCellMaterial::getShadowMat() { // Find our material which has some settings // defined on it in script. Material *mat = MATMGR->getMaterialDefinitionByName( "AL_DefaultShadowMaterial" ); // Create the material instance adding the feature which // handles rendering terrain cut outs. FeatureSet features = MATMGR->getDefaultFeatures(); BaseMatInstance *matInst = mat->createMatInstance(); if ( !matInst->init( features, getGFXVertexFormat<TerrVertex>() ) ) { delete matInst; matInst = NULL; } return matInst; }
bool WaterObject::initMaterial( S32 idx ) { // We must return false for any case which it is NOT safe for the caller // to use the indexed material. if ( idx < 0 || idx > NumMatTypes ) return false; BaseMatInstance *mat = mMatInstances[idx]; WaterMatParams &matParams = mMatParamHandles[idx]; // Is it already initialized? if ( mat && mat->isValid() ) return true; // Do we need to allocate anything? if ( mSurfMatName[idx].isNotEmpty() ) { if ( mat ) SAFE_DELETE( mat ); CustomMaterial *custMat; if ( Sim::findObject( mSurfMatName[idx], custMat ) && custMat->mShaderData ) mat = custMat->createMatInstance(); else mat = MATMGR->createMatInstance( mSurfMatName[idx] ); const GFXVertexFormat *flags = getGFXVertexFormat<GFXVertexPC>(); if ( mat && mat->init( MATMGR->getDefaultFeatures(), flags ) ) { mMatInstances[idx] = mat; matParams.init( mat ); return true; } SAFE_DELETE( mat ); } return false; }
BaseMatInstance * MaterialManager::createWarningMatInstance() { Material *warnMat = static_cast<Material*>(Sim::findObject("WarningMaterial")); BaseMatInstance *warnMatInstance = NULL; if( warnMat != NULL ) { warnMatInstance = warnMat->createMatInstance(); GFXStateBlockDesc desc; desc.setCullMode(GFXCullNone); warnMatInstance->addStateBlockDesc(desc); warnMatInstance->init( getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTTB>() ); } return warnMatInstance; }
void MaterialManager::dumpMaterialInstances( BaseMaterialDefinition *target ) const { if ( !mMatInstanceList.size() ) return; if ( target ) Con::printf( "--------------------- %s MatInstances ---------------------", target->getName() ); else Con::printf( "--------------------- MatInstances %d ---------------------", mMatInstanceList.size() ); for( U32 i=0; i<mMatInstanceList.size(); i++ ) { BaseMatInstance *inst = mMatInstanceList[i]; if ( target && inst->getMaterial() != target ) continue; inst->dumpShaderInfo(); Con::printf( "" ); } Con::printf( "---------------------- Dump complete ----------------------"); }
void MaterialList::initMatInstances( const FeatureSet &features, const GFXVertexFormat *vertexFormat ) { for( U32 i=0; i < mMatInstList.size(); i++ ) { BaseMatInstance *matInst = mMatInstList[i]; if ( !matInst ) continue; if ( !matInst->init( features, vertexFormat ) ) { Con::errorf( "MaterialList::initMatInstances - failed to initialize material instance for '%s'", matInst->getMaterial()->getName() ); // Fall back to warning material. SAFE_DELETE( matInst ); matInst = MATMGR->createMatInstance( "WarningMaterial" ); matInst->init( MATMGR->getDefaultFeatures(), vertexFormat ); mMatInstList[ i ] = matInst; } } }
BaseMatInstance* ClipMap::getMaterialAndTextures( U32 level1, U32 level2, U32 level3/*=-1*/, U32 level4/*=-1*/, bool doTerrainRenderHack ) { // Figure out how many layers we have. U32 levelCount = 2; if(level3 != -1) levelCount++; if(level4 != -1) levelCount++; GRAPHIC->clearSamplerOverrides(); mMapInfoConst.setSize(levelCount); // Set up constants, bind textures. for(S32 i=0; i<levelCount; i++) { U32 curLevel = -1; switch(i) { case 0: curLevel = level1; break; case 1: curLevel = level2; break; case 2: curLevel = level3; break; case 3: curLevel = level4; break; } AssertFatal(curLevel != -1, "ClipMap::bindShaderAndTextures - tried to draw an unspecified layer!"); AssertFatal(curLevel < mLevels.size(), "ClipMap::bindShaderAndTextures - out of range level specified!"); // Grab references to relevant data. Point4F &pt = mMapInfoConst[i]; ClipMap::ClipStackEntry &cse = mLevels[curLevel]; // Bind debug or real textures, depending on flag. if(smDebugTextures) GRAPHIC->setTexture(i, cse.mDebugTex); else GRAPHIC->setTexture(i, cse.mTex); // Note the offset and center for this level as well. pt.x = cse.mClipCenter.x * cse.mScale; pt.y = cse.mClipCenter.y * cse.mScale; pt.z = cse.mScale; pt.w = 0.f; if (doTerrainRenderHack && TerrainRender::mCurrentBlock && !TerrainRender::mCurrentBlock->isTiling()) { // At scale 1.0 we can clamp the UV edges avoiding edge bleed between terrain blocks if (cse.mScale == 1.0f) { GRAPHIC->setSamplerAddressModeOverride(i, true, GAddressClamp); } // Ideally, we want to clamp at scale 2.0 as well. // however, we can't clamp as the shader is scaling the UV coords // edge bleed is caused by mipmaps wrapping, so let's bias the mipmap selection // out a little bit, this is only necessary for level 2 of the clip map if (cse.mScale == 2.0f) { GRAPHIC->setSamplerMipLODBiasOverride(i, true, -1.0f); } else { GRAPHIC->setSamplerMipLODBiasOverride(i, true, 0.0f); } } } S32 idx = levelCount - 1; BaseMatInstance* ret = mClipmapMat[idx]; MaterialParameters* params = ret->getMaterialParameters(); // We do not use the morph target in the shader, but // we also cannot assume it will be cleared for us. params->set(mMorphTSC[idx], 0.0f); // Set all the constants in one go. params->set(mMapInfoTC[idx], mMapInfoConst); params->set(mDiffuseMap0TC[idx], (S32)0); params->set(mDiffuseMap1TC[idx], (S32)1); params->set(mDiffuseMap2TC[idx], (S32)2); params->set(mDiffuseMap3TC[idx], (S32)3); GRAPHIC->updateStates(true); // Ok - all bound! return ret; }
void ClipMap::initClipStack() { PROFILE_START(ClipMap_initClipStack); // Clear out all the levels. while(mLevels.size()) { mLevels.last().mDebugTex = NULL; mLevels.last().mTex = NULL; mLevels.pop_back(); } // What texture profile are we going to be using? AssertFatal(mImageCache, "ClipMap::initClipStack - must have image cache by this point."); GTextureProfile *texProfile = mImageCache->isRenderToTargetCache() ? &ClipMapTextureRTProfile : &ClipMapTextureProfile; // Figure out how many clipstack textures we'll have. mClipStackDepth = getBinLog2(mTextureSize) - getBinLog2(mClipMapSize) + 1; mLevels.setSize(mClipStackDepth); // Print a little report on our allocation. Con::printf("Allocating a %d px clipmap for a %dpx source texture.", mClipMapSize, mTextureSize); Con::printf(" - %d base clipstack entries, + 1 cap.", mClipStackDepth - 1); U32 baseTexSize = (mClipMapSize * mClipMapSize * 4); Con::printf(" - Using approximately %fMB of texture memory.", (F32(baseTexSize * mClipStackDepth) * 1.33) / (1024.0*1024.0)); // First do our base textures - they are not mipped. // We rely on auto-mipmapping, but if the device/card doesn't support it, we should just not ask for it. U32 numMips = GRAPHIC->getCardProfiler()->queryProfile("autoMipMapLevel", true) ? 0 : 1; for(S32 i=0; i<mClipStackDepth; i++) { mLevels[i].mScale = (F32)BIT(mClipStackDepth - (1 + i)); mLevels[i].mTex.set(mClipMapSize, mClipMapSize, GFormatR8G8B8X8, texProfile, avar("%s() - mLevels[%d].mTex (line %d)", __FUNCTION__, i, __LINE__), numMips); } // Some stuff can get skipped once we're set up. if(mTexCallbackHandle != -1) return; // Don't forget to allocate our debug textures... for(S32 i=0; i<mClipStackDepth; i++) mLevels[i].initDebugTexture(i); GAtlasVert2* vert = NULL; if (GRAPHIC->getPixelShaderVersion() > 0) { // Do shader lookup for 2,3,4 level shaders. for(S32 i=2; i<5; i++) { // Init materials const String matname = String::ToString("AtlasMaterial%d", i); const U32 arrayOffset = i-1; mClipmapMat[arrayOffset] = MaterialManager::get()->createMatInstance(matname, (GVertexFlags)getGVertFlags(vert)); if (!mClipmapMat[arrayOffset]) { Con::errorf("Could not find material: %s", matname.c_str()); continue; } else { if (mMapInfoConst.getElementSize() == 0) mMapInfoConst.setCapacity(4, mClipmapMat[arrayOffset]->getMaterialParameters()->getAlignmentValue(GSCT_Float4)); } BaseMatInstance* matParams = mClipmapMat[arrayOffset]; mMorphTSC[arrayOffset] = matParams->getMaterialParameterHandle("$morphT"); mMapInfoTC[arrayOffset] = matParams->getMaterialParameterHandle("$mapInfo"); mDiffuseMap0TC[arrayOffset] = matParams->getMaterialParameterHandle("$diffuseMap0"); mDiffuseMap1TC[arrayOffset] = matParams->getMaterialParameterHandle("$diffuseMap1"); mDiffuseMap2TC[arrayOffset] = matParams->getMaterialParameterHandle("$diffuseMap2"); mDiffuseMap3TC[arrayOffset] = matParams->getMaterialParameterHandle("$diffuseMap3"); } } else { mClipmapMatBasePassFF = MaterialManager::get()->createMatInstance("AtlasMaterialFFBasePass", (GVertexFlags)getGVertFlags(vert)); mClipmapMatAddPassFF = MaterialManager::get()->createMatInstance("AtlasMaterialFFAddPass", (GVertexFlags)getGVertFlags(vert)); } // Grab a callback from the texture manager to deal with zombification. GRAPHIC->getTextureManager()->registerTexCallback(texCB, this, mTexCallbackHandle); // Ok, everything is ready to go. PROFILE_END(); }
void ShadowMaterialHook::init( BaseMatInstance *inMat ) { if( !inMat->isValid() ) return; // Tweak the feature data to include just what we need. FeatureSet features; features.addFeature( MFT_VertTransform ); features.addFeature( MFT_DiffuseMap ); features.addFeature( MFT_TexAnim ); features.addFeature( MFT_AlphaTest ); features.addFeature( MFT_Visibility ); // Actually we want to include features from the inMat // if they operate on the preTransform verts so things // like wind/deformation effects will also affect the shadow. const FeatureSet &inFeatures = inMat->getFeatures(); for ( U32 i = 0; i < inFeatures.getCount(); i++ ) { const FeatureType& ft = inFeatures.getAt(i); if ( ft.getGroup() == MFG_PreTransform ) features.addFeature( ft ); } // Do instancing in shadows if we can. if ( inFeatures.hasFeature( MFT_UseInstancing ) ) features.addFeature( MFT_UseInstancing ); Material *shadowMat = (Material*)inMat->getMaterial(); if ( dynamic_cast<CustomMaterial*>( shadowMat ) ) { // This is a custom material... who knows what it really does, but // if it wasn't already filtered out of the shadow render then just // give it some default depth out material. shadowMat = MATMGR->getMaterialDefinitionByName( "AL_DefaultShadowMaterial" ); } // By default we want to disable some states // that the material might enable for us. GFXStateBlockDesc forced; forced.setBlend( false ); forced.setAlphaTest( false ); // We should force on zwrite as the prepass // will disable it by default. forced.setZReadWrite( true, true ); // TODO: Should we render backfaces for // shadows or does the ESM take care of // all our acne issues? //forced.setCullMode( GFXCullCW ); // Vector, and spotlights use the same shadow material. BaseMatInstance *newMat = new ShadowMatInstance( shadowMat ); newMat->setUserObject( inMat->getUserObject() ); newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures ); newMat->addStateBlockDesc( forced ); if( !newMat->init( features, inMat->getVertexFormat() ) ) { SAFE_DELETE( newMat ); newMat = MATMGR->createWarningMatInstance(); } mShadowMat[ShadowType_Spot] = newMat; newMat = new ShadowMatInstance( shadowMat ); newMat->setUserObject( inMat->getUserObject() ); newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures ); forced.setCullMode( GFXCullCW ); newMat->addStateBlockDesc( forced ); forced.cullDefined = false; newMat->addShaderMacro( "CUBE_SHADOW_MAP", "" ); newMat->init( features, inMat->getVertexFormat() ); mShadowMat[ShadowType_CubeMap] = newMat; // A dual paraboloid shadow rendered in a single draw call. features.addFeature( MFT_ParaboloidVertTransform ); features.addFeature( MFT_IsSinglePassParaboloid ); features.removeFeature( MFT_VertTransform ); newMat = new ShadowMatInstance( shadowMat ); newMat->setUserObject( inMat->getUserObject() ); GFXStateBlockDesc noCull( forced ); noCull.setCullMode( GFXCullNone ); newMat->addStateBlockDesc( noCull ); newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures ); newMat->init( features, inMat->getVertexFormat() ); mShadowMat[ShadowType_DualParaboloidSinglePass] = newMat; // Regular dual paraboloid shadow. features.addFeature( MFT_ParaboloidVertTransform ); features.removeFeature( MFT_IsSinglePassParaboloid ); features.removeFeature( MFT_VertTransform ); newMat = new ShadowMatInstance( shadowMat ); newMat->setUserObject( inMat->getUserObject() ); newMat->addStateBlockDesc( forced ); newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures ); newMat->init( features, inMat->getVertexFormat() ); mShadowMat[ShadowType_DualParaboloid] = newMat; /* // A single paraboloid shadow. newMat = new ShadowMatInstance( startMatInstance ); GFXStateBlockDesc noCull; noCull.setCullMode( GFXCullNone ); newMat->addStateBlockDesc( noCull ); newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures ); newMat->init( features, globalFeatures, inMat->getVertexFormat() ); mShadowMat[ShadowType_DualParaboloidSinglePass] = newMat; */ }
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 WaterPlane::innerRender( SceneRenderState *state ) { GFXDEBUGEVENT_SCOPE( WaterPlane_innerRender, ColorI( 255, 0, 0 ) ); const Point3F &camPosition = state->getCameraPosition(); Point3F rvec, fvec, uvec, pos; const MatrixF &objMat = getTransform(); //getRenderTransform(); const MatrixF &camMat = state->getCameraTransform(); MatrixF renderMat( true ); camMat.getColumn( 1, &fvec ); uvec.set( 0, 0, 1 ); rvec = mCross( fvec, uvec ); rvec.normalize(); fvec = mCross( uvec, rvec ); pos = camPosition; pos.z = objMat.getPosition().z; renderMat.setColumn( 0, rvec ); renderMat.setColumn( 1, fvec ); renderMat.setColumn( 2, uvec ); renderMat.setColumn( 3, pos ); setRenderTransform( renderMat ); // Setup SceneData SceneData sgData = setupSceneGraphInfo( state ); // set the material S32 matIdx = getMaterialIndex( camPosition ); if ( !initMaterial( matIdx ) ) return; BaseMatInstance *mat = mMatInstances[matIdx]; WaterMatParams matParams = mMatParamHandles[matIdx]; // render the geometry if ( mat ) { // setup proj/world transform mMatrixSet->restoreSceneViewProjection(); mMatrixSet->setWorld(getRenderTransform()); setShaderParams( state, mat, matParams ); while( mat->setupPass( state, sgData ) ) { mat->setSceneInfo(state, sgData); mat->setTransforms(*mMatrixSet, state, sgData); setCustomTextures( matIdx, mat->getCurPass(), matParams ); // set vert/prim buffer GFX->setVertexBuffer( mVertBuff ); GFX->setPrimitiveBuffer( mPrimBuff ); GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, mVertCount, 0, mPrimCount ); } } }
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 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; // 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; ) { MeshRenderInst *ri = static_cast<MeshRenderInst*>(mElementList[j].inst); 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++ ) { 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 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 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 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; } } }
//----------------------------------------------------------------------------- // render //----------------------------------------------------------------------------- void RenderMeshMgr::render(SceneRenderState * state) { PROFILE_SCOPE(RenderMeshMgr_render); // Early out if nothing to draw. if(!mElementList.size()) return; GFXDEBUGEVENT_SCOPE( RenderMeshMgr_Render, ColorI::GREEN ); // Automagically save & restore our viewport and transforms. GFXTransformSaver saver; // Restore transforms MatrixSet &matrixSet = getRenderPass()->getMatrixSet(); matrixSet.restoreSceneViewProjection(); // init loop data GFXTextureObject *lastLM = NULL; GFXCubemap *lastCubemap = NULL; GFXTextureObject *lastReflectTex = NULL; GFXTextureObject *lastMiscTex = NULL; SceneData sgData; sgData.init( state ); U32 binSize = mElementList.size(); for( U32 j=0; j<binSize; ) { MeshRenderInst *ri = static_cast<MeshRenderInst*>(mElementList[j].inst); setupSGData( ri, sgData ); BaseMatInstance *mat = ri->matInst; // If we have an override delegate then give it a // chance to swap the material with another. if ( mMatOverrideDelegate ) { mat = mMatOverrideDelegate( mat ); if ( !mat ) { j++; continue; } } if( !mat ) mat = MATMGR->getWarningMatInstance(); U32 matListEnd = j; lastMiscTex = sgData.miscTex; U32 a; while( mat && mat->setupPass(state, sgData ) ) { for( a=j; a<binSize; a++ ) { MeshRenderInst *passRI = static_cast<MeshRenderInst*>(mElementList[a].inst); // Check to see if we need to break this batch. if ( newPassNeeded( ri, passRI ) || lastMiscTex != passRI->miscTex ) { lastLM = NULL; break; } matrixSet.setWorld(*passRI->objectToWorld); matrixSet.setView(*passRI->worldToCamera); matrixSet.setProjection(*passRI->projection); mat->setTransforms(matrixSet, state); setupSGData( passRI, sgData ); mat->setSceneInfo( state, sgData ); // 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; } // TODO: This could proably be done in a cleaner way. // // This section of code is dangerous, it overwrites the // lightmap values in sgData. This could be a problem when multiple // render instances use the same multi-pass material. When // the first pass is done, setupPass() is called again on // the material, but the lightmap data has been changed in // sgData to the lightmaps in the last renderInstance rendered. // This section sets the lightmap data for the current batch. // For the first iteration, it sets the same lightmap data, // however the redundancy will be caught by GFXDevice and not // actually sent to the card. This is done for simplicity given // the possible condition mentioned above. Better to set always // than to get bogged down into special case detection. //------------------------------------- bool dirty = false; // set the lightmaps if different if( passRI->lightmap && passRI->lightmap != lastLM ) { sgData.lightmap = passRI->lightmap; lastLM = passRI->lightmap; dirty = true; } // set the cubemap if different. if ( passRI->cubemap != lastCubemap ) { sgData.cubemap = passRI->cubemap; lastCubemap = passRI->cubemap; dirty = true; } if ( passRI->reflectTex != lastReflectTex ) { sgData.reflectTex = passRI->reflectTex; lastReflectTex = passRI->reflectTex; dirty = true; } if ( dirty ) mat->setTextureStages( state, sgData ); // 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 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 ); } }