DeferredView.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  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 deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // 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 FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Geometry.h"
  25. #include "GeometryNode.h"
  26. #include "Light.h"
  27. #include "Log.h"
  28. #include "Material.h"
  29. #include "Pipeline.h"
  30. #include "PixelShader.h"
  31. #include "Profiler.h"
  32. #include "Renderer.h"
  33. #include "RendererImpl.h"
  34. #include "Texture2D.h"
  35. #include "VertexShader.h"
  36. #include "View.h"
  37. #include "DebugNew.h"
  38. static const std::string hwDepthVariations[] =
  39. {
  40. "",
  41. "HW"
  42. };
  43. static const std::string linearVariations[] =
  44. {
  45. "",
  46. "Linear"
  47. };
  48. void View::getBatchesDeferred()
  49. {
  50. Renderer* renderer = mPipeline->getRenderer();
  51. bool deferred = renderer->getRenderMode() == RENDER_DEFERRED;
  52. // G-Buffer pass types depend on whether deferred shading or light prepass is in use
  53. PassType gBufferPass, additionalPass;
  54. if (deferred)
  55. {
  56. gBufferPass = PASS_DEFERRED;
  57. additionalPass = PASS_EMISSIVE;
  58. }
  59. else
  60. {
  61. gBufferPass = PASS_PREPASS;
  62. additionalPass = PASS_MATERIAL;
  63. }
  64. // Go through geometries for GBuffer and ambient batches
  65. {
  66. PROFILE(View_GetAmbientBatches);
  67. for (unsigned i = 0; i < mGeometries.size(); ++i)
  68. {
  69. GeometryNode* node = mGeometries[i];
  70. unsigned numBatches = node->getNumBatches();
  71. for (unsigned j = 0; j < numBatches; ++j)
  72. {
  73. Geometry* geom = node->getBatchGeometry(j);
  74. if (!geom)
  75. continue;
  76. MaterialTechnique* tech = getMaterialTechnique(node, j);
  77. if (!tech)
  78. continue;
  79. // Check here if the material technique refers to a render target texture with camera(s) attached
  80. // Only check this for the main view (null rendertarget)
  81. if ((!mRenderTarget) && (tech->getAuxViewFrameNumber() != mFrame.mFrameNumber))
  82. checkTechniqueForAuxView(tech);
  83. Batch newBatch;
  84. newBatch.mNode = node;
  85. newBatch.mCamera = mCamera;
  86. newBatch.mDistance = node->getDistance();
  87. newBatch.mGeometry = geom;
  88. newBatch.mBatchIndex = j;
  89. // GBuffer pass has priority over ambient pass
  90. MaterialPass* pass = tech->getPass(gBufferPass);
  91. if (pass)
  92. {
  93. // Render opaque objects without alpha masking first
  94. newBatch.mHasPriority = !(pass->getAlphaMask() || pass->getAlphaTest());
  95. mPipeline->setBatchShaders(newBatch, tech, pass);
  96. newBatch.calculateSortKey(true, true);
  97. mGBufferQueue.push_back(newBatch);
  98. // Check for additional emissive pass with deferred rendering, and material pass with light prepass
  99. pass = tech->getPass(additionalPass);
  100. if (pass)
  101. {
  102. newBatch.mHasPriority = false;
  103. mPipeline->setBatchShaders(newBatch, tech, pass);
  104. newBatch.calculateSortKey(true, true);
  105. mForwardQueue.push_back(newBatch);
  106. }
  107. }
  108. else
  109. {
  110. pass = tech->getPass(PASS_AMBIENT);
  111. if (pass)
  112. {
  113. mPipeline->setBatchShaders(newBatch, tech, pass);
  114. if (pass->getBlendMode() == BLEND_REPLACE)
  115. {
  116. newBatch.mHasPriority = !(pass->getAlphaTest() || pass->getAlphaMask());
  117. newBatch.calculateSortKey(true, true);
  118. mAmbientQueue.push_back(newBatch);
  119. }
  120. else
  121. {
  122. newBatch.mHasPriority = true;
  123. newBatch.calculateSortKey(false, false);
  124. mTransparentQueue.push_back(newBatch);
  125. }
  126. }
  127. else
  128. {
  129. // If no other pass yet, check for post-opaque (custom) pass
  130. pass = tech->getPass(PASS_POSTOPAQUE);
  131. if (pass)
  132. {
  133. newBatch.mHasPriority = false;
  134. mPipeline->setBatchShaders(newBatch, tech, pass);
  135. newBatch.calculateSortKey(true, true);
  136. mPostOpaqueQueue.push_back(newBatch);
  137. }
  138. }
  139. }
  140. }
  141. }
  142. }
  143. // Go through lights
  144. {
  145. PROFILE_MULTIPLE(View_GetLightBatches, mLights.size());
  146. unsigned lightQueueCount = 0;
  147. for (unsigned i = 0; i < mLights.size(); ++i)
  148. {
  149. Light* light = mLights[i];
  150. unsigned splits = processLight(light);
  151. if (!splits)
  152. continue;
  153. // For split point lights, check that a transparent object is not lit multiple times
  154. bool splitPointLight = sSplitLights[0]->getLightType() == LIGHT_SPLITPOINT;
  155. static std::set<GeometryNode*> litTransparencies;
  156. litTransparencies.clear();
  157. // Negative (darkening) lighting flag
  158. bool negative = mLights[i]->isNegative();
  159. // Prepare lit object + shadow caster queues for each split
  160. if (mLightQueues.size() < lightQueueCount + splits)
  161. mLightQueues.resize(lightQueueCount + splits);
  162. unsigned prevLightQueueCount = lightQueueCount;
  163. for (unsigned j = 0; j < splits; ++j)
  164. {
  165. LightBatchQueue& lightQueue = mLightQueues[lightQueueCount];
  166. lightQueue.mLight = sSplitLights[j];
  167. lightQueue.mShadowBatches.clear();
  168. lightQueue.mBatches.clear();
  169. lightQueue.mLastSplit = false;
  170. // Loop through shadow casters
  171. Camera& shadowCamera = sSplitLights[j]->getShadowCamera();
  172. for (unsigned k = 0; k < sShadowCasters[j].size(); ++k)
  173. {
  174. GeometryNode* node = sShadowCasters[j][k];
  175. unsigned numBatches = node->getNumBatches();
  176. for (unsigned l = 0; l < numBatches; ++l)
  177. {
  178. MaterialTechnique* tech = getMaterialTechnique(node, l);
  179. if (!tech)
  180. continue;
  181. MaterialPass* pass = tech->getPass(PASS_SHADOW);
  182. // Skip if material has no shadow pass
  183. if (!pass)
  184. continue;
  185. Geometry* geom = node->getBatchGeometry(l);
  186. if (!geom)
  187. continue;
  188. // Build the shadow batch
  189. // Note: shadow cameras are never parented, so can simply use getPosition()
  190. Batch shadowBatch;
  191. shadowBatch.mNode = node;
  192. shadowBatch.mCamera = &shadowCamera;
  193. shadowBatch.mDistance = (node->getWorldPosition() - shadowCamera.getPosition()).getLengthFast();
  194. shadowBatch.mGeometry = geom;
  195. shadowBatch.mBatchIndex = l;
  196. shadowBatch.mForwardLight = sSplitLights[j];
  197. shadowBatch.mHasPriority = !(pass->getAlphaTest() || pass->getAlphaMask());
  198. mPipeline->setBatchShaders(shadowBatch, tech, pass);
  199. shadowBatch.calculateSortKey(true, true);
  200. lightQueue.mShadowBatches.push_back(shadowBatch);
  201. }
  202. }
  203. // Loop through lit geometries to get forward lit objects
  204. for (unsigned k = 0; k < sLitGeometries[j].size(); ++k)
  205. {
  206. GeometryNode* node = sLitGeometries[j][k];
  207. unsigned numBatches = node->getNumBatches();
  208. for (unsigned l = 0; l < numBatches; ++l)
  209. {
  210. MaterialTechnique* tech = getMaterialTechnique(node, l);
  211. if (!tech)
  212. continue;
  213. // Skip if material uses deferred rendering
  214. if (tech->hasPass(gBufferPass))
  215. continue;
  216. MaterialPass* pass;
  217. if (!negative)
  218. pass = tech->getPass(PASS_LIGHT);
  219. else
  220. pass = tech->getPass(PASS_NEGATIVE);
  221. // Skip if material does not receive light
  222. if (!pass)
  223. continue;
  224. Geometry* geom = node->getBatchGeometry(l);
  225. if (!geom)
  226. continue;
  227. // Build the lit batch
  228. Batch newBatch;
  229. newBatch.mNode = node;
  230. newBatch.mCamera = mCamera;
  231. newBatch.mDistance = node->getDistance();
  232. newBatch.mGeometry = geom;
  233. newBatch.mBatchIndex = l;
  234. newBatch.mForwardLight = sSplitLights[j];
  235. // No shadows in any forward lighting
  236. mPipeline->setBatchShaders(newBatch, tech, pass, false);
  237. // Check from the ambient pass whether the object is opaque
  238. MaterialPass* ambientPass = tech->getPass(PASS_AMBIENT);
  239. if ((!ambientPass) || (ambientPass->getBlendMode() == BLEND_REPLACE))
  240. {
  241. // Render negative lights first in the forward lighting queue
  242. newBatch.mHasPriority = negative;
  243. newBatch.calculateSortKey(true, true);
  244. mForwardQueue.push_back(newBatch);
  245. }
  246. else
  247. {
  248. // Prevent multi-lighting by a split point light
  249. // (transparent rendering can not handle the needed stencil masking)
  250. if (splitPointLight)
  251. {
  252. if (litTransparencies.find(node) != litTransparencies.end())
  253. continue;
  254. // Use the original light instead of the split one, to choose correct scissor
  255. newBatch.mForwardLight = mLights[i];
  256. }
  257. // If light is negative, bias the distance slightly to ensure it has priority
  258. if (negative)
  259. newBatch.mDistance -= 0.001f;
  260. newBatch.calculateSortKey(false, false);
  261. mTransparentQueue.push_back(newBatch);
  262. }
  263. }
  264. if (splitPointLight)
  265. litTransparencies.insert(node);
  266. }
  267. // Build the light volume batch
  268. // Check amount of lit geometries
  269. if (sLitGeometries[j].size())
  270. {
  271. Batch lightBatch;
  272. lightBatch.mNode = sSplitLights[j];
  273. lightBatch.mCamera = mCamera;
  274. lightBatch.mDistance = sSplitLights[j]->getDistance();
  275. lightBatch.mGeometry = mPipeline->getLightGeometry(sSplitLights[j]);
  276. mPipeline->setLightVolumeShaders(lightBatch);
  277. lightBatch.calculateSortKey(true, true);
  278. // If light is a split point light, it must be treated as shadowed in any case for correct stencil clearing
  279. if ((sSplitLights[j]->getShadowMap()) || (sSplitLights[j]->getLightType() == LIGHT_SPLITPOINT))
  280. {
  281. lightQueue.mBatches.push_back(lightBatch);
  282. lightQueueCount++;
  283. }
  284. else
  285. {
  286. if (!negative)
  287. mNoShadowLightQueue.push_back(lightBatch);
  288. else
  289. mNegativeLightQueue.push_back(lightBatch);
  290. }
  291. }
  292. }
  293. // Mark the last split
  294. if (lightQueueCount != prevLightQueueCount)
  295. mLightQueues[lightQueueCount - 1].mLastSplit = true;
  296. }
  297. // Resize the shadowed light queue vector now that final size is known
  298. mLightQueues.resize(lightQueueCount);
  299. }
  300. // Finally sort the batches
  301. {
  302. PROFILE(View_SortBatches);
  303. sortBatches(mGBufferQueue, mGBufferQueueSorted);
  304. sortBatches(mNegativeLightQueue, mNegativeLightQueueSorted);
  305. sortBatches(mNoShadowLightQueue, mNoShadowLightQueueSorted);
  306. sortBatches(mAmbientQueue, mAmbientQueueSorted);
  307. sortBatches(mForwardQueue, mForwardQueueSorted);
  308. sortBatches(mPostOpaqueQueue, mPostOpaqueQueueSorted);
  309. sortBatches(mTransparentQueue, mTransparentQueueSorted);
  310. for (unsigned i = 0; i < mLightQueues.size(); ++i)
  311. sortBatches(mLightQueues[i].mShadowBatches, mLightQueues[i].mSortedShadowBatches);
  312. }
  313. }
  314. void View::renderBatchesDeferred()
  315. {
  316. Renderer* renderer = mPipeline->getRenderer();
  317. bool deferred = renderer->getRenderMode() == RENDER_DEFERRED;
  318. Texture2D* diffBuffer = renderer->getDiffBuffer();
  319. Texture2D* normalBuffer = renderer->getNormalBuffer();
  320. Texture2D* depthBuffer = renderer->getDepthBuffer();
  321. bool hwDepth = renderer->getHardwareDepthSupport();
  322. // Check for edge filter. Only use it on the main view (null rendertarget)
  323. const EdgeFilterParameters& filterParams = mPipeline->getEdgeFilter();
  324. bool edgeFilter = (!mRenderTarget) && renderer->getMultiSample() && renderer->getScreenBuffer() &&
  325. (filterParams.mFilterStep > 0.0f) && (filterParams.mMaxFilter > 0.0f);
  326. // Use screen buffer only with edge filtering, else render direct to rendertarget or backbuffer
  327. RenderSurface* renderBuffer = edgeFilter ? renderer->getScreenBuffer()->getRenderSurface() : mRenderTarget;
  328. // Set the G-buffer UV coord adjustment here
  329. int gBufferWidth = diffBuffer->getWidth();
  330. int gBufferHeight = diffBuffer->getHeight();
  331. float widthRange = 0.5f * mWidth / gBufferWidth;
  332. float heightRange = 0.5f * mHeight / gBufferHeight;
  333. Vector4 bufferUVOffset((0.5f + (float)mScreenRect.mLeft) / gBufferWidth, (0.5f + (float)mScreenRect.mTop) / gBufferHeight,
  334. widthRange, heightRange);
  335. renderer->setVertexShaderConstant(getVSRegister(VSP_GBUFFEROFFSETS), bufferUVOffset);
  336. {
  337. // Render G-buffer
  338. PROFILE(View_RenderGBuffer);
  339. clearLastParameterSources();
  340. // Use always the default depth stencil, so that it matches the G-buffer size, and is in the expected format
  341. // Enable depth rendertarget only if hardware depth not supported
  342. renderer->setColorWrite(true);
  343. renderer->setFillMode(FILL_SOLID);
  344. renderer->setScissorTest(false);
  345. renderer->setStencilTest(false);
  346. renderer->resetDepthStencil();
  347. if (deferred)
  348. {
  349. renderer->setRenderTarget(0, diffBuffer);
  350. renderer->setRenderTarget(1, normalBuffer);
  351. if (!hwDepth)
  352. renderer->setRenderTarget(2, depthBuffer);
  353. }
  354. else
  355. {
  356. renderer->setRenderTarget(0, normalBuffer);
  357. if (!hwDepth)
  358. renderer->setRenderTarget(1, depthBuffer);
  359. }
  360. renderer->setViewport(mScreenRect);
  361. // Clear only depth and stencil at first, render the G-buffer batches
  362. renderer->clear(CLEAR_DEPTH | CLEAR_STENCIL);
  363. for (unsigned i = 0; i < mGBufferQueueSorted.size(); ++i)
  364. mGBufferQueueSorted[i]->draw(renderer);
  365. // Then fill the untouched parts of the G-buffer with defaults: black diffuse + specular (deferred only), far depth
  366. renderer->setAlphaTest(false);
  367. renderer->setBlendMode(BLEND_REPLACE);
  368. renderer->setDepthTest(CMP_LESSEQUAL);
  369. renderer->setDepthWrite(false);
  370. if (deferred)
  371. {
  372. renderer->resetRenderTarget(2);
  373. if (!hwDepth)
  374. renderer->setRenderTarget(1, depthBuffer);
  375. else
  376. renderer->resetRenderTarget(1);
  377. mPipeline->drawFullScreenQuad(*mCamera, mPipeline->getVertexShader("Deferred/GBufferFill"),
  378. mPipeline->getPixelShader("Deferred/GBufferFill_" + hwDepthVariations[hwDepth ? 1 : 0]), false);
  379. }
  380. else if (!hwDepth)
  381. {
  382. renderer->resetRenderTarget(1);
  383. renderer->setRenderTarget(0, depthBuffer);
  384. renderer->setViewport(mScreenRect);
  385. // The stencil shader writes color 1.0, which equals far depth
  386. mPipeline->drawFullScreenQuad(*mCamera, mPipeline->getVertexShader("Stencil"),
  387. mPipeline->getPixelShader("Stencil"), false);
  388. }
  389. }
  390. if (deferred)
  391. {
  392. // Render ambient color & fog
  393. clearLastParameterSources();
  394. renderer->setDepthTest(CMP_ALWAYS);
  395. renderer->setRenderTarget(0, renderBuffer);
  396. renderer->resetRenderTarget(1);
  397. renderer->resetRenderTarget(2);
  398. renderer->setTexture(TU_DIFFBUFFER, diffBuffer);
  399. renderer->setTexture(TU_DEPTHBUFFER, depthBuffer);
  400. renderer->setViewport(mScreenRect);
  401. // Use depth reconstruction only if necessary
  402. bool linear = mCamera->isOrthographic() || (!hwDepth);
  403. mPipeline->drawFullScreenQuad(*mCamera, mPipeline->getVertexShader("Deferred/Ambient"),
  404. mPipeline->getPixelShader("Deferred/Ambient_" + linearVariations[linear ? 1 : 0]), false);
  405. }
  406. else
  407. {
  408. // Light prepass: reset the light accumulation buffer with ambient light (half intensity to allow 2x "overburn")
  409. renderer->setRenderTarget(0, diffBuffer);
  410. renderer->resetRenderTarget(1);
  411. renderer->setViewport(mScreenRect);
  412. renderer->clear(CLEAR_COLOR, mZone->getAmbientColor() * 0.5f);
  413. }
  414. {
  415. // Render lights
  416. PROFILE(View_RenderLights);
  417. // Negative lights
  418. if (mNegativeLightQueueSorted.size())
  419. {
  420. clearLastParameterSources();
  421. if (deferred)
  422. renderer->setTexture(TU_DIFFBUFFER, diffBuffer);
  423. renderer->setTexture(TU_NORMALBUFFER, normalBuffer);
  424. renderer->setTexture(TU_DEPTHBUFFER, depthBuffer);
  425. for (unsigned i = 0; i < mNegativeLightQueueSorted.size(); ++i)
  426. {
  427. mPipeline->setupLightBatch(*mNegativeLightQueueSorted[i]);
  428. mNegativeLightQueueSorted[i]->draw(renderer);
  429. }
  430. }
  431. // Shadowed lights
  432. for (unsigned i = 0; i < mLightQueues.size(); ++i)
  433. {
  434. LightBatchQueue& queue = mLightQueues[i];
  435. Texture2D* shadowMap = queue.mLight->getShadowMap();
  436. if (shadowMap)
  437. {
  438. PROFILE(View_RenderShadowMap);
  439. clearLastParameterSources();
  440. renderer->setColorWrite(false);
  441. renderer->setStencilTest(false);
  442. renderer->setTexture(TU_SHADOWMAP, 0);
  443. renderer->setRenderTarget(0, shadowMap->getRenderSurface()->getLinkedRenderTarget());
  444. renderer->setDepthStencil(shadowMap);
  445. renderer->clear(CLEAR_DEPTH);
  446. // Set shadow depth bias
  447. BiasParameters parameters = queue.mLight->getShadowBias();
  448. renderer->setDepthBias(parameters.mConstantBias, parameters.mSlopeScaledBias);
  449. // Set a scissor rectangle to match possible shadow map size reduction by out-zooming
  450. // However, do not do this for point lights
  451. if (queue.mLight->getLightType() != LIGHT_SPLITPOINT)
  452. {
  453. Texture2D* shadowMap = queue.mLight->getShadowMap();
  454. float zoom = min(queue.mLight->getShadowCamera().getZoom(),
  455. (float)(shadowMap->getWidth() - 2) / (float)shadowMap->getWidth());
  456. Rect zoomRect(Vector2(-1.0f, -1.0f) * zoom, Vector2(1.0f, 1.0f) * zoom);
  457. renderer->setScissorTest(true, zoomRect, false);
  458. }
  459. else
  460. renderer->setScissorTest(false);
  461. const std::vector<Batch*>& sortedBatches = queue.mSortedShadowBatches;
  462. if (sortedBatches.size())
  463. {
  464. for (unsigned j = 0; j < sortedBatches.size(); ++j)
  465. sortedBatches[j]->draw(renderer);
  466. }
  467. renderer->setColorWrite(true);
  468. renderer->setDepthBias(0.0f, 0.0f);
  469. }
  470. // Light volume batches are not sorted as there should be only one of them
  471. if (queue.mBatches.size())
  472. {
  473. clearLastParameterSources();
  474. if (deferred)
  475. {
  476. renderer->setRenderTarget(0, renderBuffer);
  477. renderer->setTexture(TU_DIFFBUFFER, diffBuffer);
  478. }
  479. else
  480. renderer->setRenderTarget(0, diffBuffer);
  481. renderer->setTexture(TU_NORMALBUFFER, normalBuffer);
  482. renderer->setTexture(TU_DEPTHBUFFER, depthBuffer);
  483. renderer->resetDepthStencil();
  484. renderer->setViewport(mScreenRect);
  485. for (unsigned j = 0; j < queue.mBatches.size(); ++j)
  486. {
  487. mPipeline->setupLightBatch(queue.mBatches[j]);
  488. queue.mBatches[j].draw(renderer);
  489. }
  490. // If was the last split of a split point light, clear the stencil by rendering the point light again
  491. if ((queue.mLastSplit) && (queue.mLight->getLightType() == LIGHT_SPLITPOINT))
  492. mPipeline->drawSplitLightToStencil(*mCamera, queue.mLight, true);
  493. }
  494. }
  495. // Non-shadowed lights
  496. if (mNoShadowLightQueueSorted.size())
  497. {
  498. clearLastParameterSources();
  499. if (deferred)
  500. {
  501. renderer->setRenderTarget(0, renderBuffer);
  502. renderer->setTexture(TU_DIFFBUFFER, diffBuffer);
  503. }
  504. else
  505. renderer->setRenderTarget(0, diffBuffer);
  506. renderer->setTexture(TU_NORMALBUFFER, normalBuffer);
  507. renderer->setTexture(TU_DEPTHBUFFER, depthBuffer);
  508. renderer->resetDepthStencil();
  509. renderer->setViewport(mScreenRect);
  510. for (unsigned i = 0; i < mNoShadowLightQueueSorted.size(); ++i)
  511. {
  512. mPipeline->setupLightBatch(*mNoShadowLightQueueSorted[i]);
  513. mNoShadowLightQueueSorted[i]->draw(renderer);
  514. }
  515. }
  516. }
  517. {
  518. // Render forward passes
  519. PROFILE(View_RenderForward);
  520. clearLastParameterSources();
  521. renderer->setStencilTest(false);
  522. renderer->setRenderTarget(0, renderBuffer);
  523. renderer->setTexture(TU_DIFFBUFFER, 0);
  524. renderer->setTexture(TU_NORMALBUFFER, 0);
  525. renderer->setTexture(TU_DEPTHBUFFER, 0);
  526. renderer->setViewport(mScreenRect);
  527. if (!deferred)
  528. renderer->clear(CLEAR_COLOR, mZone->getFogColor());
  529. for (unsigned i = 0; i < mAmbientQueueSorted.size(); ++i)
  530. mAmbientQueueSorted[i]->draw(renderer);
  531. for (unsigned i = 0; i < mForwardQueueSorted.size(); ++i)
  532. {
  533. if (mForwardQueueSorted[i]->mForwardLight)
  534. optimizeLightByScissor(mForwardQueueSorted[i]->mForwardLight);
  535. else
  536. {
  537. renderer->setScissorTest(false);
  538. // Bind the light accumulation buffer for material pass of prepass mode
  539. if (!deferred)
  540. renderer->setTexture(TU_LIGHTBUFFER, diffBuffer);
  541. }
  542. mForwardQueueSorted[i]->draw(renderer);
  543. }
  544. renderer->setScissorTest(false);
  545. for (unsigned i = 0; i < mPostOpaqueQueueSorted.size(); ++i)
  546. mPostOpaqueQueueSorted[i]->draw(renderer);
  547. }
  548. {
  549. // Render transparent objects last (both ambient & additive lighting)
  550. PROFILE(View_RenderTransparent);
  551. for (unsigned i = 0; i < mTransparentQueueSorted.size(); ++i)
  552. {
  553. optimizeLightByScissor(mTransparentQueueSorted[i]->mForwardLight);
  554. mTransparentQueueSorted[i]->draw(renderer);
  555. }
  556. }
  557. // Render edge filter now if enabled
  558. if (edgeFilter)
  559. {
  560. PROFILE(View_RenderEdgeFilter);
  561. float invWidth = 0.5f / gBufferWidth;
  562. float invHeight = 0.5f / gBufferHeight;
  563. renderer->setAlphaTest(false);
  564. renderer->setBlendMode(BLEND_REPLACE);
  565. renderer->setDepthTest(CMP_ALWAYS);
  566. renderer->setDepthWrite(false);
  567. renderer->setScissorTest(false);
  568. renderer->setStencilTest(false);
  569. renderer->setRenderTarget(0, mRenderTarget);
  570. renderer->setTexture(TU_DIFFBUFFER, renderer->getScreenBuffer());
  571. renderer->setPixelShaderConstant(getPSRegister(PSP_SAMPLEOFFSETS), Vector4(invWidth, -invWidth, invHeight, -invHeight));
  572. renderer->setPixelShaderConstant(getPSRegister(PSP_EDGEFILTERPARAMS), Vector4(filterParams.mThreshold,
  573. filterParams.mFilterStep, filterParams.mMaxFilter, filterParams.mMaxScale));
  574. renderer->setViewport(mScreenRect);
  575. mPipeline->drawFullScreenQuad(*mCamera, mPipeline->getVertexShader("EdgeFilter"),
  576. mPipeline->getPixelShader("EdgeFilter"), false);
  577. }
  578. }