/// Creates the default state blocks for a list of render states void ProcessedMaterial::_initRenderStateStateBlocks( RenderPassData *rpd ) { GFXStateBlockDesc stateTranslucent; GFXStateBlockDesc stateGlow; GFXStateBlockDesc stateReflect; GFXStateBlockDesc statePass; _initStateBlockTemplates( stateTranslucent, stateGlow, stateReflect ); _initPassStateBlock( rpd, statePass ); // Ok, we've got our templates set up, let's combine them together based on state and // create our state blocks. for (U32 i = 0; i < RenderPassData::STATE_MAX; i++) { GFXStateBlockDesc stateFinal; if (i & RenderPassData::STATE_REFLECT) stateFinal.addDesc(stateReflect); if (i & RenderPassData::STATE_TRANSLUCENT) stateFinal.addDesc(stateTranslucent); if (i & RenderPassData::STATE_GLOW) stateFinal.addDesc(stateGlow); stateFinal.addDesc(statePass); if (i & RenderPassData::STATE_WIREFRAME) stateFinal.fillMode = GFXFillWireframe; GFXStateBlockRef sb = GFX->createStateBlock(stateFinal); rpd->mRenderStates[i] = sb; } }
void ProcessedCustomMaterial::_initPassStateBlock( RenderPassData *rpd, GFXStateBlockDesc &result ) { Parent::_initPassStateBlock( rpd, result ); if (mCustomMaterial->getStateBlockData()) result.addDesc(mCustomMaterial->getStateBlockData()->getState()); }
void ProcessedFFMaterial::_initPassStateBlock( RenderPassData *rpd, GFXStateBlockDesc &result ) { Parent::_initPassStateBlock( rpd, result ); if ( mIsLightingMaterial ) { result.ffLighting = true; result.blendDefined = true; result.blendEnable = true; result.blendSrc = GFXBlendOne; result.blendSrc = GFXBlendOne; } // This is here for generic FF shader fallbacks. CustomMaterial* custmat = dynamic_cast<CustomMaterial*>(mMaterial); if (custmat && custmat->getStateBlockData() ) result.addDesc(custmat->getStateBlockData()->getState()); }
/// Does the base render state block setting, normally per pass void ProcessedFFMaterial::_initPassStateBlock(const Material::BlendOp blendOp, U32 numTex, const U32 texFlags[Material::MAX_TEX_PER_PASS], GFXStateBlockDesc& result) { Parent::_initPassStateBlock(blendOp, numTex, texFlags, result); if (mIsLightingMaterial) { result.ffLighting = true; result.blendDefined = true; result.blendEnable = true; result.blendSrc = GFXBlendOne; result.blendSrc = GFXBlendOne; } // This is here for generic FF shader fallbacks. CustomMaterial* custmat = dynamic_cast<CustomMaterial*>(mMaterial); if (custmat) { if (custmat->getStateBlockData()) { result.addDesc(custmat->getStateBlockData()->getState()); } } }
void ProcessedMaterial::_initPassStateBlock( RenderPassData *rpd, GFXStateBlockDesc &result ) { if ( rpd->mBlendOp != Material::None ) { result.blendDefined = true; result.blendEnable = true; _setBlendState( rpd->mBlendOp, result ); } if (mMaterial && mMaterial->isDoubleSided()) { result.cullDefined = true; result.cullMode = GFXCullNone; } if(mMaterial && mMaterial->mAlphaTest) { result.alphaDefined = true; result.alphaTestEnable = mMaterial->mAlphaTest; result.alphaTestRef = mMaterial->mAlphaRef; result.alphaTestFunc = GFXCmpGreaterEqual; } result.samplersDefined = true; NamedTexTarget *texTarget; U32 maxAnisotropy = 1; if (mMaterial && mMaterial->mUseAnisotropic[ rpd->mStageNum ] ) maxAnisotropy = MATMGR->getDefaultAnisotropy(); for( U32 i=0; i < rpd->mNumTex; i++ ) { U32 currTexFlag = rpd->mTexType[i]; switch( currTexFlag ) { default: { result.samplers[i].textureColorOp = GFXTOPModulate; result.samplers[i].addressModeU = GFXAddressWrap; result.samplers[i].addressModeV = GFXAddressWrap; if ( maxAnisotropy > 1 ) { result.samplers[i].minFilter = GFXTextureFilterAnisotropic; result.samplers[i].magFilter = GFXTextureFilterAnisotropic; result.samplers[i].maxAnisotropy = maxAnisotropy; } else { result.samplers[i].minFilter = GFXTextureFilterLinear; result.samplers[i].magFilter = GFXTextureFilterLinear; } break; } case Material::Cube: case Material::SGCube: case Material::NormalizeCube: { result.samplers[i].addressModeU = GFXAddressClamp; result.samplers[i].addressModeV = GFXAddressClamp; result.samplers[i].addressModeW = GFXAddressClamp; break; } case Material::TexTarget: { texTarget = mPasses[0]->mTexSlot[i].texTarget; if ( texTarget ) texTarget->setupSamplerState( &result.samplers[i] ); break; } } } // The prepass will take care of writing to the // zbuffer, so we don't have to by default. // The prepass can't write to the backbuffer's zbuffer in OpenGL. if ( MATMGR->getPrePassEnabled() && !GFX->getAdapterType() == OpenGL && !mFeatures.hasFeature(MFT_ForwardShading)) result.setZReadWrite( result.zEnable, false ); result.addDesc(mUserDefined); }
bool TerrainCellMaterial::_createPass( Vector<MaterialInfo*> *materials, Pass *pass, bool firstPass, bool prePassMat, bool reflectMat, bool baseOnly ) { if ( GFX->getPixelShaderVersion() < 3.0f ) baseOnly = true; // NOTE: At maximum we only try to combine sgMaxTerrainMaterialsPerPass materials // into a single pass. This is sub-optimal for the simplest // cases, but the most common case results in much fewer // shader generation failures and permutations leading to // faster load time and less hiccups during gameplay. U32 matCount = getMin( sgMaxTerrainMaterialsPerPass, materials->size() ); Vector<GFXTexHandle> normalMaps; // See if we're currently running under the // basic lighting manager. // // TODO: This seems ugly... we should trigger // features like this differently in the future. // bool useBLM = dStrcmp( LIGHTMGR->getId(), "BLM" ) == 0; // Do we need to disable normal mapping? const bool disableNormalMaps = MATMGR->getExclusionFeatures().hasFeature( MFT_NormalMap ) || useBLM; // How about parallax? const bool disableParallaxMaps = GFX->getPixelShaderVersion() < 3.0f || MATMGR->getExclusionFeatures().hasFeature( MFT_Parallax ); // Has advanced lightmap support been enabled for prepass. bool advancedLightmapSupport = false; if ( prePassMat ) { // This sucks... but it works. AdvancedLightBinManager *lightBin; if ( Sim::findObject( "AL_LightBinMgr", lightBin ) ) advancedLightmapSupport = lightBin->MRTLightmapsDuringPrePass(); } // Loop till we create a valid shader! while( true ) { FeatureSet features; features.addFeature( MFT_VertTransform ); if ( prePassMat ) { features.addFeature( MFT_EyeSpaceDepthOut ); features.addFeature( MFT_PrePassConditioner ); features.addFeature( MFT_DeferredTerrainBaseMap ); features.addFeature(MFT_isDeferred); if ( advancedLightmapSupport ) features.addFeature( MFT_RenderTarget3_Zero ); } else { features.addFeature( MFT_TerrainBaseMap ); features.addFeature( MFT_RTLighting ); // The HDR feature is always added... it will compile out // if HDR is not enabled in the engine. features.addFeature( MFT_HDROut ); } features.addFeature(MFT_DeferredTerrainBlankInfoMap); // Enable lightmaps and fogging if we're in BL. if ( reflectMat || useBLM ) { features.addFeature( MFT_Fog ); features.addFeature( MFT_ForwardShading ); } if ( useBLM ) features.addFeature( MFT_TerrainLightMap ); // The additional passes need to be lerp blended into the // target to maintain the results of the previous passes. if ( !firstPass ) features.addFeature( MFT_TerrainAdditive ); normalMaps.clear(); pass->materials.clear(); // Now add all the material layer features. for ( U32 i=0; i < matCount && !baseOnly; i++ ) { TerrainMaterial *mat = (*materials)[i]->mat; if ( mat == NULL ) continue; // We only include materials that // have more than a base texture. if ( mat->getDetailSize() <= 0 || mat->getDetailDistance() <= 0 || mat->getDetailMap().isEmpty() ) continue; S32 featureIndex = pass->materials.size(); // check for macro detail texture if ( !(mat->getMacroSize() <= 0 || mat->getMacroDistance() <= 0 || mat->getMacroMap().isEmpty() ) ) { if(prePassMat) features.addFeature( MFT_DeferredTerrainMacroMap, featureIndex ); else features.addFeature( MFT_TerrainMacroMap, featureIndex ); } if(prePassMat) features.addFeature( MFT_DeferredTerrainDetailMap, featureIndex ); else features.addFeature( MFT_TerrainDetailMap, featureIndex ); pass->materials.push_back( (*materials)[i] ); normalMaps.increment(); // Skip normal maps if we need to. if ( !disableNormalMaps && mat->getNormalMap().isNotEmpty() ) { features.addFeature( MFT_TerrainNormalMap, featureIndex ); normalMaps.last().set( mat->getNormalMap(), &GFXDefaultStaticNormalMapProfile, "TerrainCellMaterial::_createPass() - NormalMap" ); if ( normalMaps.last().getFormat() == GFXFormatDXT5 ) features.addFeature( MFT_IsDXTnm, featureIndex ); // Do we need and can we do parallax mapping? if ( !disableParallaxMaps && mat->getParallaxScale() > 0.0f && !mat->useSideProjection() ) features.addFeature( MFT_TerrainParallaxMap, featureIndex ); } // Is this layer got side projection? if ( mat->useSideProjection() ) features.addFeature( MFT_TerrainSideProject, featureIndex ); } MaterialFeatureData featureData; featureData.features = features; featureData.materialFeatures = features; // Check to see how many vertex shader output // registers we're gonna need. U32 numTex = 0; U32 numTexReg = 0; for ( U32 i=0; i < features.getCount(); i++ ) { S32 index; const FeatureType &type = features.getAt( i, &index ); ShaderFeature* sf = FEATUREMGR->getByType( type ); if ( !sf ) continue; sf->setProcessIndex( index ); ShaderFeature::Resources res = sf->getResources( featureData ); numTex += res.numTex; numTexReg += res.numTexReg; } // Can we build the shader? // // NOTE: The 10 is sort of an abitrary SM 3.0 // limit. Its really supposed to be 11, but that // always fails to compile so far. // if ( numTex < GFX->getNumSamplers() && numTexReg <= 10 ) { // NOTE: We really shouldn't be getting errors building the shaders, // but we can generate more instructions than the ps_2_x will allow. // // There is no way to deal with this case that i know of other than // letting the compile fail then recovering by trying to build it // with fewer materials. // // We normally disable the shader error logging so that the user // isn't fooled into thinking there is a real bug. That is until // we get down to a single material. If a single material case // fails it means it cannot generate any passes at all! const bool logErrors = matCount == 1; GFXShader::setLogging( logErrors, true ); pass->shader = SHADERGEN->getShader( featureData, getGFXVertexFormat<TerrVertex>(), NULL, mSamplerNames ); } // If we got a shader then we can continue. if ( pass->shader ) break; // If the material count is already 1 then this // is a real shader error... give up! if ( matCount <= 1 ) return false; // If we failed we next try half the input materials // so that we can more quickly arrive at a valid shader. matCount -= matCount / 2; } // Setup the constant buffer. pass->consts = pass->shader->allocConstBuffer(); // Prepare the basic constants. pass->modelViewProjConst = pass->shader->getShaderConstHandle( "$modelview" ); pass->worldViewOnly = pass->shader->getShaderConstHandle( "$worldViewOnly" ); pass->viewToObj = pass->shader->getShaderConstHandle( "$viewToObj" ); pass->eyePosWorldConst = pass->shader->getShaderConstHandle( "$eyePosWorld" ); pass->eyePosConst = pass->shader->getShaderConstHandle( "$eyePos" ); pass->vEyeConst = pass->shader->getShaderConstHandle( "$vEye" ); pass->layerSizeConst = pass->shader->getShaderConstHandle( "$layerSize" ); pass->objTransConst = pass->shader->getShaderConstHandle( "$objTrans" ); pass->worldToObjConst = pass->shader->getShaderConstHandle( "$worldToObj" ); pass->lightInfoBufferConst = pass->shader->getShaderConstHandle( "$lightInfoBuffer" ); pass->baseTexMapConst = pass->shader->getShaderConstHandle( "$baseTexMap" ); pass->layerTexConst = pass->shader->getShaderConstHandle( "$layerTex" ); pass->fogDataConst = pass->shader->getShaderConstHandle( "$fogData" ); pass->fogColorConst = pass->shader->getShaderConstHandle( "$fogColor" ); pass->lightMapTexConst = pass->shader->getShaderConstHandle( "$lightMapTex" ); pass->oneOverTerrainSize = pass->shader->getShaderConstHandle( "$oneOverTerrainSize" ); pass->squareSize = pass->shader->getShaderConstHandle( "$squareSize" ); pass->lightParamsConst = pass->shader->getShaderConstHandle( "$rtParamslightInfoBuffer" ); // Now prepare the basic stateblock. GFXStateBlockDesc desc; if ( !firstPass ) { desc.setBlend( true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha ); // If this is the prepass then we don't want to // write to the last two color channels (where // depth is usually encoded). // // This trick works in combination with the // MFT_TerrainAdditive feature to lerp the // output normal with the previous pass. // if ( prePassMat ) desc.setColorWrites( true, true, true, false ); } // We write to the zbuffer if this is a prepass // material or if the prepass is disabled. desc.setZReadWrite( true, !MATMGR->getPrePassEnabled() || prePassMat || reflectMat ); desc.samplersDefined = true; if ( pass->baseTexMapConst->isValid() ) desc.samplers[pass->baseTexMapConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear(); if ( pass->layerTexConst->isValid() ) desc.samplers[pass->layerTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint(); if ( pass->lightInfoBufferConst->isValid() ) desc.samplers[pass->lightInfoBufferConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint(); if ( pass->lightMapTexConst->isValid() ) desc.samplers[pass->lightMapTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear(); const U32 maxAnisotropy = MATMGR->getDefaultAnisotropy(); // Finally setup the material specific shader // constants and stateblock state. // // NOTE: If this changes be sure to check TerrainCellMaterial::_updateDefaultAnisotropy // to see if it needs the same changes. // for ( U32 i=0; i < pass->materials.size(); i++ ) { MaterialInfo *matInfo = pass->materials[i]; matInfo->detailInfoVConst = pass->shader->getShaderConstHandle( avar( "$detailScaleAndFade%d", i ) ); matInfo->detailInfoPConst = pass->shader->getShaderConstHandle( avar( "$detailIdStrengthParallax%d", i ) ); matInfo->detailTexConst = pass->shader->getShaderConstHandle( avar( "$detailMap%d", i ) ); if ( matInfo->detailTexConst->isValid() ) { const S32 sampler = matInfo->detailTexConst->getSamplerRegister(); desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); desc.samplers[sampler].magFilter = GFXTextureFilterLinear; desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; if ( maxAnisotropy > 1 ) { desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; desc.samplers[sampler].maxAnisotropy = maxAnisotropy; } else desc.samplers[sampler].minFilter = GFXTextureFilterLinear; matInfo->detailTex.set( matInfo->mat->getDetailMap(), &GFXDefaultStaticDiffuseProfile, "TerrainCellMaterial::_createPass() - DetailMap" ); } matInfo->macroInfoVConst = pass->shader->getShaderConstHandle( avar( "$macroScaleAndFade%d", i ) ); matInfo->macroInfoPConst = pass->shader->getShaderConstHandle( avar( "$macroIdStrengthParallax%d", i ) ); matInfo->macroTexConst = pass->shader->getShaderConstHandle( avar( "$macroMap%d", i ) ); if ( matInfo->macroTexConst->isValid() ) { const S32 sampler = matInfo->macroTexConst->getSamplerRegister(); desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); desc.samplers[sampler].magFilter = GFXTextureFilterLinear; desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; if ( maxAnisotropy > 1 ) { desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; desc.samplers[sampler].maxAnisotropy = maxAnisotropy; } else desc.samplers[sampler].minFilter = GFXTextureFilterLinear; matInfo->macroTex.set( matInfo->mat->getMacroMap(), &GFXDefaultStaticDiffuseProfile, "TerrainCellMaterial::_createPass() - MacroMap" ); } //end macro texture matInfo->normalTexConst = pass->shader->getShaderConstHandle( avar( "$normalMap%d", i ) ); if ( matInfo->normalTexConst->isValid() ) { const S32 sampler = matInfo->normalTexConst->getSamplerRegister(); desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); desc.samplers[sampler].magFilter = GFXTextureFilterLinear; desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; if ( maxAnisotropy > 1 ) { desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; desc.samplers[sampler].maxAnisotropy = maxAnisotropy; } else desc.samplers[sampler].minFilter = GFXTextureFilterLinear; matInfo->normalTex = normalMaps[i]; } } // Remove the materials we processed and leave the // ones that remain for the next pass. for ( U32 i=0; i < matCount; i++ ) { MaterialInfo *matInfo = materials->first(); if ( baseOnly || pass->materials.find_next( matInfo ) == -1 ) delete matInfo; materials->pop_front(); } // If we're doing prepass it requires some // special stencil settings for it to work. if ( prePassMat ) desc.addDesc( RenderPrePassMgr::getOpaqueStenciWriteDesc( false ) ); desc.setCullMode( GFXCullCCW ); pass->stateBlock = GFX->createStateBlock(desc); //reflection stateblock desc.setCullMode( GFXCullCW ); pass->reflectionStateBlock = GFX->createStateBlock(desc); // Create the wireframe state blocks. GFXStateBlockDesc wireframe( desc ); wireframe.fillMode = GFXFillWireframe; wireframe.setCullMode( GFXCullCCW ); pass->wireframeStateBlock = GFX->createStateBlock( wireframe ); return true; }
bool RenderImposterMgr::ShaderState::init( const String &shaderName, const GFXStateBlockDesc *desc ) { ShaderData *shaderData; if ( !Sim::findObject( shaderName, shaderData ) ) { Con::warnf( "TSImposterRenderMgr - failed to locate shader '%s'!", shaderName.c_str() ); return false; } // We're adding both the lightinfo uncondition and the // prepass conditioner to the shader... we usually only // use one of them, but the extra macros doesn't hurt. Vector<GFXShaderMacro> macros; mLightTarget = MatTextureTarget::findTargetByName( "lightinfo" ); if ( mLightTarget ) mLightTarget->getTargetShaderMacros( ¯os ); MatTextureTargetRef prepassTarget = MatTextureTarget::findTargetByName( "prepass" ); if ( prepassTarget ) prepassTarget->getTargetShaderMacros( ¯os ); // Get the shader. mShader = shaderData->getShader( macros ); if ( !mShader ) return false; mConsts = mShader->allocConstBuffer(); mWorldViewProjectSC = mShader->getShaderConstHandle( "$modelViewProj" ); mCamPosSC = mShader->getShaderConstHandle( "$camPos" ); mCamRightSC = mShader->getShaderConstHandle( "$camRight" ); mCamUpSC = mShader->getShaderConstHandle( "$camUp" ); mSunDirSC = mShader->getShaderConstHandle( "$sunDir" ); mFogDataSC = mShader->getShaderConstHandle( "$fogData" ); mParamsSC = mShader->getShaderConstHandle( "$params" ); mUVsSC = mShader->getShaderConstHandle( "$uvs" ); mLightColorSC = mShader->getShaderConstHandle( "$lightColor" ); mAmbientSC = mShader->getShaderConstHandle( "$ambient" ); mLightTexRT = mShader->getShaderConstHandle( "$lightTexRT" ); GFXStateBlockDesc d; d.cullDefined = true; d.cullMode = GFXCullNone; d.samplersDefined = true; d.samplers[0] = GFXSamplerStateDesc::getClampLinear(); d.samplers[1] = GFXSamplerStateDesc::getClampLinear(); d.samplers[2] = GFXSamplerStateDesc::getClampLinear(); // We clip in the shader! //d.alphaDefined = true; //d.alphaTestEnable = true; //d.alphaTestRef = 84; //d.alphaTestFunc = GFXCmpGreater; d.zDefined = true; d.zEnable = true; d.zWriteEnable = true; if ( desc ) d.addDesc( *desc ); mSB = GFX->createStateBlock(d); return true; }