/// 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);
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
0
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( &macros );

   MatTextureTargetRef prepassTarget = MatTextureTarget::findTargetByName( "prepass" );
   if ( prepassTarget )
      prepassTarget->getTargetShaderMacros( &macros );

   // 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;
}