shadowMatHook.cpp 8.9 KB

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