ForwardView.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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 "Material.h"
  28. #include "Pipeline.h"
  29. #include "PixelShader.h"
  30. #include "Profiler.h"
  31. #include "Renderer.h"
  32. #include "Texture2D.h"
  33. #include "VertexShader.h"
  34. #include "View.h"
  35. #include "DebugNew.h"
  36. void View::getBatchesForward()
  37. {
  38. // Go through geometries for ambient batches
  39. {
  40. PROFILE(View_GetAmbientBatches);
  41. for (unsigned i = 0; i < mGeometries.size(); ++i)
  42. {
  43. GeometryNode* node = mGeometries[i];
  44. unsigned numBatches = node->getNumBatches();
  45. for (unsigned j = 0; j < numBatches; ++j)
  46. {
  47. Geometry* geom = node->getBatchGeometry(j);
  48. if (!geom)
  49. continue;
  50. MaterialTechnique* tech = getMaterialTechnique(node, j);
  51. if (!tech)
  52. continue;
  53. // Check here if the material technique refers to a render target texture with camera(s) attached
  54. // Only check this for the main view (null rendertarget)
  55. if ((!mRenderTarget) && (tech->getAuxViewFrameNumber() != mFrame.mFrameNumber))
  56. checkTechniqueForAuxView(tech);
  57. Batch newBatch;
  58. newBatch.mNode = node;
  59. newBatch.mCamera = mCamera;
  60. newBatch.mDistance = node->getDistance();
  61. newBatch.mGeometry = geom;
  62. newBatch.mBatchIndex = j;
  63. MaterialPass* pass = tech->getPass(PASS_AMBIENT);
  64. if (pass)
  65. {
  66. mPipeline->setBatchShaders(newBatch, tech, pass);
  67. if (pass->getBlendMode() == BLEND_REPLACE)
  68. {
  69. newBatch.mHasPriority = !(pass->getAlphaTest() || pass->getAlphaMask());
  70. newBatch.calculateSortKey(true, true);
  71. mAmbientQueue.push_back(newBatch);
  72. }
  73. else
  74. {
  75. newBatch.mHasPriority = true;
  76. newBatch.calculateSortKey(false, false);
  77. mTransparentQueue.push_back(newBatch);
  78. }
  79. continue;
  80. }
  81. else
  82. {
  83. // If no ambient pass, check for postopaque (custom) pass
  84. pass = tech->getPass(PASS_POSTOPAQUE);
  85. if (pass)
  86. {
  87. newBatch.mHasPriority = false;
  88. mPipeline->setBatchShaders(newBatch, tech, pass);
  89. newBatch.calculateSortKey(true, true);
  90. mPostOpaqueQueue.push_back(newBatch);
  91. }
  92. }
  93. }
  94. }
  95. }
  96. // Go through lights
  97. {
  98. PROFILE_MULTIPLE(View_GetLightBatches, mLights.size());
  99. unsigned lightQueueCount = 0;
  100. for (unsigned i = 0; i < mLights.size(); ++i)
  101. {
  102. Light* light = mLights[i];
  103. unsigned splits = processLight(light);
  104. if (!splits)
  105. continue;
  106. // For split point lights, check that a transparent object is not lit multiple times
  107. bool splitPointLight = sSplitLights[0]->getLightType() == LIGHT_SPLITPOINT;
  108. static std::set<GeometryNode*> litTransparencies;
  109. litTransparencies.clear();
  110. // Negative (darkening) lighting flag
  111. bool negative = mLights[i]->isNegative();
  112. // Prepare lit object + shadow caster queues for each split
  113. if (mLightQueues.size() < lightQueueCount + splits)
  114. mLightQueues.resize(lightQueueCount + splits);
  115. unsigned prevLightQueueCount = lightQueueCount;
  116. for (unsigned j = 0; j < splits; ++j)
  117. {
  118. LightBatchQueue& lightQueue = mLightQueues[lightQueueCount];
  119. lightQueue.mLight = sSplitLights[j];
  120. lightQueue.mShadowBatches.clear();
  121. lightQueue.mBatches.clear();
  122. lightQueue.mLastSplit = false;
  123. // Loop through shadow casters
  124. Camera& shadowCamera = sSplitLights[j]->getShadowCamera();
  125. for (unsigned k = 0; k < sShadowCasters[j].size(); ++k)
  126. {
  127. GeometryNode* node = sShadowCasters[j][k];
  128. unsigned numBatches = node->getNumBatches();
  129. for (unsigned l = 0; l < numBatches; ++l)
  130. {
  131. MaterialTechnique* tech = getMaterialTechnique(node, l);
  132. if (!tech)
  133. continue;
  134. MaterialPass* pass = tech->getPass(PASS_SHADOW);
  135. // Skip if material has no shadow pass
  136. if (!pass)
  137. continue;
  138. Geometry* geom = node->getBatchGeometry(l);
  139. if (!geom)
  140. continue;
  141. // Build the shadow batch
  142. // Note: shadow cameras are never parented, so can simply use getPosition()
  143. Batch shadowBatch;
  144. shadowBatch.mNode = node;
  145. shadowBatch.mCamera = &shadowCamera;
  146. shadowBatch.mDistance = (node->getWorldPosition() - shadowCamera.getPosition()).getLengthFast();
  147. shadowBatch.mGeometry = geom;
  148. shadowBatch.mBatchIndex = l;
  149. shadowBatch.mForwardLight = sSplitLights[j];
  150. shadowBatch.mHasPriority = !(pass->getAlphaTest() || pass->getAlphaMask());
  151. mPipeline->setBatchShaders(shadowBatch, tech, pass);
  152. shadowBatch.calculateSortKey(true, true);
  153. lightQueue.mShadowBatches.push_back(shadowBatch);
  154. }
  155. }
  156. // Loop through lit geometries
  157. for (unsigned k = 0; k < sLitGeometries[j].size(); ++k)
  158. {
  159. GeometryNode* node = sLitGeometries[j][k];
  160. unsigned numBatches = node->getNumBatches();
  161. for (unsigned l = 0; l < numBatches; ++l)
  162. {
  163. MaterialTechnique* tech = getMaterialTechnique(node, l);
  164. if (!tech)
  165. continue;
  166. MaterialPass* pass = 0;
  167. if (!negative)
  168. pass = tech->getPass(PASS_LIGHT);
  169. else
  170. pass = tech->getPass(PASS_NEGATIVE);
  171. // Skip if material does not receive light
  172. if (!pass)
  173. continue;
  174. Geometry* geom = node->getBatchGeometry(l);
  175. if (!geom)
  176. continue;
  177. // Build the lit batch
  178. Batch newBatch;
  179. newBatch.mNode = node;
  180. newBatch.mCamera = mCamera;
  181. newBatch.mDistance = node->getDistance();
  182. newBatch.mGeometry = geom;
  183. newBatch.mBatchIndex = l;
  184. newBatch.mForwardLight = sSplitLights[j];
  185. // Check from the ambient pass whether the object is opaque
  186. MaterialPass* ambientPass = tech->getPass(PASS_AMBIENT);
  187. if ((!ambientPass) || (ambientPass->getBlendMode() == BLEND_REPLACE))
  188. {
  189. mPipeline->setBatchShaders(newBatch, tech, pass);
  190. newBatch.calculateSortKey(true, true);
  191. if (!negative)
  192. lightQueue.mBatches.push_back(newBatch);
  193. else
  194. mNegativeQueue.push_back(newBatch);
  195. }
  196. else
  197. {
  198. // Transparent: disable shadows
  199. // Prevent multi-lighting by a split point light
  200. // (transparent rendering can not handle the needed stencil masking)
  201. if (splitPointLight)
  202. {
  203. if (litTransparencies.find(node) != litTransparencies.end())
  204. continue;
  205. // Use the original light instead of the split one, to choose correct scissor
  206. newBatch.mForwardLight = mLights[i];
  207. }
  208. // If light is negative, bias the distance slightly to ensure it has priority
  209. if (negative)
  210. newBatch.mDistance -= 0.001f;
  211. mPipeline->setBatchShaders(newBatch, tech, pass, false);
  212. newBatch.calculateSortKey(false, false);
  213. mTransparentQueue.push_back(newBatch);
  214. }
  215. }
  216. if (splitPointLight)
  217. litTransparencies.insert(node);
  218. }
  219. // Store light & its shadow batches only if lit geometries exist
  220. if (sLitGeometries[j].size())
  221. lightQueueCount++;
  222. }
  223. // Mark the last split
  224. if (lightQueueCount != prevLightQueueCount)
  225. mLightQueues[lightQueueCount - 1].mLastSplit = true;
  226. }
  227. // Resize the light queue vector now that final size is known
  228. mLightQueues.resize(lightQueueCount);
  229. }
  230. // Finally sort the batches
  231. {
  232. PROFILE(View_SortBatches);
  233. sortBatches(mAmbientQueue, mAmbientQueueSorted);
  234. sortBatches(mNegativeQueue, mNegativeQueueSorted);
  235. sortBatches(mPostOpaqueQueue, mPostOpaqueQueueSorted);
  236. sortBatches(mTransparentQueue, mTransparentQueueSorted);
  237. for (unsigned i = 0; i < mLightQueues.size(); ++i)
  238. {
  239. sortBatches(mLightQueues[i].mShadowBatches, mLightQueues[i].mSortedShadowBatches);
  240. sortBatches(mLightQueues[i].mBatches, mLightQueues[i].mSortedBatches);
  241. }
  242. }
  243. }
  244. void View::renderBatchesForward()
  245. {
  246. Renderer* renderer = mPipeline->getRenderer();
  247. {
  248. // Render opaque objects' ambient & negative lighting
  249. PROFILE(View_RenderAmbient);
  250. clearLastParameterSources();
  251. renderer->setColorWrite(true);
  252. renderer->setFillMode(FILL_SOLID);
  253. renderer->setStencilTest(false);
  254. renderer->setRenderTarget(0, mRenderTarget);
  255. renderer->setDepthStencil(mDepthStencil);
  256. renderer->setViewport(mScreenRect);
  257. renderer->clear(CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL, mZone->getFogColor());
  258. for (unsigned i = 0; i < mAmbientQueueSorted.size(); ++i)
  259. mAmbientQueueSorted[i]->draw(renderer);
  260. for (unsigned i = 0; i < mNegativeQueueSorted.size(); ++i)
  261. {
  262. optimizeLightByScissor(mNegativeQueueSorted[i]->mForwardLight);
  263. mNegativeQueueSorted[i]->draw(renderer);
  264. }
  265. }
  266. {
  267. // Render shadow maps + opaque objects' shadowed additive lighting
  268. PROFILE(View_RenderLights);
  269. for (unsigned i = 0; i < mLightQueues.size(); ++i)
  270. {
  271. LightBatchQueue& queue = mLightQueues[i];
  272. if (queue.mLight->getShadowMap())
  273. {
  274. PROFILE(View_RenderShadowMap);
  275. Texture2D* shadowMap = queue.mLight->getShadowMap();
  276. clearLastParameterSources();
  277. renderer->setColorWrite(false);
  278. renderer->setStencilTest(false);
  279. renderer->setTexture(TU_SHADOWMAP, 0);
  280. renderer->setRenderTarget(0, shadowMap->getRenderSurface()->getLinkedRenderTarget());
  281. renderer->setDepthStencil(shadowMap);
  282. renderer->clear(CLEAR_DEPTH);
  283. // Set shadow depth bias
  284. BiasParameters parameters = queue.mLight->getShadowBias();
  285. renderer->setDepthBias(parameters.mConstantBias, parameters.mSlopeScaledBias);
  286. // Set a scissor rectangle to match possible shadow map size reduction by out-zooming
  287. // However, do not do this for point lights
  288. if (queue.mLight->getLightType() != LIGHT_SPLITPOINT)
  289. {
  290. float zoom = min(queue.mLight->getShadowCamera().getZoom(),
  291. (float)(shadowMap->getWidth() - 2) / (float)shadowMap->getWidth());
  292. Rect zoomRect(Vector2(-1.0f, -1.0f) * zoom, Vector2(1.0f, 1.0f) * zoom);
  293. renderer->setScissorTest(true, zoomRect, false);
  294. }
  295. else
  296. renderer->setScissorTest(false);
  297. std::vector<Batch*>& sortedBatches = queue.mSortedShadowBatches;
  298. if (sortedBatches.size())
  299. {
  300. for (unsigned j = 0; j < sortedBatches.size(); ++j)
  301. sortedBatches[j]->draw(renderer);
  302. }
  303. renderer->setColorWrite(true);
  304. renderer->setDepthBias(0.0f, 0.0f);
  305. }
  306. std::vector<Batch*>& sortedBatches = queue.mSortedBatches;
  307. LightType type = queue.mLight->getLightType();
  308. if (sortedBatches.size())
  309. {
  310. clearLastParameterSources();
  311. renderer->setRenderTarget(0, mRenderTarget);
  312. renderer->setDepthStencil(mDepthStencil);
  313. renderer->setViewport(mScreenRect);
  314. optimizeLightByScissor(queue.mLight);
  315. // If this is a split point or dir. light, mark the split volume to the stencil
  316. if ((type == LIGHT_DIRECTIONAL) || (type == LIGHT_SPLITPOINT))
  317. mPipeline->drawSplitLightToStencil(*mCamera, queue.mLight);
  318. for (unsigned j = 0; j < sortedBatches.size(); ++j)
  319. sortedBatches[j]->draw(renderer);
  320. }
  321. // Clear the stencil buffer after the last split
  322. if ((queue.mLastSplit) && ((type == LIGHT_DIRECTIONAL) || (type == LIGHT_SPLITPOINT)))
  323. {
  324. renderer->setScissorTest(false);
  325. mPipeline->drawSplitLightToStencil(*mCamera, queue.mLight, true);
  326. }
  327. }
  328. }
  329. {
  330. // Render post-opaque passes
  331. PROFILE(View_RenderForward);
  332. clearLastParameterSources();
  333. renderer->setScissorTest(false);
  334. renderer->setStencilTest(false);
  335. renderer->setRenderTarget(0, mRenderTarget);
  336. renderer->setViewport(mScreenRect);
  337. renderer->setDepthStencil(mDepthStencil);
  338. for (unsigned i = 0; i < mPostOpaqueQueueSorted.size(); ++i)
  339. mPostOpaqueQueueSorted[i]->draw(renderer);
  340. }
  341. {
  342. // Render transparent objects last (both ambient & additive lighting)
  343. PROFILE(View_RenderTransparent);
  344. for (unsigned i = 0; i < mTransparentQueueSorted.size(); ++i)
  345. {
  346. optimizeLightByScissor(mTransparentQueueSorted[i]->mForwardLight);
  347. mTransparentQueueSorted[i]->draw(renderer);
  348. }
  349. }
  350. }