1 //-----------------------------------------------------------------------------
2 // Copyright (c) 2012 GarageGames, LLC
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:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
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
21 //-----------------------------------------------------------------------------
23 #include "platform/platform.h"
24 #include "renderInstance/renderPrePassMgr.h"
26 #include "gfx/gfxTransformSaver.h"
27 #include "materials/sceneData.h"
28 #include "materials/materialManager.h"
29 #include "materials/materialFeatureTypes.h"
30 #include "core/util/safeDelete.h"
31 #include "shaderGen/featureMgr.h"
32 #include "shaderGen/HLSL/depthHLSL.h"
33 #include "shaderGen/GLSL/depthGLSL.h"
34 #include "shaderGen/conditionerFeature.h"
35 #include "shaderGen/shaderGenVars.h"
36 #include "scene/sceneRenderState.h"
37 #include "gfx/gfxStringEnumTranslate.h"
38 #include "gfx/gfxDebugEvent.h"
39 #include "gfx/gfxCardProfile.h"
40 #include "materials/customMaterialDefinition.h"
41 #include "lighting/advanced/advancedLightManager.h"
42 #include "lighting/advanced/advancedLightBinManager.h"
43 #include "terrain/terrCell.h"
44 #include "renderInstance/renderTerrainMgr.h"
45 #include "terrain/terrCellMaterial.h"
46 #include "math/mathUtils.h"
47 #include "math/util/matrixSet.h"
48 #include "gfx/gfxTextureManager.h"
49 #include "gfx/primBuilder.h"
50 #include "gfx/gfxDrawUtil.h"
51 #include "materials/shaderData.h"
52 #include "gfx/sim/cubemapData.h"
54 const MatInstanceHookType
PrePassMatInstanceHook::Type( "PrePass" );
55 const String
RenderPrePassMgr::BufferName("prepass");
56 const RenderInstType
RenderPrePassMgr::RIT_PrePass("PrePass");
57 const String
RenderPrePassMgr::ColorBufferName("color");
58 const String
RenderPrePassMgr::MatInfoBufferName("matinfo");
60 IMPLEMENT_CONOBJECT(RenderPrePassMgr
);
62 ConsoleDocClass( RenderPrePassMgr
,
63 "@brief The render bin which performs a z+normals prepass used in Advanced Lighting.\n\n"
64 "This render bin is used in Advanced Lighting to gather all opaque mesh render instances "
65 "and render them to the g-buffer for use in lighting the scene and doing effects.\n\n"
66 "PostEffect and other shaders can access the output of this bin by using the #prepass "
67 "texture target name. See the edge anti-aliasing post effect for an example.\n\n"
68 "@see game/core/scripts/client/postFx/edgeAA.cs\n"
69 "@ingroup RenderBin\n" );
72 RenderPrePassMgr::RenderSignal
& RenderPrePassMgr::getRenderSignal()
74 static RenderSignal theSignal
;
79 RenderPrePassMgr::RenderPrePassMgr( bool gatherDepth
,
81 : Parent( RIT_PrePass
,
85 Point2I( Parent::DefaultTargetSize
, Parent::DefaultTargetSize
),
86 gatherDepth
? Parent::DefaultTargetChainLength
: 0 ),
87 mPrePassMatInstance( NULL
)
89 notifyType( RenderPassManager::RIT_Decal
);
90 notifyType( RenderPassManager::RIT_DecalRoad
);
91 notifyType( RenderPassManager::RIT_Mesh
);
92 notifyType( RenderPassManager::RIT_Terrain
);
93 notifyType( RenderPassManager::RIT_Object
);
95 // We want a full-resolution buffer
96 mTargetSizeType
= RenderTexTargetBinManager::WindowSize
;
98 if(getTargetChainLength() > 0)
99 GFXShader::addGlobalMacro( "TORQUE_LINEAR_DEPTH" );
101 mNamedTarget
.registerWithName( BufferName
);
102 mColorTarget
.registerWithName( ColorBufferName
);
103 mMatInfoTarget
.registerWithName( MatInfoBufferName
);
105 mClearGBufferShader
= NULL
;
110 RenderPrePassMgr::~RenderPrePassMgr()
112 GFXShader::removeGlobalMacro( "TORQUE_LINEAR_DEPTH" );
114 mColorTarget
.release();
115 mMatInfoTarget
.release();
116 _unregisterFeatures();
117 SAFE_DELETE( mPrePassMatInstance
);
120 void RenderPrePassMgr::_registerFeatures()
122 ConditionerFeature
*cond
= new LinearEyeDepthConditioner( getTargetFormat() );
123 FEATUREMGR
->registerFeature( MFT_PrePassConditioner
, cond
);
124 mNamedTarget
.setConditioner( cond
);
127 void RenderPrePassMgr::_unregisterFeatures()
129 mNamedTarget
.setConditioner( NULL
);
130 FEATUREMGR
->unregisterFeature(MFT_PrePassConditioner
);
133 bool RenderPrePassMgr::setTargetSize(const Point2I
&newTargetSize
)
135 bool ret
= Parent::setTargetSize( newTargetSize
);
136 mNamedTarget
.setViewport( GFX
->getViewport() );
137 mColorTarget
.setViewport( GFX
->getViewport() );
138 mMatInfoTarget
.setViewport( GFX
->getViewport() );
142 bool RenderPrePassMgr::_updateTargets()
144 PROFILE_SCOPE(RenderPrePassMgr_updateTargets
);
146 bool ret
= Parent::_updateTargets();
148 // check for an output conditioner, and update it's format
149 ConditionerFeature
*outputConditioner
= dynamic_cast<ConditionerFeature
*>(FEATUREMGR
->getByType(MFT_PrePassConditioner
));
150 if( outputConditioner
&& outputConditioner
->setBufferFormat(mTargetFormat
) )
152 // reload materials, the conditioner needs to alter the generated shaders
155 GFXFormat colorFormat
= mTargetFormat
;
158 bool independentMrtBitDepth = GFX->getCardProfiler()->queryProfile("independentMrtBitDepth", false);
159 //If independent bit depth on a MRT is supported than just use 8bit channels for the albedo color.
160 if(independentMrtBitDepth)
161 colorFormat = GFXFormatR8G8B8A8;
164 // andrewmac: Deferred Shading Color Buffer
165 if (mColorTex
.getFormat() != colorFormat
|| mColorTex
.getWidthHeight() != mTargetSize
|| GFX
->recentlyReset())
167 mColorTarget
.release();
168 mColorTex
.set(mTargetSize
.x
, mTargetSize
.y
, colorFormat
,
169 &GFXDefaultRenderTargetProfile
, avar("%s() - (line %d)", __FUNCTION__
, __LINE__
),
170 1, GFXTextureManager::AA_MATCH_BACKBUFFER
);
171 mColorTarget
.setTexture(mColorTex
);
173 for (U32 i
= 0; i
< mTargetChainLength
; i
++)
174 mTargetChain
[i
]->attachTexture(GFXTextureTarget::Color1
, mColorTarget
.getTexture());
177 // andrewmac: Deferred Shading Material Info Buffer
178 if (mMatInfoTex
.getFormat() != colorFormat
|| mMatInfoTex
.getWidthHeight() != mTargetSize
|| GFX
->recentlyReset())
180 mMatInfoTarget
.release();
181 mMatInfoTex
.set(mTargetSize
.x
, mTargetSize
.y
, colorFormat
,
182 &GFXDefaultRenderTargetProfile
, avar("%s() - (line %d)", __FUNCTION__
, __LINE__
),
183 1, GFXTextureManager::AA_MATCH_BACKBUFFER
);
184 mMatInfoTarget
.setTexture(mMatInfoTex
);
186 for (U32 i
= 0; i
< mTargetChainLength
; i
++)
187 mTargetChain
[i
]->attachTexture(GFXTextureTarget::Color2
, mMatInfoTarget
.getTexture());
190 GFX
->finalizeReset();
192 // Attach the light info buffer as a second render target, if there is
193 // lightmapped geometry in the scene.
194 AdvancedLightBinManager
*lightBin
;
195 if ( Sim::findObject( "AL_LightBinMgr", lightBin
) &&
196 lightBin
->MRTLightmapsDuringPrePass() &&
197 lightBin
->isProperlyAdded() )
199 // Update the size of the light bin target here. This will call _updateTargets
201 ret
&= lightBin
->setTargetSize( mTargetSize
);
205 AssertFatal(lightBin
->getTargetChainLength() == mTargetChainLength
, "Target chain length mismatch");
207 // Attach light info buffer to Color1 for each target in the chain
208 for ( U32 i
= 0; i
< mTargetChainLength
; i
++ )
210 GFXTexHandle lightInfoTex
= lightBin
->getTargetTexture(0, i
);
211 mTargetChain
[i
]->attachTexture(GFXTextureTarget::Color3
, lightInfoTex
);
221 void RenderPrePassMgr::_createPrePassMaterial()
223 SAFE_DELETE(mPrePassMatInstance
);
225 const GFXVertexFormat
*vertexFormat
= getGFXVertexFormat
<GFXVertexPNTTB
>();
227 MatInstance
* prepassMat
= static_cast<MatInstance
*>(MATMGR
->createMatInstance("AL_DefaultPrePassMaterial", vertexFormat
));
228 AssertFatal( prepassMat
, "TODO: Handle this better." );
229 mPrePassMatInstance
= new PrePassMatInstance(prepassMat
, this);
230 mPrePassMatInstance
->init( MATMGR
->getDefaultFeatures(), vertexFormat
);
234 void RenderPrePassMgr::setPrePassMaterial( PrePassMatInstance
*mat
)
236 SAFE_DELETE(mPrePassMatInstance
);
237 mPrePassMatInstance
= mat
;
240 void RenderPrePassMgr::addElement( RenderInst
*inst
)
242 PROFILE_SCOPE( RenderPrePassMgr_addElement
)
244 // Skip out if this bin is disabled.
245 if ( gClientSceneGraph
->getCurrentRenderState() &&
246 gClientSceneGraph
->getCurrentRenderState()->disableAdvancedLightingBins() )
249 // First what type of render instance is it?
250 const bool isDecalMeshInst
= ((inst
->type
== RenderPassManager::RIT_Decal
)||(inst
->type
== RenderPassManager::RIT_DecalRoad
));
252 const bool isMeshInst
= inst
->type
== RenderPassManager::RIT_Mesh
;
254 const bool isTerrainInst
= inst
->type
== RenderPassManager::RIT_Terrain
;
256 // Get the material if its a mesh.
257 BaseMatInstance
* matInst
= NULL
;
258 if ( isMeshInst
|| isDecalMeshInst
)
259 matInst
= static_cast<MeshRenderInst
*>(inst
)->matInst
;
263 // Skip decals if they don't have normal maps.
264 if (isDecalMeshInst
&& !matInst
->hasNormalMap())
267 // If its a custom material and it refracts... skip it.
268 if (matInst
->isCustomMaterial() &&
269 static_cast<CustomMaterial
*>(matInst
->getMaterial())->mRefract
)
272 // Make sure we got a prepass material.
273 matInst
= getPrePassMaterial(matInst
);
274 if (!matInst
|| !matInst
->isValid())
278 // We're gonna add it to the bin... get the right element list.
279 Vector
< MainSortElem
> *elementList
;
280 if ( isMeshInst
|| isDecalMeshInst
)
281 elementList
= &mElementList
;
282 else if ( isTerrainInst
)
283 elementList
= &mTerrainElementList
;
285 elementList
= &mObjectElementList
;
287 elementList
->increment();
288 MainSortElem
&elem
= elementList
->last();
291 // Store the original key... we might need it.
292 U32 originalKey
= elem
.key
;
294 // Sort front-to-back first to get the most fillrate savings.
295 const F32 invSortDistSq
= F32_MAX
- inst
->sortDistSq
;
296 elem
.key
= *((U32
*)&invSortDistSq
);
298 // Next sort by pre-pass material if its a mesh... use the original sort key.
299 if (isMeshInst
&& matInst
)
300 elem
.key2
= matInst
->getStateHint();
302 elem
.key2
= originalKey
;
305 void RenderPrePassMgr::sort()
307 PROFILE_SCOPE( RenderPrePassMgr_sort
);
309 dQsort( mTerrainElementList
.address(), mTerrainElementList
.size(), sizeof(MainSortElem
), cmpKeyFunc
);
310 dQsort( mObjectElementList
.address(), mObjectElementList
.size(), sizeof(MainSortElem
), cmpKeyFunc
);
313 void RenderPrePassMgr::clear()
316 mTerrainElementList
.clear();
317 mObjectElementList
.clear();
320 void RenderPrePassMgr::render( SceneRenderState
*state
)
322 PROFILE_SCOPE(RenderPrePassMgr_render
);
324 // Take a look at the SceneRenderState and see if we should skip drawing the pre-pass
325 if ( state
->disableAdvancedLightingBins() )
328 // NOTE: We don't early out here when the element list is
329 // zero because we need the prepass to be cleared.
331 // Automagically save & restore our viewport and transforms.
332 GFXTransformSaver saver
;
334 GFXDEBUGEVENT_SCOPE( RenderPrePassMgr_Render
, ColorI::RED
);
336 // Tell the superclass we're about to render
337 const bool isRenderingToTarget
= _onPreRender(state
);
339 // Clear all z-buffer, and g-buffer.
342 // Restore transforms
343 MatrixSet
&matrixSet
= getRenderPass()->getMatrixSet();
344 matrixSet
.restoreSceneViewProjection();
345 const MatrixF worldViewXfm
= GFX
->getWorldMatrix();
347 // Setup the default prepass material for object instances.
348 if ( !mPrePassMatInstance
)
349 _createPrePassMaterial();
350 if ( mPrePassMatInstance
)
352 matrixSet
.setWorld(MatrixF::Identity
);
353 mPrePassMatInstance
->setTransforms(matrixSet
, state
);
356 // Signal start of pre-pass
357 getRenderSignal().trigger( state
, this, true );
359 // First do a loop and render all the terrain... these are
360 // usually the big blockers in a scene and will save us fillrate
361 // on the smaller meshes and objects.
363 // The terrain doesn't need any scene graph data
364 // in the the prepass... so just clear it.
366 sgData
.init( state
, SceneData::PrePassBin
);
368 Vector
< MainSortElem
>::const_iterator itr
= mTerrainElementList
.begin();
369 for ( ; itr
!= mTerrainElementList
.end(); itr
++ )
371 TerrainRenderInst
*ri
= static_cast<TerrainRenderInst
*>( itr
->inst
);
373 TerrainCellMaterial
*mat
= ri
->cellMat
->getPrePassMat();
375 GFX
->setPrimitiveBuffer( ri
->primBuff
);
376 GFX
->setVertexBuffer( ri
->vertBuff
);
378 mat
->setTransformAndEye( *ri
->objectToWorldXfm
,
380 GFX
->getProjectionMatrix(),
381 state
->getFarPlane() );
383 while ( mat
->setupPass( state
, sgData
) )
384 GFX
->drawPrimitive( ri
->prim
);
388 GFXTextureObject
*lastLM
= NULL
;
389 GFXCubemap
*lastCubemap
= NULL
;
390 GFXTextureObject
*lastReflectTex
= NULL
;
391 GFXTextureObject
*lastAccuTex
= NULL
;
393 // Next render all the meshes.
394 itr
= mElementList
.begin();
395 for ( ; itr
!= mElementList
.end(); )
397 MeshRenderInst
*ri
= static_cast<MeshRenderInst
*>( itr
->inst
);
399 // Get the prepass material.
400 BaseMatInstance
*mat
= getPrePassMaterial( ri
->matInst
);
402 // Set up SG data proper like and flag it
403 // as a pre-pass render
404 setupSGData( ri
, sgData
);
406 Vector
< MainSortElem
>::const_iterator meshItr
, endOfBatchItr
= itr
;
408 while ( mat
->setupPass( state
, sgData
) )
411 for ( ; meshItr
!= mElementList
.end(); meshItr
++ )
413 MeshRenderInst
*passRI
= static_cast<MeshRenderInst
*>( meshItr
->inst
);
415 // Check to see if we need to break this batch.
417 // NOTE: We're comparing the non-prepass materials
418 // here so we don't incur the cost of looking up the
419 // prepass hook on each inst.
421 if ( newPassNeeded( ri
, passRI
) )
424 // Set up SG data for this instance.
425 setupSGData( passRI
, sgData
);
426 mat
->setSceneInfo(state
, sgData
);
428 matrixSet
.setWorld(*passRI
->objectToWorld
);
429 matrixSet
.setView(*passRI
->worldToCamera
);
430 matrixSet
.setProjection(*passRI
->projection
);
431 mat
->setTransforms(matrixSet
, state
);
433 // Setup HW skinning transforms if applicable
434 if (mat
->usesHardwareSkinning())
436 mat
->setNodeTransforms(passRI
->mNodeTransforms
, passRI
->mNodeTransformCount
);
439 // If we're instanced then don't render yet.
440 if ( mat
->isInstanced() )
442 // Let the material increment the instance buffer, but
443 // break the batch if it runs out of room for more.
444 if ( !mat
->stepInstance() )
455 // set the lightmaps if different
456 if( passRI
->lightmap
&& passRI
->lightmap
!= lastLM
)
458 sgData
.lightmap
= passRI
->lightmap
;
459 lastLM
= passRI
->lightmap
;
463 // set the cubemap if different.
464 if ( passRI
->cubemap
!= lastCubemap
)
466 sgData
.cubemap
= passRI
->cubemap
;
467 lastCubemap
= passRI
->cubemap
;
471 if ( passRI
->reflectTex
!= lastReflectTex
)
473 sgData
.reflectTex
= passRI
->reflectTex
;
474 lastReflectTex
= passRI
->reflectTex
;
478 // Update accumulation texture if it changed.
479 // Note: accumulation texture can be NULL, and must be updated.
480 if (passRI
->accuTex
!= lastAccuTex
)
482 sgData
.accuTex
= passRI
->accuTex
;
483 lastAccuTex
= passRI
->accuTex
;
488 mat
->setTextureStages( state
, sgData
);
490 // Setup the vertex and index buffers.
491 mat
->setBuffers( passRI
->vertBuff
, passRI
->primBuff
);
493 // Render this sucker.
495 GFX
->drawPrimitive( *passRI
->prim
);
497 GFX
->drawPrimitive( passRI
->primBuffIndex
);
500 // Draw the instanced batch.
501 if ( mat
->isInstanced() )
503 // Sets the buffers including the instancing stream.
504 mat
->setBuffers( ri
->vertBuff
, ri
->primBuff
);
507 GFX
->drawPrimitive( *ri
->prim
);
509 GFX
->drawPrimitive( ri
->primBuffIndex
);
512 endOfBatchItr
= meshItr
;
514 } // while( mat->setupPass(state, sgData) )
516 // Force the increment if none happened, otherwise go to end of batch.
517 itr
= ( itr
== endOfBatchItr
) ? itr
+ 1 : endOfBatchItr
;
520 // The final loop is for object render instances.
521 itr
= mObjectElementList
.begin();
522 for ( ; itr
!= mObjectElementList
.end(); itr
++ )
524 ObjectRenderInst
*ri
= static_cast<ObjectRenderInst
*>( itr
->inst
);
525 if ( ri
->renderDelegate
)
526 ri
->renderDelegate( ri
, state
, mPrePassMatInstance
);
529 // Signal end of pre-pass
530 getRenderSignal().trigger( state
, this, false );
532 if(isRenderingToTarget
)
536 const GFXStateBlockDesc
& RenderPrePassMgr::getOpaqueStenciWriteDesc( bool lightmappedGeometry
/*= true*/ )
538 static bool sbInit
= false;
539 static GFXStateBlockDesc sOpaqueStaticLitStencilWriteDesc
;
540 static GFXStateBlockDesc sOpaqueDynamicLitStencilWriteDesc
;
546 // Build the static opaque stencil write/test state block descriptions
547 sOpaqueStaticLitStencilWriteDesc
.stencilDefined
= true;
548 sOpaqueStaticLitStencilWriteDesc
.stencilEnable
= true;
549 sOpaqueStaticLitStencilWriteDesc
.stencilWriteMask
= 0x03;
550 sOpaqueStaticLitStencilWriteDesc
.stencilMask
= 0x03;
551 sOpaqueStaticLitStencilWriteDesc
.stencilRef
= RenderPrePassMgr::OpaqueStaticLitMask
;
552 sOpaqueStaticLitStencilWriteDesc
.stencilPassOp
= GFXStencilOpReplace
;
553 sOpaqueStaticLitStencilWriteDesc
.stencilFailOp
= GFXStencilOpKeep
;
554 sOpaqueStaticLitStencilWriteDesc
.stencilZFailOp
= GFXStencilOpKeep
;
555 sOpaqueStaticLitStencilWriteDesc
.stencilFunc
= GFXCmpAlways
;
558 sOpaqueDynamicLitStencilWriteDesc
= sOpaqueStaticLitStencilWriteDesc
;
559 sOpaqueDynamicLitStencilWriteDesc
.stencilRef
= RenderPrePassMgr::OpaqueDynamicLitMask
;
562 return (lightmappedGeometry
? sOpaqueStaticLitStencilWriteDesc
: sOpaqueDynamicLitStencilWriteDesc
);
565 const GFXStateBlockDesc
& RenderPrePassMgr::getOpaqueStencilTestDesc()
567 static bool sbInit
= false;
568 static GFXStateBlockDesc sOpaqueStencilTestDesc
;
574 sOpaqueStencilTestDesc
.stencilDefined
= true;
575 sOpaqueStencilTestDesc
.stencilEnable
= true;
576 sOpaqueStencilTestDesc
.stencilWriteMask
= 0xFE;
577 sOpaqueStencilTestDesc
.stencilMask
= 0x03;
578 sOpaqueStencilTestDesc
.stencilRef
= 0;
579 sOpaqueStencilTestDesc
.stencilPassOp
= GFXStencilOpKeep
;
580 sOpaqueStencilTestDesc
.stencilFailOp
= GFXStencilOpKeep
;
581 sOpaqueStencilTestDesc
.stencilZFailOp
= GFXStencilOpKeep
;
582 sOpaqueStencilTestDesc
.stencilFunc
= GFXCmpLess
;
585 return sOpaqueStencilTestDesc
;
588 //------------------------------------------------------------------------------
589 //------------------------------------------------------------------------------
592 ProcessedPrePassMaterial::ProcessedPrePassMaterial( Material
& mat
, const RenderPrePassMgr
*prePassMgr
)
593 : Parent(mat
), mPrePassMgr(prePassMgr
)
598 void ProcessedPrePassMaterial::_determineFeatures( U32 stageNum
,
599 MaterialFeatureData
&fd
,
600 const FeatureSet
&features
)
602 Parent::_determineFeatures( stageNum
, fd
, features
);
604 // Find this for use down below...
605 bool bEnableMRTLightmap
= false;
606 AdvancedLightBinManager
*lightBin
;
607 if ( Sim::findObject( "AL_LightBinMgr", lightBin
) )
608 bEnableMRTLightmap
= lightBin
->MRTLightmapsDuringPrePass();
610 // If this material has a lightmap or tonemap (texture or baked vertex color),
611 // it must be static. Otherwise it is dynamic.
612 mIsLightmappedGeometry
= ( fd
.features
.hasFeature( MFT_ToneMap
) ||
613 fd
.features
.hasFeature( MFT_LightMap
) ||
614 fd
.features
.hasFeature( MFT_VertLit
) ||
615 ( bEnableMRTLightmap
&& fd
.features
.hasFeature( MFT_IsTranslucent
) ||
616 fd
.features
.hasFeature( MFT_ForwardShading
) ||
617 fd
.features
.hasFeature( MFT_IsTranslucentZWrite
) ) );
619 // Integrate proper opaque stencil write state
620 mUserDefined
.addDesc( mPrePassMgr
->getOpaqueStenciWriteDesc( mIsLightmappedGeometry
) );
622 FeatureSet newFeatures
;
624 // These are always on for prepass.
625 newFeatures
.addFeature( MFT_EyeSpaceDepthOut
);
626 newFeatures
.addFeature( MFT_PrePassConditioner
);
628 #ifndef TORQUE_DEDICATED
630 //tag all materials running through prepass as deferred
631 newFeatures
.addFeature(MFT_isDeferred
);
633 // Deferred Shading : Diffuse
634 if (mStages
[stageNum
].getTex( MFT_DiffuseMap
))
636 newFeatures
.addFeature(MFT_DiffuseMap
);
638 newFeatures
.addFeature( MFT_DiffuseColor
);
640 // Deferred Shading : Specular
641 if( mStages
[stageNum
].getTex( MFT_SpecularMap
) )
643 newFeatures
.addFeature( MFT_DeferredSpecMap
);
645 else if ( mMaterial
->mPixelSpecular
[stageNum
] )
647 newFeatures
.addFeature( MFT_DeferredSpecVars
);
650 newFeatures
.addFeature(MFT_DeferredEmptySpec
);
652 // Deferred Shading : Material Info Flags
653 newFeatures
.addFeature( MFT_DeferredMatInfoFlags
);
655 for ( U32 i
=0; i
< fd
.features
.getCount(); i
++ )
657 const FeatureType
&type
= fd
.features
.getAt( i
);
659 // Turn on the diffuse texture only if we
661 if ( type
== MFT_AlphaTest
)
663 newFeatures
.addFeature( MFT_AlphaTest
);
664 newFeatures
.addFeature( MFT_DiffuseMap
);
667 else if ( type
== MFT_IsTranslucentZWrite
)
669 newFeatures
.addFeature( MFT_IsTranslucentZWrite
);
670 newFeatures
.addFeature( MFT_DiffuseMap
);
673 // Always allow these.
674 else if ( type
== MFT_IsDXTnm
||
675 type
== MFT_TexAnim
||
676 type
== MFT_NormalMap
||
677 type
== MFT_DetailNormalMap
||
678 type
== MFT_AlphaTest
||
679 type
== MFT_Parallax
||
680 type
== MFT_InterlacedPrePass
||
681 type
== MFT_Visibility
||
682 type
== MFT_UseInstancing
||
683 type
== MFT_DiffuseVertColor
||
684 type
== MFT_DetailMap
||
685 type
== MFT_DetailNormalMap
||
686 type
== MFT_DiffuseMapAtlas
)
687 newFeatures
.addFeature( type
);
689 // Add any transform features.
690 else if ( type
.getGroup() == MFG_PreTransform
||
691 type
.getGroup() == MFG_Transform
||
692 type
.getGroup() == MFG_PostTransform
)
693 newFeatures
.addFeature( type
);
696 if (mMaterial
->mAccuEnabled
[stageNum
])
698 newFeatures
.addFeature(MFT_AccuMap
);
699 mHasAccumulation
= true;
702 // we need both diffuse and normal maps + sm3 to have an accu map
703 if (newFeatures
[MFT_AccuMap
] &&
704 (!newFeatures
[MFT_DiffuseMap
] ||
705 !newFeatures
[MFT_NormalMap
] ||
706 GFX
->getPixelShaderVersion() < 3.0f
)) {
707 AssertWarn(false, "SAHARA: Using an Accu Map requires SM 3.0 and a normal map.");
708 newFeatures
.removeFeature(MFT_AccuMap
);
709 mHasAccumulation
= false;
712 // if we still have the AccuMap feature, we add all accu constant features
713 if (newFeatures
[MFT_AccuMap
]) {
714 // add the dependencies of the accu map
715 newFeatures
.addFeature(MFT_AccuScale
);
716 newFeatures
.addFeature(MFT_AccuDirection
);
717 newFeatures
.addFeature(MFT_AccuStrength
);
718 newFeatures
.addFeature(MFT_AccuCoverage
);
719 newFeatures
.addFeature(MFT_AccuSpecular
);
720 // now remove some features that are not compatible with this
721 newFeatures
.removeFeature(MFT_UseInstancing
);
724 // If there is lightmapped geometry support, add the MRT light buffer features
725 if(bEnableMRTLightmap
)
727 // If this material has a lightmap, pass it through, and flag it to
728 // send it's output to RenderTarget3
729 if( fd
.features
.hasFeature( MFT_ToneMap
) )
731 newFeatures
.addFeature( MFT_ToneMap
);
732 newFeatures
.addFeature( MFT_LightbufferMRT
);
734 else if( fd
.features
.hasFeature( MFT_LightMap
) )
736 newFeatures
.addFeature( MFT_LightMap
);
737 newFeatures
.addFeature( MFT_LightbufferMRT
);
739 else if( fd
.features
.hasFeature( MFT_VertLit
) )
741 // Flag un-tone-map if necesasary
742 if( fd
.features
.hasFeature( MFT_DiffuseMap
) )
743 newFeatures
.addFeature( MFT_VertLitTone
);
745 newFeatures
.addFeature( MFT_VertLit
);
746 newFeatures
.addFeature( MFT_LightbufferMRT
);
750 // If this object isn't lightmapped, add a zero-output feature to it
751 newFeatures
.addFeature( MFT_RenderTarget3_Zero
);
755 // cubemaps only available on stage 0 for now - bramage
757 ( ( mMaterial
->mCubemapData
&& mMaterial
->mCubemapData
->mCubemap
) ||
758 mMaterial
->mDynamicCubemap
) )
759 newFeatures
.addFeature( MFT_CubeMap
);
763 // Set the new features.
764 fd
.features
= newFeatures
;
767 U32
ProcessedPrePassMaterial::getNumStages()
769 // Loops through all stages to determine how many
770 // stages we actually use.
772 // The first stage is always active else we shouldn't be
773 // creating the material to begin with.
777 for( i
=1; i
<Material::MAX_STAGES
; i
++ )
779 // Assume stage is inactive
780 bool stageActive
= false;
782 // Cubemaps only on first stage
785 // If we have a cubemap the stage is active
786 if( mMaterial
->mCubemapData
|| mMaterial
->mDynamicCubemap
)
793 // If we have a texture for the a feature the
795 if ( mStages
[i
].hasValidTex() )
798 // If this stage has specular lighting, it's active
799 if ( mMaterial
->mPixelSpecular
[i
] )
802 // If this stage has diffuse color, it's active
803 if ( mMaterial
->mDiffuse
[i
].alpha
> 0 &&
804 mMaterial
->mDiffuse
[i
] != ColorF::WHITE
)
807 // If we have a Material that is vertex lit
808 // then it may not have a texture
809 if( mMaterial
->mVertLit
[i
] )
812 // Increment the number of active stages
813 numStages
+= stageActive
;
819 void ProcessedPrePassMaterial::addStateBlockDesc(const GFXStateBlockDesc
& desc
)
821 GFXStateBlockDesc prePassStateBlock
= desc
;
823 // Adjust color writes if this is a pure z-fill pass
824 const bool pixelOutEnabled
= mPrePassMgr
->getTargetChainLength() > 0;
825 if ( !pixelOutEnabled
)
827 prePassStateBlock
.colorWriteDefined
= true;
828 prePassStateBlock
.colorWriteRed
= pixelOutEnabled
;
829 prePassStateBlock
.colorWriteGreen
= pixelOutEnabled
;
830 prePassStateBlock
.colorWriteBlue
= pixelOutEnabled
;
831 prePassStateBlock
.colorWriteAlpha
= pixelOutEnabled
;
834 // Never allow the alpha test state when rendering
835 // the prepass as we use the alpha channel for the
836 // depth information... MFT_AlphaTest will handle it.
837 prePassStateBlock
.alphaDefined
= true;
838 prePassStateBlock
.alphaTestEnable
= false;
840 // If we're translucent then we're doing prepass blending
841 // which never writes to the depth channels.
842 const bool isTranslucent
= getMaterial()->isTranslucent();
845 prePassStateBlock
.setBlend( true, GFXBlendSrcAlpha
, GFXBlendInvSrcAlpha
);
846 prePassStateBlock
.setColorWrites(false, false, false, true);
849 // Enable z reads, but only enable zwrites if we're not translucent.
850 prePassStateBlock
.setZReadWrite( true, isTranslucent
? false : true );
853 Parent::addStateBlockDesc(prePassStateBlock
);
856 PrePassMatInstance::PrePassMatInstance(MatInstance
* root
, const RenderPrePassMgr
*prePassMgr
)
857 : Parent(*root
->getMaterial()), mPrePassMgr(prePassMgr
)
859 mFeatureList
= root
->getRequestedFeatures();
860 mVertexFormat
= root
->getVertexFormat();
861 mUserObject
= root
->getUserObject();
864 PrePassMatInstance::~PrePassMatInstance()
868 ProcessedMaterial
* PrePassMatInstance::getShaderMaterial()
870 return new ProcessedPrePassMaterial(*mMaterial
, mPrePassMgr
);
873 bool PrePassMatInstance::init( const FeatureSet
&features
,
874 const GFXVertexFormat
*vertexFormat
)
876 bool vaild
= Parent::init(features
, vertexFormat
);
878 if (mMaterial
&& mMaterial
->mDiffuseMapFilename
[0].isNotEmpty() && mMaterial
->mDiffuseMapFilename
[0].substr(0, 1).equal("#"))
880 String texTargetBufferName
= mMaterial
->mDiffuseMapFilename
[0].substr(1, mMaterial
->mDiffuseMapFilename
[0].length() - 1);
881 NamedTexTarget
*texTarget
= NamedTexTarget::find(texTargetBufferName
);
882 RenderPassData
* rpd
= getPass(0);
886 rpd
->mTexSlot
[0].texTarget
= texTarget
;
887 rpd
->mTexType
[0] = Material::TexTarget
;
888 rpd
->mSamplerNames
[0] = "diffuseMap";
894 PrePassMatInstanceHook::PrePassMatInstanceHook( MatInstance
*baseMatInst
,
895 const RenderPrePassMgr
*prePassMgr
)
896 : mHookedPrePassMatInst(NULL
), mPrePassManager(prePassMgr
)
898 // If the material is a custom material then
899 // hope that using DefaultPrePassMaterial gives
900 // them a good prepass.
901 if ( baseMatInst
->isCustomMaterial() )
903 MatInstance
* dummyInst
= static_cast<MatInstance
*>( MATMGR
->createMatInstance( "AL_DefaultPrePassMaterial", baseMatInst
->getVertexFormat() ) );
905 mHookedPrePassMatInst
= new PrePassMatInstance( dummyInst
, prePassMgr
);
906 mHookedPrePassMatInst
->init( dummyInst
->getRequestedFeatures(), baseMatInst
->getVertexFormat());
912 // Create the prepass material instance.
913 mHookedPrePassMatInst
= new PrePassMatInstance(baseMatInst
, prePassMgr
);
914 mHookedPrePassMatInst
->getFeaturesDelegate() = baseMatInst
->getFeaturesDelegate();
916 // Get the features, but remove the instancing feature if the
917 // original material didn't end up using it.
918 FeatureSet features
= baseMatInst
->getRequestedFeatures();
919 if ( !baseMatInst
->isInstanced() )
920 features
.removeFeature( MFT_UseInstancing
);
922 // Initialize the material.
923 mHookedPrePassMatInst
->init(features
, baseMatInst
->getVertexFormat());
926 PrePassMatInstanceHook::~PrePassMatInstanceHook()
928 SAFE_DELETE(mHookedPrePassMatInst
);
931 //------------------------------------------------------------------------------
932 //------------------------------------------------------------------------------
934 void LinearEyeDepthConditioner::processPix( Vector
<ShaderComponent
*> &componentList
, const MaterialFeatureData
&fd
)
937 ShaderFeature
*depthFeat
= FEATUREMGR
->getByType( MFT_EyeSpaceDepthOut
);
938 AssertFatal( depthFeat
!= NULL
, "No eye space depth feature found!" );
940 Var
*depth
= (Var
*) LangElement::find(depthFeat
->getOutputVarName());
941 AssertFatal( depth
, "Something went bad with ShaderGen. The depth should be already generated by the EyeSpaceDepthOut feature." );
943 MultiLine
*meta
= new MultiLine
;
945 meta
->addStatement( assignOutput( depth
) );
950 Var
*LinearEyeDepthConditioner::_conditionOutput( Var
*unconditionedOutput
, MultiLine
*meta
)
954 String fracMethodName
= (GFX
->getAdapterType() == OpenGL
) ? "fract" : "frac";
956 switch(getBufferFormat())
958 case GFXFormatR8G8B8A8
:
960 retVar
->setType("float4");
961 retVar
->setName("_ppDepth");
962 meta
->addStatement( new GenOp( " // depth conditioner: packing to rgba\r\n" ) );
963 meta
->addStatement( new GenOp(
964 avar( " @ = %s(@ * (255.0/256) * float4(1, 255, 255 * 255, 255 * 255 * 255));\r\n", fracMethodName
.c_str() ),
965 new DecOp(retVar
), unconditionedOutput
) );
968 retVar
= unconditionedOutput
;
969 meta
->addStatement( new GenOp( " // depth conditioner: no conditioning\r\n" ) );
973 AssertFatal( retVar
!= NULL
, avar( "Cannot condition output to buffer format: %s", GFXStringTextureFormat
[getBufferFormat()] ) );
977 Var
*LinearEyeDepthConditioner::_unconditionInput( Var
*conditionedInput
, MultiLine
*meta
)
979 String float4Typename
= (GFX
->getAdapterType() == OpenGL
) ? "vec4" : "float4";
981 Var
*retVar
= conditionedInput
;
982 if(getBufferFormat() != GFXFormat_COUNT
)
985 retVar
->setType(float4Typename
.c_str());
986 retVar
->setName("_ppDepth");
987 meta
->addStatement( new GenOp( avar( " @ = %s(0, 0, 1, 1);\r\n", float4Typename
.c_str() ), new DecOp(retVar
) ) );
989 switch(getBufferFormat())
993 meta
->addStatement( new GenOp( " // depth conditioner: float texture\r\n" ) );
994 meta
->addStatement( new GenOp( " @.w = @.r;\r\n", retVar
, conditionedInput
) );
997 case GFXFormatR8G8B8A8
:
998 meta
->addStatement( new GenOp( " // depth conditioner: unpacking from rgba\r\n" ) );
999 meta
->addStatement( new GenOp(
1000 avar( " @.w = dot(@ * (256.0/255), %s(1, 1 / 255, 1 / (255 * 255), 1 / (255 * 255 * 255)));\r\n", float4Typename
.c_str() )
1001 , retVar
, conditionedInput
) );
1004 AssertFatal(false, "LinearEyeDepthConditioner::_unconditionInput - Unrecognized buffer format");
1011 Var
* LinearEyeDepthConditioner::printMethodHeader( MethodType methodType
, const String
&methodName
, Stream
&stream
, MultiLine
*meta
)
1013 const bool isCondition
= ( methodType
== ConditionerFeature::ConditionMethod
);
1017 // The uncondition method inputs are changed
1019 retVal
= Parent::printMethodHeader( methodType
, methodName
, stream
, meta
);
1022 Var
*methodVar
= new Var
;
1023 methodVar
->setName(methodName
);
1024 if (GFX
->getAdapterType() == OpenGL
)
1025 methodVar
->setType("vec4");
1027 methodVar
->setType("inline float4");
1028 DecOp
*methodDecl
= new DecOp(methodVar
);
1030 Var
*prepassSampler
= new Var
;
1031 prepassSampler
->setName("prepassSamplerVar");
1032 prepassSampler
->setType("sampler2D");
1033 DecOp
*prepassSamplerDecl
= new DecOp(prepassSampler
);
1035 Var
*screenUV
= new Var
;
1036 screenUV
->setName("screenUVVar");
1037 if (GFX
->getAdapterType() == OpenGL
)
1038 screenUV
->setType("vec2");
1040 screenUV
->setType("float2");
1041 DecOp
*screenUVDecl
= new DecOp(screenUV
);
1043 Var
*bufferSample
= new Var
;
1044 bufferSample
->setName("bufferSample");
1045 if (GFX
->getAdapterType() == OpenGL
)
1046 bufferSample
->setType("vec4");
1048 bufferSample
->setType("float4");
1049 DecOp
*bufferSampleDecl
= new DecOp(bufferSample
);
1051 meta
->addStatement( new GenOp( "@(@, @)\r\n", methodDecl
, prepassSamplerDecl
, screenUVDecl
) );
1053 meta
->addStatement( new GenOp( "{\r\n" ) );
1055 meta
->addStatement( new GenOp( " // Sampler g-buffer\r\n" ) );
1057 // The linear depth target has no mipmaps, so use tex2dlod when
1058 // possible so that the shader compiler can optimize.
1059 meta
->addStatement( new GenOp( " #if TORQUE_SM >= 30\r\n" ) );
1060 if (GFX
->getAdapterType() == OpenGL
)
1061 meta
->addStatement( new GenOp( " @ = textureLod(@, @, 0); \r\n", bufferSampleDecl
, prepassSampler
, screenUV
) );
1063 meta
->addStatement( new GenOp( " @ = tex2Dlod(@, float4(@,0,0));\r\n", bufferSampleDecl
, prepassSampler
, screenUV
) );
1064 meta
->addStatement( new GenOp( " #else\r\n" ) );
1065 if (GFX
->getAdapterType() == OpenGL
)
1066 meta
->addStatement( new GenOp( " @ = texture(@, @);\r\n", bufferSampleDecl
, prepassSampler
, screenUV
) );
1068 meta
->addStatement( new GenOp( " @ = tex2D(@, @);\r\n", bufferSampleDecl
, prepassSampler
, screenUV
) );
1069 meta
->addStatement( new GenOp( " #endif\r\n\r\n" ) );
1071 // We don't use this way of passing var's around, so this should cause a crash
1072 // if something uses this improperly
1073 retVal
= bufferSample
;
1079 void RenderPrePassMgr::_initShaders()
1081 if ( mClearGBufferShader
) return;
1084 ShaderData
*shaderData
;
1085 mClearGBufferShader
= Sim::findObject( "ClearGBufferShader", shaderData
) ? shaderData
->getShader() : NULL
;
1086 if ( !mClearGBufferShader
)
1087 Con::errorf( "RenderPrePassMgr::_initShaders - could not find ClearGBufferShader" );
1089 // Create StateBlocks
1090 GFXStateBlockDesc desc
;
1091 desc
.setCullMode( GFXCullNone
);
1092 desc
.setBlend( true );
1093 desc
.setZReadWrite( false, false );
1094 desc
.samplersDefined
= true;
1095 desc
.samplers
[0].addressModeU
= GFXAddressWrap
;
1096 desc
.samplers
[0].addressModeV
= GFXAddressWrap
;
1097 desc
.samplers
[0].addressModeW
= GFXAddressWrap
;
1098 desc
.samplers
[0].magFilter
= GFXTextureFilterLinear
;
1099 desc
.samplers
[0].minFilter
= GFXTextureFilterLinear
;
1100 desc
.samplers
[0].mipFilter
= GFXTextureFilterLinear
;
1101 desc
.samplers
[0].textureColorOp
= GFXTOPModulate
;
1103 mStateblock
= GFX
->createStateBlock( desc
);
1105 // Set up shader constants.
1106 mShaderConsts
= mClearGBufferShader
->allocConstBuffer();
1107 mSpecularStrengthSC
= mClearGBufferShader
->getShaderConstHandle( "$specularStrength" );
1108 mSpecularPowerSC
= mClearGBufferShader
->getShaderConstHandle( "$specularPower" );
1111 void RenderPrePassMgr::clearBuffers()
1114 GFX
->clear( GFXClearTarget
| GFXClearZBuffer
| GFXClearStencil
, ColorI::ZERO
, 1.0f
, 0);
1116 if ( !mClearGBufferShader
)
1119 GFXTransformSaver saver
;
1121 // Clear the g-buffer.
1122 RectI
box(-1, -1, 3, 3);
1123 GFX
->setWorldMatrix( MatrixF::Identity
);
1124 GFX
->setViewMatrix( MatrixF::Identity
);
1125 GFX
->setProjectionMatrix( MatrixF::Identity
);
1127 GFX
->setShader(mClearGBufferShader
);
1128 GFX
->setStateBlock(mStateblock
);
1130 Point2F
nw(-0.5,-0.5);
1131 Point2F
ne(0.5,-0.5);
1133 GFXVertexBufferHandle
<GFXVertexPC
> verts(GFX
, 4, GFXBufferTypeVolatile
);
1136 F32 ulOffset
= 0.5f
- GFX
->getFillConventionOffset();
1138 Point2F
upperLeft(-1.0, -1.0);
1139 Point2F
lowerRight(1.0, 1.0);
1141 verts
[0].point
.set( upperLeft
.x
+nw
.x
+ulOffset
, upperLeft
.y
+nw
.y
+ulOffset
, 0.0f
);
1142 verts
[1].point
.set( lowerRight
.x
+ne
.x
, upperLeft
.y
+ne
.y
+ulOffset
, 0.0f
);
1143 verts
[2].point
.set( upperLeft
.x
-ne
.x
+ulOffset
, lowerRight
.y
-ne
.y
, 0.0f
);
1144 verts
[3].point
.set( lowerRight
.x
-nw
.x
, lowerRight
.y
-nw
.y
, 0.0f
);
1148 GFX
->setVertexBuffer( verts
);
1149 GFX
->drawPrimitive( GFXTriangleStrip
, 0, 2 );
1150 GFX
->setShader(NULL
);