renderParticleMgr.cpp
Engine/source/renderInstance/renderParticleMgr.cpp
Public Variables
Public Functions
ConsoleDocClass(RenderParticleMgr , "@brief A <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin which renders particle <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">geometry.\n\n</a>" "This <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin gathers particle <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> instances, sorts , and renders them. " "It is currently used by <a href="/coding/class/classparticleemitter/">ParticleEmitter</a> and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">LightFlareData.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RenderBin\n</a>" )
GFXImplementVertexFormat(CompositeQuadVert )
Detailed Description
Public Variables
const Point4F cubePoints [9]
const bool RenderToParticleTarget
const bool RenderToSingleTarget
Public Functions
ConsoleDocClass(RenderParticleMgr , "@brief A <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin which renders particle <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">geometry.\n\n</a>" "This <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin gathers particle <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> instances, sorts , and renders them. " "It is currently used by <a href="/coding/class/classparticleemitter/">ParticleEmitter</a> and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">LightFlareData.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RenderBin\n</a>" )
GFXImplementVertexFormat(CompositeQuadVert )
IMPLEMENT_CONOBJECT(RenderParticleMgr )
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 "renderInstance/renderParticleMgr.h" 26#include "renderInstance/renderDeferredMgr.h" 27#include "scene/sceneManager.h" 28#include "scene/sceneObject.h" 29#include "scene/sceneRenderState.h" 30#include "gfx/gfxPrimitiveBuffer.h" 31#include "gfx/gfxTransformSaver.h" 32#include "gfx/gfxDebugEvent.h" 33#include "materials/shaderData.h" 34#include "materials/sceneData.h" 35#include "materials/matInstance.h" 36#include "gfx/util/screenspace.h" 37#include "gfx/gfxDrawUtil.h" 38#include "collision/clippedPolyList.h" 39 40static const Point4F cubePoints[9] = 41{ 42 Point4F(-0.5, -0.5, -0.5, 1.0f), Point4F(-0.5, -0.5, 0.5, 1.0f), Point4F(-0.5, 0.5, -0.5, 1.0f), Point4F(-0.5, 0.5, 0.5, 1.0f), 43 Point4F( 0.5, -0.5, -0.5, 1.0f), Point4F( 0.5, -0.5, 0.5, 1.0f), Point4F( 0.5, 0.5, -0.5, 1.0f), Point4F( 0.5, 0.5, 0.5, 1.0f) 44}; 45 46GFXImplementVertexFormat( CompositeQuadVert ) 47{ 48 addElement( "COLOR", GFXDeclType_Color ); 49} 50 51IMPLEMENT_CONOBJECT(RenderParticleMgr); 52 53 54ConsoleDocClass( RenderParticleMgr, 55 "@brief A render bin which renders particle geometry.\n\n" 56 "This render bin gathers particle render instances, sorts, and renders them. " 57 "It is currently used by ParticleEmitter and LightFlareData.\n\n" 58 "@ingroup RenderBin\n" ); 59 60 61const RenderInstType RenderParticleMgr::RIT_Particles("ParticleSystem"); 62 63// TODO: Replace these once they are supported via options 64const bool RenderToParticleTarget = true; 65const bool RenderToSingleTarget = true; 66 67RenderParticleMgr::RenderParticleMgr() 68: Parent( RenderParticleMgr::RIT_Particles, 69 1.0f, 70 1.0f, 71 GFXFormatR8G8B8A8, 72 Point2I( Parent::DefaultTargetSize, Parent::DefaultTargetSize), 73 RenderToParticleTarget ? Parent::DefaultTargetChainLength : 0 ), 74 mParticleShader( NULL ) 75{ 76 // Render particles at 1/4 resolution 77 mTargetSizeType = WindowSizeScaled; 78 mTargetScale.set(0.5f, 0.5f); 79 80 // We use the target chain like a texture pool, not like a swap chain 81 if(!RenderToSingleTarget) 82 setTargetChainLength(5); 83 else 84 mOffscreenSystems.setSize(1); 85 86 notifyType( RenderPassManager::RIT_Particle ); 87 LightManager::smActivateSignal.notify( this, &RenderParticleMgr::_onLMActivate ); 88} 89 90RenderParticleMgr::~RenderParticleMgr() 91{ 92 LightManager::smActivateSignal.remove( this, &RenderParticleMgr::_onLMActivate ); 93} 94 95void RenderParticleMgr::setTargetChainLength( const U32 chainLength ) 96{ 97 Parent::setTargetChainLength(chainLength); 98 99 if(!RenderToSingleTarget) 100 mOffscreenSystems.setSize(chainLength); 101} 102 103void RenderParticleMgr::addElement( RenderInst *inst ) 104{ 105 ParticleRenderInst *pri = reinterpret_cast<ParticleRenderInst *>(inst); 106 107 // If this system isn't waiting for an offscreen draw, skip it 108 if( pri->systemState != PSS_AwaitingOffscreenDraw ) 109 return; 110 111 // If offscreen rendering isn't enabled, set to high-res, and skip 112 if(!mOffscreenRenderEnabled) 113 { 114 pri->systemState = PSS_AwaitingHighResDraw; 115 return; 116 } 117 118 // Assign a target index 119 RectF screenRect; 120 S32 chainIndex = -1; 121 if(RenderToSingleTarget) 122 { 123 pri->targetIndex = 0; 124 screenRect.point.set(-1.0f, -1.0f); 125 screenRect.extent.set(2.0f, 2.0f); 126 127 mElementList.setSize(1); 128 } 129 else 130 { 131 132 // If we can't fit this into the offscreen systems, skip it, it will render 133 // high resolution 134 // 135 // TODO: Improve this once we are grouping systems 136 if( mTargetChainIdx == OffscreenPoolSize ) 137 return; 138 139 // Transform bounding box into screen space 140 const static PlaneF planes[] = { 141 PlaneF(Point3F( 1.0f, 0.0f, 0.0f), Point3F(-1.0f, 0.0f, 0.0f)), 142 PlaneF(Point3F(-1.0f, 0.0f, 0.0f), Point3F( 1.0f, 0.0f, 0.0f)), 143 144 PlaneF(Point3F( 0.0f, 1.0f, 0.0f), Point3F( 0.0f, -1.0f, 0.0f)), 145 PlaneF(Point3F( 0.0f, -1.0f, 0.0f), Point3F( 0.0f, 1.0f, 0.0f)), 146 147 PlaneF(Point3F( 0.0f, 0.0f, 0.0f), Point3F( 0.0f, 0.0f, 1.0f)), 148 PlaneF(Point3F( 0.0f, 0.0f, 1.0f), Point3F( 0.0f, 0.0f, -1.0f)), 149 }; 150 const static dsize_t numPlanes = sizeof(planes) / sizeof(PlaneF); 151 152 // Set up a clipper 153 ClippedPolyList screenClipper; 154 screenClipper.setBaseTransform(MatrixF::Identity); 155 screenClipper.setTransform(&MatrixF::Identity, Point3F::One); 156 TORQUE_UNUSED(numPlanes); 157 158 Point4F tempPt(0.0f, 0.0f, 0.0f, 1.0f); 159 pri->bbModelViewProj->mul(tempPt); 160 tempPt = tempPt / tempPt.w; 161 162 for(S32 i = 0; i < 1; i++) 163 { 164 screenClipper.mPlaneList.push_back(planes[i]); 165 screenClipper.mPlaneList.last() += tempPt.asPoint3F(); 166 } 167 168 Box3F screenSpaceBoundingBox; 169 screenSpaceBoundingBox.minExtents = Point3F::Zero; 170 screenSpaceBoundingBox.maxExtents = Point3F::Zero; 171 172 for(S32 i = 0; i < 8; i++) 173 { 174 tempPt = cubePoints[i]; 175 pri->bbModelViewProj->mul(tempPt); 176 tempPt = tempPt / tempPt.w; 177 178 screenSpaceBoundingBox.maxExtents.setMax(tempPt.asPoint3F()); 179 screenSpaceBoundingBox.minExtents.setMin(tempPt.asPoint3F()); 180 } 181 182 screenClipper.addBox(screenSpaceBoundingBox); 183 184 screenClipper.cullUnusedVerts(); 185 //screenClipper.triangulate(); 186 187 // Empty vertex list? Skip! 188 if(screenClipper.mVertexList.empty()) 189 { 190 pri->systemState = PSS_AwaitingHighResDraw; 191 return; 192 } 193 194 Point2F minExtents(0.0f, 0.0f), maxExtents(0.0f, 0.0f); 195 for(ClippedPolyList::VertexList::const_iterator itr = screenClipper.mVertexList.begin(); 196 itr != screenClipper.mVertexList.end(); itr++) 197 { 198 minExtents.x = getMin(minExtents.x, (*itr).point.x); 199 minExtents.y = getMin(minExtents.y, (*itr).point.y); 200 maxExtents.x = getMax(maxExtents.x, (*itr).point.x); 201 maxExtents.y = getMax(maxExtents.y, (*itr).point.y); 202 } 203 screenRect.set( minExtents, maxExtents - minExtents ); 204 205 // Check the size of the system on screen. If it is small, it won't 206 // be eating fillrate anyway, so just draw it high-resolution. 207 // The value it checks against is one I found from experimentation, 208 // not anything really meaningful. 209 if( screenRect.extent.x < 0.35f || screenRect.extent.y < 0.35f ) 210 { 211 pri->systemState = PSS_AwaitingHighResDraw; 212 return; 213 } 214 215 pri->targetIndex = mTargetChainIdx; 216 chainIndex = mTargetChainIdx; 217 mTargetChainIdx++; 218 219 // TODO: Rewrite this... 220 mElementList.increment(); 221 } 222 223 // Set up system entry 224 OffscreenSystemEntry &systemEntry = mOffscreenSystems[pri->targetIndex]; 225 226 systemEntry.screenRect = screenRect; 227 systemEntry.targetChainIdx = chainIndex; 228 systemEntry.pInstances.push_back(pri); 229 230 // TODO: Rewrite this block 231 // Assign proper values to sort element 232 MainSortElem& elem = mElementList.last(); 233 elem.inst = reinterpret_cast<RenderInst *>(&systemEntry); 234 elem.key = *((U32*)&inst->sortDistSq); 235 elem.key2 = inst->defaultKey; 236 237 // TODO: [re]move this block 238 systemEntry.clipMatrix.identity(); 239 if(!RenderToSingleTarget) 240 { 241 // Construct crop matrix 242 Point3F scale( getMax(2.0f / systemEntry.screenRect.extent.x, 1.0f), 243 getMax(2.0f / systemEntry.screenRect.extent.y, 1.0f), 244 1.0f); 245 246 Point3F offset((systemEntry.screenRect.point.x + systemEntry.screenRect.extent.x * 0.5f) * scale.x, 247 (systemEntry.screenRect.point.y + systemEntry.screenRect.extent.y * 0.5f) * scale.y, 248 0.0f); 249 250 //systemEntry.clipMatrix.scale(scale); 251 //systemEntry.clipMatrix.setPosition(-offset); 252 } 253 254 // The translucent mgr will also pick up particles, and will call this class 255 // to composiste the particle systems back into the main scene 256} 257 258void RenderParticleMgr::sort() 259{ 260 Parent::sort(); 261} 262 263void RenderParticleMgr::clear() 264{ 265 Parent::clear(); 266 267 // Reset pool index 268 if(!RenderToSingleTarget) 269 mTargetChainIdx = 0; 270 271 for(Vector<OffscreenSystemEntry>::iterator itr = mOffscreenSystems.begin(); 272 itr != mOffscreenSystems.end(); itr++) 273 { 274 (*itr).drawnThisFrame = false; 275 (*itr).pInstances.clear(); 276 } 277} 278 279void RenderParticleMgr::render( SceneRenderState *state ) 280{ 281 PROFILE_SCOPE(RenderParticleMgr_render); 282 283 // Early out if nothing to draw 284 if( !mElementList.size() || 285 (!mParticleShader && !_initShader()) ) 286 return; 287 288 GFXDEBUGEVENT_SCOPE(RenderParticleMgr_Render, ColorI::RED); 289 290 GFXTransformSaver saver; 291 292 // Iterate render instances 293 for( Vector<MainSortElem>::const_iterator itr = mElementList.begin(); 294 itr != mElementList.end(); itr++ ) 295 { 296 OffscreenSystemEntry &systemEntry = *reinterpret_cast<OffscreenSystemEntry *>(itr->inst); 297 298 // Setup target 299 // NOTE: If you are using this on the Xbox360 with Basic Lighting, 300 // you are going to have to mess with either the render order, or 301 // you are going to have to make this a 'preserve' draw 302 if(!RenderToSingleTarget) 303 mTargetChainIdx = systemEntry.targetChainIdx; 304 _onPreRender(state); 305 306 // Clear offscreen target 307 GFX->clear(GFXClearTarget, ColorI::ZERO, 1.0f, 0); 308 309 // Draw offscreen systems 310 for( Vector<ParticleRenderInst *>::const_iterator itr2 = systemEntry.pInstances.begin(); 311 itr2 != systemEntry.pInstances.end(); itr2++ ) 312 { 313 ParticleRenderInst *ri = *itr2; 314 315 // Sanity check 316 if(ri->systemState == PSS_AwaitingOffscreenDraw) 317 { 318 // If this is not a diffuse path, flag the system appropriately, and skip 319 // the offscreen processing. 320 if( !state->isDiffusePass() ) 321 { 322 if(state->isReflectPass()) 323 ri->systemState = PSS_AwaitingHighResDraw; 324 else 325 ri->systemState = PSS_DrawComplete; 326 continue; 327 } 328 329 // Draw system offscreen 330 renderInstance(ri, state); 331 } 332 } 333 334 // Cleanup 335 _onPostRender(); 336 } 337} 338 339void RenderParticleMgr::_initGFXResources() 340{ 341 // Screen quad 342 U16 prims [] = { 343 0, 1, 2, 3, 344 }; 345 mScreenQuadPrimBuff.immutable(GFX, 4, 2, prims); 346 347 mScreenQuadVertBuff.set(GFX, 4, GFXBufferTypeStatic); 348 CompositeQuadVert *verts = mScreenQuadVertBuff.lock(); 349 (*verts++).uvCoord.set(0, 0, 0, 0); 350 (*verts++).uvCoord.set(0, 255, 0, 0); 351 (*verts++).uvCoord.set(255, 0, 0, 0); 352 (*verts++).uvCoord.set(255, 255, 0, 0); 353 mScreenQuadVertBuff.unlock(); 354 355 // Stencil setup state block 356 GFXStateBlockDesc d; 357 358 d.setCullMode(GFXCullNone); 359 d.setColorWrites(false, false, false, false); 360 d.setBlend(false); 361 d.setZReadWrite(false, false); 362 363 d.stencilDefined = true; 364 d.stencilEnable = true; 365 d.stencilMask = RenderParticleMgr::ParticleSystemStencilMask; 366 d.stencilWriteMask = RenderParticleMgr::ParticleSystemStencilMask; 367 d.stencilFunc = GFXCmpAlways; 368 d.stencilPassOp = GFXStencilOpZero; 369 370 mStencilClearSB = GFX->createStateBlock(d); 371} 372 373void RenderParticleMgr::renderInstance(ParticleRenderInst *ri, SceneRenderState *state) 374{ 375 // Draw system path, or draw composite path 376 if(ri->systemState == PSS_DrawComplete) 377 return; 378 379 if(ri->systemState != PSS_AwaitingCompositeDraw) 380 { 381 // Set proper stateblock, and update state 382 if(ri->systemState == PSS_AwaitingOffscreenDraw) 383 { 384 GFX->setStateBlock( _getOffscreenStateBlock(ri) ); 385 ri->systemState = PSS_AwaitingCompositeDraw; 386 mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mModelViewProjSC, 387 *ri->modelViewProj * mOffscreenSystems[ri->targetIndex].clipMatrix ); 388 } 389 else 390 { 391 if(ri->systemState == PSS_AwaitingMixedResDraw) 392 GFX->setStateBlock( _getMixedResStateBlock( ri ) ); 393 else 394 GFX->setStateBlock( _getHighResStateBlock( ri ) ); 395 ri->systemState = PSS_DrawComplete; 396 mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mModelViewProjSC, *ri->modelViewProj ); 397 } 398 399 renderParticle(ri, state); 400 } 401 else if(ri->systemState == PSS_AwaitingCompositeDraw) 402 { 403 OffscreenSystemEntry &systemEntry = mOffscreenSystems[ri->targetIndex]; 404 405 // If this system has already been composited this frame, skip it 406 if(systemEntry.drawnThisFrame) 407 return; 408 409 // Non-target render, composite the particle system back into the scene 410 GFX->setVertexBuffer(mScreenQuadVertBuff); 411 GFX->setPrimitiveBuffer(mScreenQuadPrimBuff); 412 413 414 // Set up shader constants 415 mParticleCompositeShaderConsts.mShaderConsts->setSafe( mParticleCompositeShaderConsts.mScreenRect, *((Point4F *)&systemEntry.screenRect) ); 416 417 // Set offscreen texture 418 Point4F rtParams; 419 GFXTextureObject *particleSource = mNamedTarget.getTexture(); 420 GFX->setTexture( mParticleCompositeShaderConsts.mSamplerColorSource->getSamplerRegister(), particleSource ); 421 if(particleSource) 422 { 423 ScreenSpace::RenderTargetParameters(particleSource->getSize(), mNamedTarget.getViewport(), rtParams); 424 mParticleCompositeShaderConsts.mShaderConsts->setSafe( mParticleCompositeShaderConsts.mOffscreenTargetParamsSC, rtParams ); 425 } 426 427 // And edges 428 GFXTextureObject *texObject = mEdgeTarget ? mEdgeTarget->getTexture() : NULL; 429 GFX->setTexture( mParticleCompositeShaderConsts.mSamplerEdgeSource->getSamplerRegister(), texObject ); 430 if(texObject) 431 { 432 ScreenSpace::RenderTargetParameters(texObject->getSize(), mEdgeTarget->getViewport(), rtParams); 433 mParticleCompositeShaderConsts.mShaderConsts->setSafe( mParticleCompositeShaderConsts.mEdgeTargetParamsSC, rtParams ); 434 } 435 else 436 { 437 AssertFatal(false, "No edge texture target defined, if you want to use mixed particle" 438 "rendering, then make sure that the EdgeDetectPostEffect is enabled."); 439 ri->systemState = PSS_AwaitingHighResDraw; 440 return; 441 } 442 443 // Set shader and constant buffer 444 GFX->setShader( mParticleCompositeShader ); 445 GFX->setShaderConstBuffer( mParticleCompositeShaderConsts.mShaderConsts ); 446 447 // Draw to stencil buffer only to clear the stencil values 448 GFX->setStateBlock( mStencilClearSB ); 449 GFX->drawIndexedPrimitive( GFXTriangleStrip, 0, 0, 4, 0, 2 ); 450 451 // composite particle system back into the scene 452 GFX->setStateBlock( _getCompositeStateBlock(ri) ); 453 GFX->drawIndexedPrimitive( GFXTriangleStrip, 0, 0, 4, 0, 2 ); 454 455 // Re-draw the particle systems in high-res, but only to the stenciled 456 // areas which were enabled via the edge buffer 457 for( Vector<ParticleRenderInst *>::const_iterator itr = systemEntry.pInstances.begin(); 458 itr != systemEntry.pInstances.end(); itr++ ) 459 { 460 ParticleRenderInst *pri = *itr; 461 if(pri->systemState == PSS_AwaitingCompositeDraw) 462 { 463 pri->systemState = PSS_AwaitingMixedResDraw; 464 renderInstance(pri, state); 465 } 466 } 467 468 // Mark this system as having been composited this frame 469 systemEntry.drawnThisFrame = true; 470 } 471} 472 473void RenderParticleMgr::renderParticle(ParticleRenderInst* ri, SceneRenderState* state) 474{ 475 // We want to turn everything into variation on a pre-multiplied alpha blend 476 F32 alphaFactor = 0.0f, alphaScale = 1.0f; 477 switch(ri->blendStyle) 478 { 479 // SrcAlpha, InvSrcAlpha 480 case ParticleRenderInst::BlendNormal: 481 alphaFactor = 1.0f; 482 break; 483 484 // SrcAlpha, One 485 case ParticleRenderInst::BlendAdditive: 486 alphaFactor = 1.0f; 487 alphaScale = 0.0f; 488 break; 489 490 // SrcColor, One 491 case ParticleRenderInst::BlendGreyscale: 492 alphaFactor = -1.0f; 493 alphaScale = 0.0f; 494 break; 495 } 496 497 mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mAlphaFactorSC, alphaFactor ); 498 mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mAlphaScaleSC, alphaScale ); 499 500 mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mFSModelViewProjSC, *ri->modelViewProj ); 501 mParticleShaderConsts.mShaderConsts->setSafe( mParticleShaderConsts.mOneOverFarSC, 1.0f / state->getFarPlane() ); 502 503 if ( mParticleShaderConsts.mOneOverSoftnessSC->isValid() ) 504 { 505 F32 oneOverSoftness = 1.0f; 506 if ( ri->softnessDistance > 0.0f ) 507 oneOverSoftness = 1.0f / ( ri->softnessDistance / state->getFarPlane() ); 508 mParticleShaderConsts.mShaderConsts->set( mParticleShaderConsts.mOneOverSoftnessSC, oneOverSoftness ); 509 } 510 511 GFX->setShader( mParticleShader ); 512 GFX->setShaderConstBuffer( mParticleShaderConsts.mShaderConsts ); 513 514 GFX->setTexture( mParticleShaderConsts.mSamplerDiffuse->getSamplerRegister(), ri->diffuseTex ); 515 516 // Set up the deferred texture. 517 if ( mParticleShaderConsts.mDeferredTargetParamsSC->isValid() ) 518 { 519 GFXTextureObject *texObject = mDeferredTarget ? mDeferredTarget->getTexture(0) : NULL; 520 GFX->setTexture( mParticleShaderConsts.mSamplerDeferredTex->getSamplerRegister(), texObject ); 521 522 Point4F rtParams( 0.0f, 0.0f, 1.0f, 1.0f ); 523 if ( texObject ) 524 ScreenSpace::RenderTargetParameters(texObject->getSize(), mDeferredTarget->getViewport(), rtParams); 525 526 mParticleShaderConsts.mShaderConsts->set( mParticleShaderConsts.mDeferredTargetParamsSC, rtParams ); 527 } 528 529 GFX->setPrimitiveBuffer( *ri->primBuff ); 530 GFX->setVertexBuffer( *ri->vertBuff ); 531 532 GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, ri->count * 4, 0, ri->count * 2 ); 533} 534 535bool RenderParticleMgr::_initShader() 536{ 537 ShaderData *shaderData = NULL; 538 bool ret = true; 539 540 // Need depth from pre-pass, so get the macros 541 Vector<GFXShaderMacro> macros; 542 if ( mDeferredTarget ) 543 mDeferredTarget->getShaderMacros( ¯os ); 544 545 // Create particle shader 546 if ( !Sim::findObject( "ParticlesShaderData", shaderData ) || !shaderData ) 547 Con::warnf( "RenderParticleMgr::_initShader - failed to locate shader ParticlesShaderData!" ); 548 if( shaderData ) 549 mParticleShader = shaderData->getShader( macros ); 550 ret &= (mParticleShader != NULL); 551 552 if ( mParticleShader ) 553 { 554 mParticleShaderConsts.mShaderConsts = mParticleShader->allocConstBuffer(); 555 mParticleShaderConsts.mModelViewProjSC = mParticleShader->getShaderConstHandle( "$modelViewProj" ); 556 mParticleShaderConsts.mOneOverFarSC = mParticleShader->getShaderConstHandle( "$oneOverFar" ); 557 mParticleShaderConsts.mOneOverSoftnessSC = mParticleShader->getShaderConstHandle( "$oneOverSoftness" ); 558 mParticleShaderConsts.mAlphaFactorSC = mParticleShader->getShaderConstHandle( "$alphaFactor" ); 559 mParticleShaderConsts.mAlphaScaleSC = mParticleShader->getShaderConstHandle( "$alphaScale" ); 560 mParticleShaderConsts.mFSModelViewProjSC = mParticleShader->getShaderConstHandle( "$fsModelViewProj" ); 561 mParticleShaderConsts.mDeferredTargetParamsSC = mParticleShader->getShaderConstHandle( "$deferredTargetParams" ); 562 563 //samplers 564 mParticleShaderConsts.mSamplerDiffuse = mParticleShader->getShaderConstHandle("$diffuseMap"); 565 mParticleShaderConsts.mSamplerDeferredTex = mParticleShader->getShaderConstHandle("$deferredTex"); 566 mParticleShaderConsts.mSamplerParaboloidLightMap = mParticleShader->getShaderConstHandle("$paraboloidLightMap"); 567 } 568 569 shaderData = NULL; 570 571 // Create off screen particle composite shader 572 if ( !Sim::findObject( "OffscreenParticleCompositeShaderData", shaderData ) || !shaderData ) 573 Con::warnf( "RenderParticleMgr::_initShader - failed to locate shader OffscreenParticleCompositeShaderData!" ); 574 if( shaderData ) 575 mParticleCompositeShader = shaderData->getShader( macros ); 576 ret &= (mParticleCompositeShader != NULL); 577 578 if ( mParticleCompositeShader ) 579 { 580 mParticleCompositeShaderConsts.mShaderConsts = mParticleCompositeShader->allocConstBuffer(); 581 mParticleCompositeShaderConsts.mScreenRect = mParticleCompositeShader->getShaderConstHandle( "$screenRect" ); 582 mParticleCompositeShaderConsts.mSamplerColorSource = mParticleCompositeShader->getShaderConstHandle( "$colorSource" ); 583 mParticleCompositeShaderConsts.mSamplerEdgeSource = mParticleCompositeShader->getShaderConstHandle( "$edgeSource" ); 584 mParticleCompositeShaderConsts.mEdgeTargetParamsSC = mParticleCompositeShader->getShaderConstHandle( "$edgeTargetParams" ); 585 mParticleCompositeShaderConsts.mOffscreenTargetParamsSC = mParticleCompositeShader->getShaderConstHandle( "$offscreenTargetParams" ); 586 } 587 588 return ret; 589} 590 591void RenderParticleMgr::_onLMActivate( const char*, bool activate ) 592{ 593 if ( activate ) 594 { 595 RenderPassManager *rpm = getRenderPass(); 596 if ( !rpm ) 597 return; 598 599 // Hunt for the pre-pass manager/target 600 RenderDeferredMgr *deferredBin = NULL; 601 for( U32 i = 0; i < rpm->getManagerCount(); i++ ) 602 { 603 RenderBinManager *bin = rpm->getManager(i); 604 if( bin->getRenderInstType() == RenderDeferredMgr::RIT_Deferred ) 605 { 606 deferredBin = (RenderDeferredMgr*)bin; 607 break; 608 } 609 } 610 611 // If we found the deferred bin, set this bin to render very shortly afterwards 612 // and re-add this render-manager. If there is no pre-pass bin, or it doesn't 613 // have a depth-texture, we can't render offscreen. 614 mOffscreenRenderEnabled = deferredBin && (deferredBin->getTargetChainLength() > 0); 615 if(mOffscreenRenderEnabled) 616 { 617 rpm->removeManager(this); 618 setRenderOrder( deferredBin->getRenderOrder() + 0.011f ); 619 rpm->addManager(this); 620 } 621 622 // Find the targets we use 623 mDeferredTarget = NamedTexTarget::find( "deferred" ); 624 mEdgeTarget = NamedTexTarget::find( "edge" ); 625 626 // Setup the shader 627 _initShader(); 628 629 if ( mScreenQuadVertBuff.isNull() ) 630 _initGFXResources(); 631 } 632 else 633 { 634 mStencilClearSB = NULL; 635 mScreenQuadPrimBuff = NULL; 636 mScreenQuadVertBuff = NULL; 637 } 638} 639 640GFXStateBlockRef RenderParticleMgr::_getOffscreenStateBlock(ParticleRenderInst *ri) 641{ 642 const U8 blendStyle = ri->blendStyle; 643 if ( mOffscreenBlocks[blendStyle].isValid() ) 644 return mOffscreenBlocks[blendStyle]; 645 646 GFXStateBlockDesc d; 647 648 d.setCullMode(GFXCullNone); 649 d.setZReadWrite(false, false); // No zreads or writes, all z-testing is done in the pixel shader 650 651 // Draw everything either subtractive, or using a variation on premultiplied 652 // alpha 653 if(blendStyle == ParticleRenderInst::BlendSubtractive) 654 d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor); 655 else 656 d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha); 657 658 // Offscreen target, we need to add alpha. 659 d.separateAlphaBlendDefined = true; 660 d.separateAlphaBlendEnable = true; 661 d.separateAlphaBlendSrc = GFXBlendOne; 662 d.separateAlphaBlendDest = GFXBlendInvSrcAlpha; 663 664 d.samplersDefined = true; 665 666 // Diffuse texture sampler 667 d.samplers[0] = GFXSamplerStateDesc::getClampLinear(); 668 669 // Deferred sampler 670 d.samplers[1] = GFXSamplerStateDesc::getClampPoint(); 671 672 mOffscreenBlocks[blendStyle] = GFX->createStateBlock(d); 673 return mOffscreenBlocks[blendStyle]; 674} 675 676GFXStateBlockRef RenderParticleMgr::_getHighResStateBlock(ParticleRenderInst *ri) 677{ 678 const U8 blendStyle = ri->blendStyle; 679 if ( mHighResBlocks[blendStyle].isValid() ) 680 return mHighResBlocks[blendStyle]; 681 682 GFXStateBlockDesc d; 683 684 d.setZReadWrite(true, false); 685 d.setCullMode(GFXCullNone); 686 687 // Draw everything either subtractive, or using a variation on premultiplied 688 // alpha 689 if(blendStyle == ParticleRenderInst::BlendSubtractive) 690 d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor); 691 else 692 d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha); 693 694 d.samplersDefined = true; 695 696 // Diffuse texture sampler 697 d.samplers[0] = GFXSamplerStateDesc::getClampLinear(); 698 699 // Deferred sampler 700 d.samplers[1] = GFXSamplerStateDesc::getClampPoint(); 701 702 mHighResBlocks[blendStyle] = GFX->createStateBlock(d); 703 return mHighResBlocks[blendStyle]; 704} 705 706GFXStateBlockRef RenderParticleMgr::_getMixedResStateBlock(ParticleRenderInst *ri) 707{ 708 const U8 blendStyle = ri->blendStyle; 709 if ( mMixedResBlocks[blendStyle].isValid() ) 710 return mMixedResBlocks[blendStyle]; 711 712 GFXStateBlockDesc d; 713 714 d.setZReadWrite(true, false); 715 d.setCullMode(GFXCullNone); 716 717 /* 718 // Old blend styles... 719 switch (blendStyle) 720 { 721 case ParticleRenderInst::BlendNormal: 722 d.blendSrc = GFXBlendSrcAlpha; 723 d.blendDest = GFXBlendInvSrcAlpha; 724 break; 725 726 case ParticleRenderInst::BlendSubtractive: 727 d.blendSrc = GFXBlendZero; 728 d.blendDest = GFXBlendInvSrcColor; 729 break; 730 731 case ParticleRenderInst::BlendPremultAlpha: 732 d.blendSrc = GFXBlendOne; 733 d.blendDest = GFXBlendInvSrcAlpha; 734 break; 735 736 // Default to additive blend mode 737 case ParticleRenderInst::BlendAdditive: 738 case ParticleRenderInst::BlendUndefined: 739 default: 740 d.blendSrc = GFXBlendSrcAlpha; 741 d.blendDest = GFXBlendOne; 742 break; 743 } 744 */ 745 746 // Draw everything either subtractive, or using a variation on premultiplied 747 // alpha 748 if(blendStyle == ParticleRenderInst::BlendSubtractive) 749 d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor); 750 else 751 d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha); 752 753 // Draw to anything but the stencil ref value (the edges) 754 d.stencilDefined = true; 755 d.stencilEnable = true; 756 d.stencilRef = RenderParticleMgr::HighResStencilRef; 757 d.stencilMask = RenderParticleMgr::ParticleSystemStencilMask; 758 d.stencilPassOp = GFXStencilOpKeep; 759 d.stencilFailOp = GFXStencilOpKeep; 760 d.stencilZFailOp = GFXStencilOpKeep; 761 d.stencilFunc = GFXCmpNotEqual; 762 763 d.samplersDefined = true; 764 765 // Diffuse texture sampler 766 d.samplers[0] = GFXSamplerStateDesc::getClampLinear(); 767 768 // Deferred sampler 769 d.samplers[1] = GFXSamplerStateDesc::getClampPoint(); 770 771 mMixedResBlocks[blendStyle] = GFX->createStateBlock(d); 772 return mMixedResBlocks[blendStyle]; 773} 774 775GFXStateBlockRef RenderParticleMgr::_getCompositeStateBlock(ParticleRenderInst *ri) 776{ 777 const U8 blendStyle = ri->blendStyle; 778 if ( mBackbufferBlocks[blendStyle].isValid() ) 779 return mBackbufferBlocks[blendStyle]; 780 781 GFXStateBlockDesc d; 782 783 // This is a billboard 784 d.setCullMode(GFXCullNone); 785 d.setZReadWrite(false, false); 786 787 // When we re-composite the particles, it is always either a pre-mult alpha 788 // blend, or a subtractive blend! 789 if(blendStyle == ParticleRenderInst::BlendSubtractive) 790 d.setBlend(true, GFXBlendZero, GFXBlendInvSrcColor); 791 else 792 d.setBlend(true, GFXBlendOne, GFXBlendInvSrcAlpha); 793 794 // All areas which are not along the edges of geometry where the particle system 795 // is being drawn get assigned a stencil ref value as the system is composited 796 // back into the scene. The high-res stateblock uses this value as a mask, and 797 // draws only in areas which are NOT this ref value. This causes high resolution 798 // draws to ONLY the edge areas. 799 d.stencilDefined = true; 800 d.stencilEnable = true; 801 d.stencilRef = RenderParticleMgr::HighResStencilRef; 802 d.stencilWriteMask = RenderParticleMgr::ParticleSystemStencilMask; 803 d.stencilMask = RenderParticleMgr::ParticleSystemStencilMask; 804 d.stencilPassOp = GFXStencilOpReplace; 805 d.stencilFunc = GFXCmpGreater; 806 807 // Diffuse texture sampler and 808 d.samplersDefined = true; 809 d.samplers[0] = GFXSamplerStateDesc::getClampLinear(); 810 d.samplers[1] = GFXSamplerStateDesc::getClampLinear(); 811 812 mBackbufferBlocks[blendStyle] = GFX->createStateBlock(d); 813 return mBackbufferBlocks[blendStyle]; 814} 815 816bool RenderParticleMgr::_handleGFXEvent( GFXDevice::GFXDeviceEventType event ) 817{ 818 if(RenderToSingleTarget) 819 return Parent::_handleGFXEvent( event ); 820 821 // Do nothing. This render manager uses its target chain as a pool of targets. 822 return true; 823} 824