Batch.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  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 "Camera.h"
  25. #include "Geometry.h"
  26. #include "Graphics.h"
  27. #include "GraphicsImpl.h"
  28. #include "Light.h"
  29. #include "Material.h"
  30. #include "Renderer.h"
  31. #include "PixelShader.h"
  32. #include "Profiler.h"
  33. #include "Sort.h"
  34. #include "Technique.h"
  35. #include "Texture2D.h"
  36. #include "VertexBuffer.h"
  37. #include "VertexShader.h"
  38. #include "DebugNew.h"
  39. inline bool CompareBatchesFrontToBack(Batch* lhs, Batch* rhs)
  40. {
  41. if (lhs->sortKey_ == rhs->sortKey_)
  42. return lhs->distance_ < rhs->distance_;
  43. else
  44. return lhs->sortKey_ < rhs->sortKey_;
  45. }
  46. inline bool CompareBatchesBackToFront(Batch* lhs, Batch* rhs)
  47. {
  48. if (lhs->distance_ == rhs->distance_)
  49. return lhs->sortKey_ < rhs->sortKey_;
  50. else
  51. return lhs->distance_ > rhs->distance_;
  52. }
  53. inline bool CompareInstancesFrontToBack(const InstanceData& lhs, const InstanceData& rhs)
  54. {
  55. return lhs.distance_ < rhs.distance_;
  56. }
  57. void Batch::CalculateSortKey()
  58. {
  59. unsigned light = (*((unsigned*)&light_) / sizeof(Light)) & 0x7fff;
  60. unsigned pass = (*((unsigned*)&pass_) / sizeof(Pass)) & 0xffff;
  61. unsigned material = (*((unsigned*)&material_) / sizeof(Material)) & 0xffff;
  62. unsigned geometry = (*((unsigned*)&geometry_) / sizeof(Geometry)) & 0xffff;
  63. if (hasPriority_)
  64. light |= 0x8000;
  65. sortKey_ = (((unsigned long long)light) << 48) || (((unsigned long long)pass) << 32) ||
  66. (((unsigned long long)material) << 16) || geometry;
  67. }
  68. void Batch::Prepare(Graphics* graphics, bool SetModelTransform) const
  69. {
  70. if ((!vertexShader_) || (!pixelShader_))
  71. return;
  72. // Set pass / material-specific renderstates
  73. if ((pass_) && (material_))
  74. {
  75. if (pass_->GetAlphaTest())
  76. graphics->SetAlphaTest(true, CMP_GREATEREQUAL, 0.5f);
  77. else
  78. graphics->SetAlphaTest(false);
  79. graphics->SetBlendMode(pass_->GetBlendMode());
  80. graphics->SetCullMode(pass_->GetType() != PASS_SHADOW ? material_->GetCullMode() : material_->GetShadowCullMode());
  81. graphics->SetDepthTest(pass_->GetDepthTestMode());
  82. graphics->SetDepthWrite(pass_->GetDepthWrite());
  83. const Vector<SharedPtr<Texture> >& textures = material_->GetTextures();
  84. if (pixelShader_->HasTextureUnit(TU_DIFFUSE))
  85. graphics->SetTexture(TU_DIFFUSE, textures[TU_DIFFUSE]);
  86. if (pixelShader_->HasTextureUnit(TU_NORMAL))
  87. graphics->SetTexture(TU_NORMAL, textures[TU_NORMAL]);
  88. if (pixelShader_->HasTextureUnit(TU_SPECULAR))
  89. graphics->SetTexture(TU_SPECULAR, textures[TU_SPECULAR]);
  90. if (pixelShader_->HasTextureUnit(TU_DETAIL))
  91. graphics->SetTexture(TU_DETAIL, textures[TU_DETAIL]);
  92. if (pixelShader_->HasTextureUnit(TU_ENVIRONMENT))
  93. graphics->SetTexture(TU_ENVIRONMENT, textures[TU_ENVIRONMENT]);
  94. if (!light_)
  95. {
  96. if (pixelShader_->HasTextureUnit(TU_EMISSIVE))
  97. graphics->SetTexture(TU_EMISSIVE, textures[TU_EMISSIVE]);
  98. }
  99. }
  100. // Set light-related textures
  101. Texture2D* shadowMap = 0;
  102. if (light_)
  103. {
  104. shadowMap = light_->GetShadowMap();
  105. if ((shadowMap) && (pixelShader_->HasTextureUnit(TU_SHADOWMAP)))
  106. graphics->SetTexture(TU_SHADOWMAP, shadowMap);
  107. if (pixelShader_->HasTextureUnit(TU_LIGHTRAMP))
  108. graphics->SetTexture(TU_LIGHTRAMP, light_->GetRampTexture());
  109. if (pixelShader_->HasTextureUnit(TU_LIGHTSPOT))
  110. graphics->SetTexture(TU_LIGHTSPOT, light_->GetShapeTexture());
  111. }
  112. // Set shaders
  113. graphics->SetShaders(vertexShader_, pixelShader_);
  114. // Set viewport parameters
  115. if (vertexShader_->NeedParameterUpdate(VSP_CAMERAPOS, camera_))
  116. graphics->SetVertexShaderParameter(VSP_CAMERAPOS, camera_->GetWorldPosition());
  117. if (vertexShader_->NeedParameterUpdate(VSP_CAMERAROT, camera_))
  118. graphics->SetVertexShaderParameter(VSP_CAMERAROT, camera_->GetWorldTransform().GetRotationMatrix());
  119. if (vertexShader_->NeedParameterUpdate(VSP_DEPTHMODE, camera_))
  120. {
  121. Vector4 depthMode = Vector4::ZERO;
  122. if (camera_->IsOrthographic())
  123. depthMode.z_ = 1.0f;
  124. else
  125. depthMode.w_ = 1.0f / camera_->GetFarClip();
  126. graphics->SetVertexShaderParameter(VSP_DEPTHMODE, depthMode);
  127. }
  128. // Set transforms
  129. if ((SetModelTransform) && (vertexShader_->NeedParameterUpdate(VSP_MODEL, worldTransform_)))
  130. graphics->SetVertexShaderParameter(VSP_MODEL, *worldTransform_);
  131. if ((shadowMap) && (vertexShader_->NeedParameterUpdate(VSP_SHADOWPROJ, light_)))
  132. {
  133. Camera* shadowCamera = light_->GetShadowCamera();
  134. Matrix4x3 shadowView(shadowCamera->GetInverseWorldTransform());
  135. Matrix4 shadowProj(shadowCamera->GetProjection());
  136. Matrix4 texAdjust(Matrix4::IDENTITY);
  137. float offset = 0.5f + 0.5f / (float)shadowMap->GetWidth();
  138. texAdjust.SetTranslation(Vector3(offset, offset, 0.0f));
  139. texAdjust.SetScale(Vector3(0.5f, -0.5f, 1.0f));
  140. graphics->SetVertexShaderParameter(VSP_SHADOWPROJ, texAdjust * shadowProj * shadowView);
  141. }
  142. if ((light_) && (vertexShader_->NeedParameterUpdate(VSP_SPOTPROJ, light_)))
  143. {
  144. const Matrix4x3& transform = light_->GetWorldTransform();
  145. Matrix4x3 spotView(transform.GetTranslation(), transform.GetRotation(), 1.0f);
  146. Matrix4 spotProj(Matrix4::ZERO);
  147. // Make the projected light slightly smaller than the shadow map to prevent light spill
  148. float h = 1.005f / tanf(light_->GetFov() * M_DEGTORAD * 0.5f);
  149. float w = h / light_->GetAspectRatio();
  150. spotProj.m00_ = w;
  151. spotProj.m11_ = h;
  152. spotProj.m22_ = 1.0f / Max(light_->GetRange(), M_EPSILON);
  153. spotProj.m32_ = 1.0f;
  154. Matrix4 texAdjust(Matrix4::IDENTITY);
  155. texAdjust.SetTranslation(Vector3(0.5f, 0.5f, 0.0f));
  156. texAdjust.SetScale(Vector3(0.5f, -0.5f, 1.0f));
  157. graphics->SetVertexShaderParameter(VSP_SPOTPROJ, texAdjust * spotProj * spotView.GetInverse());
  158. }
  159. if (overrideView_)
  160. {
  161. // If we override the view matrix, also disable any projection jittering
  162. /// \todo This may not be correct in all cases (skybox rendering?)
  163. if (vertexShader_->NeedParameterUpdate(VSP_VIEWPROJ, &Matrix4x3::IDENTITY))
  164. graphics->SetVertexShaderParameter(VSP_VIEWPROJ, camera_->GetProjection(false));
  165. }
  166. else
  167. {
  168. if (vertexShader_->NeedParameterUpdate(VSP_VIEWPROJ, camera_))
  169. graphics->SetVertexShaderParameter(VSP_VIEWPROJ, camera_->GetProjection() *
  170. camera_->GetInverseWorldTransform());
  171. }
  172. // Set material's vertex shader parameters
  173. if (material_)
  174. {
  175. const Map<VSParameter, Vector4>& parameters = material_->GetVertexShaderParameters();
  176. for (Map<VSParameter, Vector4>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
  177. {
  178. if (vertexShader_->NeedParameterUpdate(i->first_, material_))
  179. graphics->SetVertexShaderParameter(i->first_, i->second_);
  180. }
  181. }
  182. if (vertexShader_->NeedParameterUpdate(VSP_VIEWRIGHTVECTOR, camera_))
  183. graphics->SetVertexShaderParameter(VSP_VIEWRIGHTVECTOR, camera_->GetRightVector());
  184. if (vertexShader_->NeedParameterUpdate(VSP_VIEWUPVECTOR, camera_))
  185. graphics->SetVertexShaderParameter(VSP_VIEWUPVECTOR, camera_->GetUpVector());
  186. // Set skinning transforms
  187. if ((shaderData_) && (shaderDataSize_))
  188. {
  189. if (vertexShader_->NeedParameterUpdate(VSP_SKINMATRICES, shaderData_))
  190. graphics->SetVertexShaderParameter(VSP_SKINMATRICES, (const float*)shaderData_, shaderDataSize_);
  191. }
  192. // Set light-related parameters
  193. if (light_)
  194. {
  195. if (pixelShader_->NeedParameterUpdate(PSP_LIGHTATTEN, light_))
  196. {
  197. Vector4 light_Atten(1.0f / Max(light_->GetRange(), M_EPSILON), 0.0f, 0.0f, 0.0f);
  198. graphics->SetPixelShaderParameter(PSP_LIGHTATTEN, light_Atten);
  199. }
  200. if (pixelShader_->NeedParameterUpdate(PSP_LIGHTCOLOR, light_))
  201. {
  202. float fade = 1.0f;
  203. float fadeEnd = light_->GetDrawDistance();
  204. float fadeStart = light_->GetFadeDistance();
  205. // Do fade calculation for light if both fade & draw distance defined
  206. if ((light_->GetLightType() != LIGHT_DIRECTIONAL) && (fadeEnd > 0.0f) && (fadeStart > 0.0f) && (fadeStart < fadeEnd))
  207. fade = Min(1.0f - (light_->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
  208. graphics->SetPixelShaderParameter(PSP_LIGHTCOLOR, Vector4(light_->GetColor().GetRGB(),
  209. light_->GetSpecularIntensity()) * fade);
  210. }
  211. if (pixelShader_->NeedParameterUpdate(PSP_LIGHTDIR, light_))
  212. graphics->SetPixelShaderParameter(PSP_LIGHTDIR, light_->GetWorldRotation() * Vector3::BACK);
  213. if (pixelShader_->NeedParameterUpdate(PSP_LIGHTPOS, light_))
  214. graphics->SetPixelShaderParameter(PSP_LIGHTPOS, light_->GetWorldPosition() - camera_->GetWorldPosition());
  215. if (pixelShader_->NeedParameterUpdate(PSP_LIGHTSPLITS, light_))
  216. {
  217. float nearFadeRange = light_->GetNearFadeRange();
  218. float farFadeRange = light_->GetFarFadeRange();
  219. float nearFadeStart = light_->GetNearSplit() - nearFadeRange;
  220. float farFadeStart = light_->GetFarSplit() - farFadeRange;
  221. float depthRange = camera_->GetFarClip();
  222. graphics->SetPixelShaderParameter(PSP_LIGHTSPLITS, Vector4(nearFadeStart / depthRange, 1.0f / (nearFadeRange / depthRange),
  223. farFadeStart / depthRange, 1.0f / (farFadeRange / depthRange)));
  224. }
  225. if (pixelShader_->NeedParameterUpdate(PSP_LIGHTVECROT, light_))
  226. {
  227. Matrix4x3 light_VecRot;
  228. // Use original light if available (split lights)
  229. Light* original = light_->GetOriginalLight();
  230. if (!original)
  231. light_VecRot = Matrix4x3(Vector3::ZERO, light_->GetWorldRotation(), Vector3::UNITY);
  232. else
  233. light_VecRot = Matrix4x3(Vector3::ZERO, original->GetWorldRotation(), Vector3::UNITY);
  234. graphics->SetPixelShaderParameter(PSP_LIGHTVECROT, light_VecRot);
  235. }
  236. }
  237. // Set material's pixel shader parameters
  238. if (material_)
  239. {
  240. const Map<PSParameter, Vector4>& parameters = material_->GetPixelShaderParameters();
  241. for (Map<PSParameter, Vector4>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
  242. {
  243. if (pixelShader_->NeedParameterUpdate(i->first_, material_))
  244. graphics->SetPixelShaderParameter(i->first_, i->second_);
  245. }
  246. }
  247. // Set shadow & spotlight projection parameters
  248. if (shadowMap)
  249. {
  250. if (pixelShader_->NeedParameterUpdate(PSP_SAMPLEOFFSETS, shadowMap))
  251. {
  252. float invWidth = 1.0f / (float)shadowMap->GetWidth();
  253. graphics->SetPixelShaderParameter(PSP_SAMPLEOFFSETS, Vector4(0.5f * invWidth, -0.5f * invWidth, 0.0f, 0.0f));
  254. }
  255. if (pixelShader_->NeedParameterUpdate(PSP_SHADOWINTENSITY, light_))
  256. {
  257. float intensity = light_->GetShadowIntensity();
  258. float fadeStart = light_->GetShadowFadeDistance();
  259. float fadeEnd = light_->GetShadowDistance();
  260. if ((fadeStart > 0.0f) && (fadeEnd > 0.0f) && (fadeEnd > fadeStart))
  261. intensity = Lerp(intensity, 1.0f, Clamp((light_->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 0.0f, 1.0f));
  262. float pcfValues = (1.0f - intensity) * 0.25f;
  263. graphics->SetPixelShaderParameter(PSP_SHADOWINTENSITY, Vector4(pcfValues, intensity, 0.0f, 0.0f));
  264. }
  265. if (pixelShader_->NeedParameterUpdate(PSP_SHADOWPROJ, light_))
  266. {
  267. Camera* shadowCamera = light_->GetShadowCamera();
  268. Matrix4x3 shadowView(shadowCamera->GetInverseWorldTransform());
  269. Matrix4 shadowProj(shadowCamera->GetProjection());
  270. Matrix4x3 viewPos(Matrix4x3::IDENTITY);
  271. viewPos.SetTranslation(camera_->GetWorldPosition());
  272. Matrix4 texAdjust(Matrix4::IDENTITY);
  273. float offset = 0.5f + 0.5f / (float)shadowMap->GetWidth();
  274. texAdjust.SetTranslation(Vector3(offset, offset, 0.0f));
  275. texAdjust.SetScale(Vector3(0.5f, -0.5f, 1.0f));
  276. graphics->SetPixelShaderParameter(PSP_SHADOWPROJ, texAdjust * shadowProj * shadowView * viewPos);
  277. }
  278. }
  279. if ((light_) && (pixelShader_->NeedParameterUpdate(PSP_SPOTPROJ, light_)))
  280. {
  281. Matrix4x3 spotView(light_->GetWorldPosition(), light_->GetWorldRotation(), 1.0f);
  282. Matrix4 spotProj(Matrix4::IDENTITY);
  283. // Make the projected light slightly smaller than the shadow map to prevent light spill
  284. float h = 1.005f / tanf(light_->GetFov() * M_DEGTORAD * 0.5f);
  285. float w = h / light_->GetAspectRatio();
  286. spotProj.m00_ = w;
  287. spotProj.m11_ = h;
  288. spotProj.m22_ = 1.0f / Max(light_->GetRange(), M_EPSILON);
  289. spotProj.m32_ = 1.0f;
  290. Matrix4x3 viewPos(Matrix4x3::IDENTITY);
  291. viewPos.SetTranslation(camera_->GetWorldPosition());
  292. Matrix4 texAdjust(Matrix4::IDENTITY);
  293. texAdjust.SetTranslation(Vector3(0.5f, 0.5f, 0.0f));
  294. texAdjust.SetScale(Vector3(0.5f, -0.5f, 1.0f));
  295. graphics->SetPixelShaderParameter(PSP_SPOTPROJ, texAdjust * spotProj * spotView.GetInverse() * viewPos);
  296. }
  297. }
  298. void Batch::Draw(Graphics* graphics) const
  299. {
  300. Prepare(graphics);
  301. geometry_->Draw(graphics);
  302. }
  303. void BatchGroup::SetTransforms(void* lockedData, unsigned& freeIndex)
  304. {
  305. // Do not use up buffer space if not going to draw as instanced
  306. if (instances_.Size() < MIN_INSTANCES)
  307. return;
  308. startIndex_ = freeIndex;
  309. Matrix4x3* dest = (Matrix4x3*)lockedData;
  310. dest += freeIndex;
  311. for (unsigned i = 0; i < instances_.Size(); ++i)
  312. *dest++ = *instances_[i].worldTransform_;
  313. freeIndex += instances_.Size();
  314. }
  315. void BatchGroup::Draw(Graphics* graphics, VertexBuffer* buffer) const
  316. {
  317. if (!instances_.Size())
  318. return;
  319. // Construct a temporary batch for rendering
  320. Batch batch;
  321. batch.geometry_ = geometry_;
  322. batch.material_ = material_;
  323. batch.pass_ = pass_;
  324. batch.vertexShader_ = vertexShader_;
  325. batch.pixelShader_ = pixelShader_;
  326. batch.camera_ = camera_;
  327. batch.light_ = light_;
  328. batch.vertexShaderIndex_ = vertexShaderIndex_;
  329. // Draw as individual instances if below minimum size, or if instancing not supported
  330. if ((instances_.Size() < MIN_INSTANCES) || (!buffer))
  331. {
  332. batch.Prepare(graphics, false);
  333. graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
  334. graphics->SetVertexBuffers(geometry_->GetVertexBuffers(), geometry_->GetVertexElementMasks());
  335. for (unsigned i = 0; i < instances_.Size(); ++i)
  336. {
  337. if (vertexShader_->NeedParameterUpdate(VSP_MODEL, instances_[i].worldTransform_))
  338. graphics->SetVertexShaderParameter(VSP_MODEL, *instances_[i].worldTransform_);
  339. graphics->Draw(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
  340. geometry_->GetVertexStart(), geometry_->GetVertexCount());
  341. }
  342. }
  343. else
  344. {
  345. // Switch to the instancing vertex shader
  346. // The indexing is different in the forward lit passes
  347. Vector<SharedPtr<VertexShader> >& vertexShaders = pass_->GetVertexShaders();
  348. Vector<SharedPtr<PixelShader> >& pixelShaders = pass_->GetPixelShaders();
  349. PassType type = pass_->GetType();
  350. if ((type != PASS_LITBASE) && (type != PASS_LIGHT))
  351. batch.vertexShader_ = vertexShaders[vertexShaderIndex_ + GEOM_INSTANCED];
  352. else
  353. batch.vertexShader_ = vertexShaders[vertexShaderIndex_ + GEOM_INSTANCED * MAX_LIGHT_VS_VARIATIONS];
  354. batch.Prepare(graphics, false);
  355. // Get the geometry vertex buffers, then add the instancing stream buffer
  356. Vector<SharedPtr<VertexBuffer> > vertexBuffers = geometry_->GetVertexBuffers();
  357. Vector<unsigned> elementMasks = geometry_->GetVertexElementMasks();
  358. vertexBuffers.Push(SharedPtr<VertexBuffer>(buffer));
  359. elementMasks.Push(buffer->GetElementMask());
  360. // No stream offset support, instancing buffer not pre-filled with transforms: have to lock and fill now
  361. if (startIndex_ == M_MAX_UNSIGNED)
  362. {
  363. unsigned startIndex = 0;
  364. while (startIndex < instances_.Size())
  365. {
  366. unsigned instances = instances_.Size() - startIndex;
  367. if (instances > buffer->GetVertexCount())
  368. instances = buffer->GetVertexCount();
  369. // Lock the instance stream buffer and copy the transforms
  370. void* data = buffer->Lock(0, instances, LOCK_DISCARD);
  371. if (!data)
  372. return;
  373. Matrix4x3* dest = (Matrix4x3*)data;
  374. for (unsigned i = 0; i < instances; ++i)
  375. dest[i] = *instances_[i + startIndex].worldTransform_;
  376. buffer->Unlock();
  377. graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
  378. graphics->SetVertexBuffers(vertexBuffers, elementMasks);
  379. graphics->DrawInstanced(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
  380. geometry_->GetVertexStart(), geometry_->GetVertexCount(), instances);
  381. startIndex += instances;
  382. }
  383. }
  384. // Stream offset supported, and instancing buffer has been already filled, so just draw
  385. else
  386. {
  387. graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
  388. graphics->SetVertexBuffers(vertexBuffers, elementMasks, startIndex_);
  389. graphics->DrawInstanced(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
  390. geometry_->GetVertexStart(), geometry_->GetVertexCount(), instances_.Size());
  391. }
  392. }
  393. }
  394. void BatchQueue::Clear()
  395. {
  396. batches_.Clear();
  397. sortedPriorityBatches_.Clear();
  398. sortedBatches_.Clear();
  399. priorityBatchGroups_.Clear();
  400. batchGroups_.Clear();
  401. }
  402. void BatchQueue::AddBatch(const Batch& batch, bool noInstancing)
  403. {
  404. // If batch is something else than static, has custom view, or has per-instance shader data defined, can not instance
  405. if ((noInstancing) || (batch.geometryType_ != GEOM_STATIC) || (batch.overrideView_) || (batch.shaderData_))
  406. batches_.Push(batch);
  407. else
  408. {
  409. BatchGroupKey key;
  410. key.light_ = batch.light_;
  411. key.pass_ = batch.pass_;
  412. key.material_ = batch.material_;
  413. key.geometry_ = batch.geometry_;
  414. Map<BatchGroupKey, BatchGroup>* groups = batch.hasPriority_ ? &priorityBatchGroups_ : &batchGroups_;
  415. Map<BatchGroupKey, BatchGroup>::Iterator i = groups->Find(key);
  416. if (i == groups->End())
  417. {
  418. // Create new group
  419. BatchGroup newGroup;
  420. newGroup.geometry_ = batch.geometry_;
  421. newGroup.material_ = batch.material_;
  422. newGroup.pass_ = batch.pass_;
  423. newGroup.vertexShader_ = batch.vertexShader_;
  424. newGroup.pixelShader_ = batch.pixelShader_;
  425. newGroup.camera_ = batch.camera_;
  426. newGroup.light_ = batch.light_;
  427. newGroup.vertexShaderIndex_ = batch.vertexShaderIndex_;
  428. newGroup.instances_.Push(InstanceData(batch.worldTransform_, batch.distance_));
  429. groups->Insert(MakePair(key, newGroup));
  430. }
  431. else
  432. i->second_.instances_.Push(InstanceData(batch.worldTransform_, batch.distance_));
  433. }
  434. }
  435. void BatchQueue::SortBackToFront()
  436. {
  437. sortedPriorityBatches_.Clear();
  438. sortedBatches_.Resize(batches_.Size());
  439. for (unsigned i = 0; i < batches_.Size(); ++i)
  440. sortedBatches_[i] = &batches_[i];
  441. Sort(sortedBatches_.Begin(), sortedBatches_.End(), CompareBatchesBackToFront);
  442. }
  443. void BatchQueue::SortFrontToBack()
  444. {
  445. sortedPriorityBatches_.Clear();
  446. sortedBatches_.Clear();
  447. // Must explicitly divide into priority batches and non-priority, so that priorities do not get mixed up between
  448. // instanced and non-instanced batches
  449. for (unsigned i = 0; i < batches_.Size(); ++i)
  450. {
  451. if (batches_[i].hasPriority_)
  452. sortedPriorityBatches_.Push(&batches_[i]);
  453. else
  454. sortedBatches_.Push(&batches_[i]);
  455. }
  456. Sort(sortedPriorityBatches_.Begin(), sortedPriorityBatches_.End(), CompareBatchesFrontToBack);
  457. Sort(sortedBatches_.Begin(), sortedBatches_.End(), CompareBatchesFrontToBack);
  458. // Sort each group front to back
  459. for (Map<BatchGroupKey, BatchGroup>::Iterator i = priorityBatchGroups_.Begin(); i != priorityBatchGroups_.End(); ++i)
  460. Sort(i->second_.instances_.Begin(), i->second_.instances_.End(), CompareInstancesFrontToBack);
  461. for (Map<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
  462. Sort(i->second_.instances_.Begin(), i->second_.instances_.End(), CompareInstancesFrontToBack);
  463. }
  464. void BatchQueue::SetTransforms(void* lockedData, unsigned& freeIndex)
  465. {
  466. for (Map<BatchGroupKey, BatchGroup>::Iterator i = priorityBatchGroups_.Begin(); i != priorityBatchGroups_.End(); ++i)
  467. i->second_.SetTransforms(lockedData, freeIndex);
  468. for (Map<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
  469. i->second_.SetTransforms(lockedData, freeIndex);
  470. }
  471. unsigned BatchQueue::GetNumInstances() const
  472. {
  473. unsigned total = 0;
  474. // This is for the purpose of calculating how much space is needed in the instancing buffer. Do not add instance counts
  475. // that are below the minimum threshold for instancing
  476. for (Map<BatchGroupKey, BatchGroup>::ConstIterator i = priorityBatchGroups_.Begin(); i != priorityBatchGroups_.End(); ++i)
  477. {
  478. unsigned instances = i->second_.instances_.Size();
  479. if (instances >= MIN_INSTANCES)
  480. total += instances;
  481. }
  482. for (Map<BatchGroupKey, BatchGroup>::ConstIterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
  483. {
  484. unsigned instances = i->second_.instances_.Size();
  485. if (instances >= MIN_INSTANCES)
  486. total += instances;
  487. }
  488. return total;
  489. }