Batch.cpp 25 KB

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