Torque3D Documentation / _generateds / shadowMatHook.cpp

shadowMatHook.cpp

Engine/source/lighting/shadowMap/shadowMatHook.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "lighting/shadowMap/shadowMatHook.h"
 26
 27#include "materials/materialManager.h"
 28#include "materials/customMaterialDefinition.h"
 29#include "materials/materialFeatureTypes.h"
 30#include "materials/materialFeatureData.h"
 31#include "shaderGen/featureType.h"
 32#include "shaderGen/featureMgr.h"
 33#include "scene/sceneRenderState.h"
 34#include "terrain/terrFeatureTypes.h"
 35
 36
 37const MatInstanceHookType ShadowMaterialHook::Type( "ShadowMap" );
 38
 39ShadowMaterialHook::ShadowMaterialHook()
 40{
 41   dMemset( mShadowMat, 0, sizeof( mShadowMat ) );
 42}
 43
 44ShadowMaterialHook::~ShadowMaterialHook()
 45{
 46   for ( U32 i = 0; i < ShadowType_Count; i++ )
 47      SAFE_DELETE( mShadowMat[i] );
 48}
 49
 50void ShadowMaterialHook::init( BaseMatInstance *inMat )
 51{
 52   if( !inMat->isValid() )
 53      return;
 54
 55   // Tweak the feature data to include just what we need.
 56   FeatureSet features;
 57   features.addFeature( MFT_VertTransform );
 58   features.addFeature( MFT_DiffuseMap );
 59   features.addFeature( MFT_TexAnim );
 60   features.addFeature( MFT_AlphaTest );
 61   features.addFeature( MFT_Visibility );
 62
 63   // Actually we want to include features from the inMat
 64   // if they operate on the preTransform verts so things
 65   // like wind/deformation effects will also affect the shadow.
 66   const FeatureSet &inFeatures = inMat->getFeatures();
 67   for ( U32 i = 0; i < inFeatures.getCount(); i++ )
 68   {      
 69      const FeatureType& ft = inFeatures.getAt(i);
 70      
 71      if ( ft.getGroup() == MFG_PreTransform )
 72         features.addFeature( ft );
 73   }
 74
 75   // Do instancing in shadows if we can.
 76   if ( inFeatures.hasFeature( MFT_UseInstancing ) )
 77      features.addFeature( MFT_UseInstancing );
 78
 79   Material *shadowMat = (Material*)inMat->getMaterial();
 80   if ( dynamic_cast<CustomMaterial*>( shadowMat ) )
 81   {
 82      // This is a custom material... who knows what it really does, but
 83      // if it wasn't already filtered out of the shadow render then just
 84      // give it some default depth out material.
 85      shadowMat = MATMGR->getMaterialDefinitionByName( "AL_DefaultShadowMaterial" );
 86   }
 87
 88   // By default we want to disable some states
 89   // that the material might enable for us.
 90   GFXStateBlockDesc forced;
 91   forced.setBlend( false );
 92   forced.setAlphaTest( false );
 93
 94   // We should force on zwrite as the deferred
 95   // will disable it by default.
 96   forced.setZReadWrite( true, true );
 97   
 98   // TODO: Should we render backfaces for 
 99   // shadows or does the ESM take care of 
100   // all our acne issues?
101   //forced.setCullMode( GFXCullCW );
102
103   // Vector, and spotlights use the same shadow material.
104   BaseMatInstance *newMat = new ShadowMatInstance( shadowMat );
105   newMat->setUserObject( inMat->getUserObject() );
106   newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
107   newMat->addStateBlockDesc( forced );
108   if( !newMat->init( features, inMat->getVertexFormat() ) )
109   {
110      SAFE_DELETE( newMat );
111      newMat = MATMGR->createWarningMatInstance();
112   }
113   
114   mShadowMat[ShadowType_Spot] = newMat;
115
116   newMat = new ShadowMatInstance( shadowMat );
117   newMat->setUserObject( inMat->getUserObject() );
118   newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
119   forced.setCullMode( GFXCullCW );   
120   newMat->addStateBlockDesc( forced );
121   forced.cullDefined = false;
122   newMat->addShaderMacro( "CUBE_SHADOW_MAP", "" );
123   newMat->init( features, inMat->getVertexFormat() );
124   mShadowMat[ShadowType_CubeMap] = newMat;
125   
126   // A dual paraboloid shadow rendered in a single draw call.
127   features.addFeature( MFT_ParaboloidVertTransform );
128   features.addFeature( MFT_IsSinglePassParaboloid );
129   features.removeFeature( MFT_VertTransform );
130   newMat = new ShadowMatInstance( shadowMat );
131   newMat->setUserObject( inMat->getUserObject() );
132   GFXStateBlockDesc noCull( forced );
133   noCull.setCullMode( GFXCullNone );
134   newMat->addStateBlockDesc( noCull );
135   newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
136   newMat->init( features, inMat->getVertexFormat() );
137   mShadowMat[ShadowType_DualParaboloidSinglePass] = newMat;
138
139   // Regular dual paraboloid shadow.
140   features.addFeature( MFT_ParaboloidVertTransform );
141   features.removeFeature( MFT_IsSinglePassParaboloid );
142   features.removeFeature( MFT_VertTransform );
143   newMat = new ShadowMatInstance( shadowMat );
144   newMat->setUserObject( inMat->getUserObject() );
145   newMat->addStateBlockDesc( forced );
146   newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
147   newMat->init( features, inMat->getVertexFormat() );
148   mShadowMat[ShadowType_DualParaboloid] = newMat;
149
150   /*
151   // A single paraboloid shadow.
152   newMat = new ShadowMatInstance( startMatInstance );
153   GFXStateBlockDesc noCull;
154   noCull.setCullMode( GFXCullNone );
155   newMat->addStateBlockDesc( noCull );
156   newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
157   newMat->init( features, globalFeatures, inMat->getVertexFormat() );
158   mShadowMat[ShadowType_DualParaboloidSinglePass] = newMat;
159   */
160}
161
162BaseMatInstance* ShadowMaterialHook::getShadowMat( ShadowType type ) const
163{ 
164   AssertFatal( type < ShadowType_Count, "ShadowMaterialHook::getShadowMat() - Bad light type!" );
165
166   // The cubemap and pssm shadows use the same
167   // spotlight material for shadows.
168   if (  type == ShadowType_Spot ||         
169         type == ShadowType_PSSM )
170      return mShadowMat[ShadowType_Spot];   
171
172   // Get the specialized shadow material.
173   return mShadowMat[type]; 
174}
175
176void ShadowMaterialHook::_overrideFeatures(  ProcessedMaterial *mat,
177                                             U32 stageNum,
178                                             MaterialFeatureData &fd, 
179                                             const FeatureSet &features )
180{
181   FeatureSet newFeatures;
182
183   for (U32 i = 0; i < fd.features.getCount(); i++)
184   {
185      const FeatureType& type = fd.features.getAt(i);
186      if (type == MFT_AlphaTest ||
187         type == MFT_TexAnim ||
188         type == MFT_DiffuseMap ||
189         type == MFT_IsTranslucent ||
190         type == MFT_Visibility ||
191         type == MFT_UseInstancing ||
192         type == MFT_EyeSpaceDepthOut ||
193         type == MFT_DeferredConditioner)
194            newFeatures.addFeature(type);
195      else if (type.getGroup() == MFG_PreTransform ||
196            type.getGroup() == MFG_Transform ||
197            type.getGroup() == MFG_PostTransform)
198         newFeatures.addFeature(type);
199   }
200
201
202   // Disable the base texture if we don't 
203   // have alpha test enabled.
204   if (!newFeatures[MFT_AlphaTest])
205   {
206      newFeatures.removeFeature(MFT_TexAnim);
207      newFeatures.removeFeature(MFT_DiffuseMap);
208   }
209   else
210      newFeatures.removeFeature(MFT_IsTranslucent);
211
212   // HACK: Need to figure out how to enable these 
213   // suckers without this override call!
214
215   newFeatures.setFeature( MFT_ParaboloidVertTransform,
216      features.hasFeature( MFT_ParaboloidVertTransform ) );
217   newFeatures.setFeature( MFT_IsSinglePassParaboloid,
218      features.hasFeature( MFT_IsSinglePassParaboloid ) );
219      
220   // The paraboloid transform outputs linear depth, so
221   // it needs to use the plain depth out feature.
222   if (newFeatures.hasFeature( MFT_ParaboloidVertTransform ) )
223      newFeatures.addFeature( MFT_DepthOut );
224   else
225      newFeatures.addFeature( MFT_EyeSpaceDepthOut );
226
227   fd.features = newFeatures;
228}
229
230ShadowMatInstance::ShadowMatInstance( Material *mat ) 
231 : MatInstance( *mat )
232{
233   mLightmappedMaterial = mMaterial->isLightmapped();
234}
235
236bool ShadowMatInstance::setupPass( SceneRenderState *state, const SceneData &sgData )
237{
238   // Respect SceneRenderState render flags
239   if( (mLightmappedMaterial && !state->renderLightmappedMeshes()) ||
240       (!mLightmappedMaterial && !state->renderNonLightmappedMeshes()) )
241      return false;
242
243   return Parent::setupPass(state, sgData);
244}
245