shadowMatHook.cpp
Engine/source/lighting/shadowMap/shadowMatHook.cpp
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