adress #1914
[Torque-3d.git] / Engine / source / renderInstance / renderPrePassMgr.cpp
blob23e44f6ed578dd2d77463ea384ff44081b80a55d
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:
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
20 // IN THE SOFTWARE.
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;
75 return theSignal;
79 RenderPrePassMgr::RenderPrePassMgr( bool gatherDepth,
80 GFXFormat format )
81 : Parent( RIT_PrePass,
82 0.01f,
83 0.01f,
84 format,
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;
107 _registerFeatures();
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() );
139 return ret;
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
200 // on the light bin
201 ret &= lightBin->setTargetSize( mTargetSize );
202 if ( ret )
204 // Sanity check
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);
216 _initShaders();
218 return ret;
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);
231 delete prepassMat;
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() )
247 return;
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;
261 if (matInst)
263 // Skip decals if they don't have normal maps.
264 if (isDecalMeshInst && !matInst->hasNormalMap())
265 return;
267 // If its a custom material and it refracts... skip it.
268 if (matInst->isCustomMaterial() &&
269 static_cast<CustomMaterial*>(matInst->getMaterial())->mRefract)
270 return;
272 // Make sure we got a prepass material.
273 matInst = getPrePassMaterial(matInst);
274 if (!matInst || !matInst->isValid())
275 return;
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;
284 else
285 elementList = &mObjectElementList;
287 elementList->increment();
288 MainSortElem &elem = elementList->last();
289 elem.inst = inst;
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();
301 else
302 elem.key2 = originalKey;
305 void RenderPrePassMgr::sort()
307 PROFILE_SCOPE( RenderPrePassMgr_sort );
308 Parent::sort();
309 dQsort( mTerrainElementList.address(), mTerrainElementList.size(), sizeof(MainSortElem), cmpKeyFunc);
310 dQsort( mObjectElementList.address(), mObjectElementList.size(), sizeof(MainSortElem), cmpKeyFunc);
313 void RenderPrePassMgr::clear()
315 Parent::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() )
326 return;
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.
340 clearBuffers();
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.
365 SceneData sgData;
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,
379 worldViewXfm,
380 GFX->getProjectionMatrix(),
381 state->getFarPlane() );
383 while ( mat->setupPass( state, sgData ) )
384 GFX->drawPrimitive( ri->prim );
387 // init loop data
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 ) )
410 meshItr = itr;
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 ) )
422 break;
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() )
446 meshItr++;
447 break;
450 continue;
453 bool dirty = false;
455 // set the lightmaps if different
456 if( passRI->lightmap && passRI->lightmap != lastLM )
458 sgData.lightmap = passRI->lightmap;
459 lastLM = passRI->lightmap;
460 dirty = true;
463 // set the cubemap if different.
464 if ( passRI->cubemap != lastCubemap )
466 sgData.cubemap = passRI->cubemap;
467 lastCubemap = passRI->cubemap;
468 dirty = true;
471 if ( passRI->reflectTex != lastReflectTex )
473 sgData.reflectTex = passRI->reflectTex;
474 lastReflectTex = passRI->reflectTex;
475 dirty = true;
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;
484 dirty = true;
487 if ( dirty )
488 mat->setTextureStages( state, sgData );
490 // Setup the vertex and index buffers.
491 mat->setBuffers( passRI->vertBuff, passRI->primBuff );
493 // Render this sucker.
494 if ( passRI->prim )
495 GFX->drawPrimitive( *passRI->prim );
496 else
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 );
506 if ( ri->prim )
507 GFX->drawPrimitive( *ri->prim );
508 else
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)
533 _onPostRender();
536 const GFXStateBlockDesc & RenderPrePassMgr::getOpaqueStenciWriteDesc( bool lightmappedGeometry /*= true*/ )
538 static bool sbInit = false;
539 static GFXStateBlockDesc sOpaqueStaticLitStencilWriteDesc;
540 static GFXStateBlockDesc sOpaqueDynamicLitStencilWriteDesc;
542 if(!sbInit)
544 sbInit = true;
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;
557 // Same only dynamic
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;
570 if(!sbInit)
572 // Build opaque test
573 sbInit = true;
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 );
649 else
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
660 // have alpha test.
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 );
748 else
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
756 if ( stageNum < 1 &&
757 ( ( mMaterial->mCubemapData && mMaterial->mCubemapData->mCubemap ) ||
758 mMaterial->mDynamicCubemap ) )
759 newFeatures.addFeature( MFT_CubeMap );
761 #endif
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.
774 U32 numStages = 1;
776 U32 i;
777 for( i=1; i<Material::MAX_STAGES; i++ )
779 // Assume stage is inactive
780 bool stageActive = false;
782 // Cubemaps only on first stage
783 if( i == 0 )
785 // If we have a cubemap the stage is active
786 if( mMaterial->mCubemapData || mMaterial->mDynamicCubemap )
788 numStages++;
789 continue;
793 // If we have a texture for the a feature the
794 // stage is active.
795 if ( mStages[i].hasValidTex() )
796 stageActive = true;
798 // If this stage has specular lighting, it's active
799 if ( mMaterial->mPixelSpecular[i] )
800 stageActive = true;
802 // If this stage has diffuse color, it's active
803 if ( mMaterial->mDiffuse[i].alpha > 0 &&
804 mMaterial->mDiffuse[i] != ColorF::WHITE )
805 stageActive = true;
807 // If we have a Material that is vertex lit
808 // then it may not have a texture
809 if( mMaterial->mVertLit[i] )
810 stageActive = true;
812 // Increment the number of active stages
813 numStages += stageActive;
816 return numStages;
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();
843 if ( 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 );
852 // Pass to parent
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);
884 if (rpd)
886 rpd->mTexSlot[0].texTarget = texTarget;
887 rpd->mTexType[0] = Material::TexTarget;
888 rpd->mSamplerNames[0] = "diffuseMap";
891 return vaild;
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());
908 delete dummyInst;
909 return;
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 )
936 // find depth
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 ) );
947 output = meta;
950 Var *LinearEyeDepthConditioner::_conditionOutput( Var *unconditionedOutput, MultiLine *meta )
952 Var *retVar = NULL;
954 String fracMethodName = (GFX->getAdapterType() == OpenGL) ? "fract" : "frac";
956 switch(getBufferFormat())
958 case GFXFormatR8G8B8A8:
959 retVar = new Var;
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 ) );
966 break;
967 default:
968 retVar = unconditionedOutput;
969 meta->addStatement( new GenOp( " // depth conditioner: no conditioning\r\n" ) );
970 break;
973 AssertFatal( retVar != NULL, avar( "Cannot condition output to buffer format: %s", GFXStringTextureFormat[getBufferFormat()] ) );
974 return retVar;
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)
984 retVar = new Var;
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())
991 case GFXFormatR32F:
992 case GFXFormatR16F:
993 meta->addStatement( new GenOp( " // depth conditioner: float texture\r\n" ) );
994 meta->addStatement( new GenOp( " @.w = @.r;\r\n", retVar, conditionedInput ) );
995 break;
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 ) );
1002 break;
1003 default:
1004 AssertFatal(false, "LinearEyeDepthConditioner::_unconditionInput - Unrecognized buffer format");
1008 return retVar;
1011 Var* LinearEyeDepthConditioner::printMethodHeader( MethodType methodType, const String &methodName, Stream &stream, MultiLine *meta )
1013 const bool isCondition = ( methodType == ConditionerFeature::ConditionMethod );
1015 Var *retVal = NULL;
1017 // The uncondition method inputs are changed
1018 if( isCondition )
1019 retVal = Parent::printMethodHeader( methodType, methodName, stream, meta );
1020 else
1022 Var *methodVar = new Var;
1023 methodVar->setName(methodName);
1024 if (GFX->getAdapterType() == OpenGL)
1025 methodVar->setType("vec4");
1026 else
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");
1039 else
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");
1047 else
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) );
1062 else
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) );
1067 else
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;
1076 return retVal;
1079 void RenderPrePassMgr::_initShaders()
1081 if ( mClearGBufferShader ) return;
1083 // Find ShaderData
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()
1113 // Clear z-buffer.
1114 GFX->clear( GFXClearTarget | GFXClearZBuffer | GFXClearStencil, ColorI::ZERO, 1.0f, 0);
1116 if ( !mClearGBufferShader )
1117 return;
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);
1134 verts.lock();
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 );
1146 verts.unlock();
1148 GFX->setVertexBuffer( verts );
1149 GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
1150 GFX->setShader(NULL);