bool RenderPrePassMgr::_updateTargets()
{
   PROFILE_SCOPE(RenderPrePassMgr_updateTargets);

   bool ret = Parent::_updateTargets();

   // check for an output conditioner, and update it's format
   ConditionerFeature *outputConditioner = dynamic_cast<ConditionerFeature *>(FEATUREMGR->getByType(MFT_PrePassConditioner));
   if( outputConditioner && outputConditioner->setBufferFormat(mTargetFormat) )
   {
      // reload materials, the conditioner needs to alter the generated shaders
   }

   // Attach the light info buffer as a second render target, if there is
   // lightmapped geometry in the scene.
   AdvancedLightBinManager *lightBin;
   if (  Sim::findObject( "AL_LightBinMgr", lightBin ) &&
         lightBin->MRTLightmapsDuringPrePass() &&
         lightBin->isProperlyAdded() )
   {
      // Update the size of the light bin target here. This will call _updateTargets
      // on the light bin
      ret &= lightBin->setTargetSize( mTargetSize );
      if ( ret )
      {
         // Sanity check
         AssertFatal(lightBin->getTargetChainLength() == mTargetChainLength, "Target chain length mismatch");

         // Attach light info buffer to Color1 for each target in the chain
         for ( U32 i = 0; i < mTargetChainLength; i++ )
         {
            GFXTexHandle lightInfoTex = lightBin->getTargetTexture(0, i);
            mTargetChain[i]->attachTexture(GFXTextureTarget::Color1, lightInfoTex);
         }
      }
   }

   return ret;
}
示例#2
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;
}