Batch.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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 <cstring>
  35. #include "DebugNew.h"
  36. void Batch::calculateSortKey(bool stateHasPriority, bool frontToBack)
  37. {
  38. // Distance
  39. unsigned short distance = (unsigned short)(clamp(mDistance / mCamera->getFarClip(), 0.0f, 1.0f) * 65535.0f);
  40. if (frontToBack)
  41. distance = 65535 - distance;
  42. // Shaders
  43. unsigned short shaders = (mVertexShader ? mVertexShader->getHash() : 0) + (mPixelShader ? mPixelShader->getHash() : 0);
  44. // Material technique (determines textures and shader parameters)
  45. unsigned short technique = *((unsigned short*)&mTechnique);
  46. // Vertex and index buffers and forward light
  47. unsigned short buffers = 0;
  48. buffers += mGeometry->getBufferHash();
  49. buffers += *((unsigned short*)&mForwardLight);
  50. if (stateHasPriority)
  51. {
  52. shaders >>= 1;
  53. if (mHasPriority) shaders |= 32768;
  54. mSortKey = (((unsigned long long)shaders) << 48) | (((unsigned long long)technique) << 32) |
  55. (((unsigned long long)buffers) << 16) | ((unsigned long long)distance);
  56. }
  57. else
  58. {
  59. distance >>= 1;
  60. if (mHasPriority) distance |= 32768;
  61. mSortKey = (((unsigned long long)distance) << 48) | (((unsigned long long)shaders) << 32) |
  62. (((unsigned long long)technique) << 16) | ((unsigned long long)buffers);
  63. }
  64. }
  65. void Batch::draw(Renderer* renderer) const
  66. {
  67. // Get node
  68. VolumeNode* node = mNode;
  69. // Get shaders
  70. VertexShader* vs = mVertexShader;
  71. PixelShader* ps = mPixelShader;
  72. if ((!vs) || (!ps))
  73. return;
  74. // Get light (if any)
  75. Light* light = mForwardLight;
  76. if (node->getNodeFlags() & NODE_LIGHT)
  77. light = static_cast<Light*>(mNode);
  78. // Set pass-specific renderstates
  79. if (mPass)
  80. {
  81. if (mPass->getAlphaTest())
  82. renderer->setAlphaTest(true, CMP_GREATEREQUAL, 0.5f);
  83. else
  84. renderer->setAlphaTest(false);
  85. renderer->setBlendMode(mPass->getBlendMode());
  86. renderer->setCullMode(mPass->getCullMode());
  87. renderer->setDepthTest(mPass->getDepthTestMode());
  88. renderer->setDepthWrite(mPass->getDepthWrite());
  89. }
  90. // Set material textures
  91. if (mTechnique)
  92. {
  93. const std::vector<SharedPtr<Texture> >& textures = mTechnique->getTextures();
  94. if (ps->hasTextureUnit(TU_DIFFUSE))
  95. renderer->setTexture(TU_DIFFUSE, textures[TU_DIFFUSE]);
  96. if (ps->hasTextureUnit(TU_NORMAL))
  97. renderer->setTexture(TU_NORMAL, textures[TU_NORMAL]);
  98. if (ps->hasTextureUnit(TU_SPECULAR))
  99. renderer->setTexture(TU_SPECULAR, textures[TU_SPECULAR]);
  100. if (ps->hasTextureUnit(TU_DETAIL))
  101. renderer->setTexture(TU_DETAIL, textures[TU_DETAIL]);
  102. if (ps->hasTextureUnit(TU_ENVIRONMENT))
  103. renderer->setTexture(TU_ENVIRONMENT, textures[TU_ENVIRONMENT]);
  104. if (!light)
  105. {
  106. if (ps->hasTextureUnit(TU_EMISSIVE))
  107. renderer->setTexture(TU_EMISSIVE, textures[TU_EMISSIVE]);
  108. }
  109. }
  110. // Set light-related textures
  111. Texture2D* shadowMap = 0;
  112. if (light)
  113. {
  114. shadowMap = light->getShadowMap();
  115. if ((shadowMap) && (ps->hasTextureUnit(TU_SHADOWMAP)))
  116. renderer->setTexture(TU_SHADOWMAP, shadowMap);
  117. if (ps->hasTextureUnit(TU_LIGHTRAMP))
  118. renderer->setTexture(TU_LIGHTRAMP, light->getRampTexture());
  119. if (ps->hasTextureUnit(TU_LIGHTSPOT))
  120. renderer->setTexture(TU_LIGHTSPOT, light->getSpotTexture());
  121. }
  122. // Set shaders
  123. renderer->setVertexShader(vs);
  124. renderer->setPixelShader(ps);
  125. // Set viewport parameters
  126. if (vs->needParameterUpdate(VSP_DEPTHMODE, mCamera))
  127. {
  128. Vector4 depthMode = Vector4::sZero;
  129. if (mCamera->isOrthographic())
  130. depthMode.mZ = 1.0f;
  131. else
  132. depthMode.mW = 1.0f / mCamera->getFarClip();
  133. renderer->setVertexShaderConstant(getVSRegister(VSP_DEPTHMODE), depthMode);
  134. }
  135. if (vs->needParameterUpdate(VSP_FRUSTUMSIZE, mCamera))
  136. {
  137. const Vector3& farVector = mCamera->getFrustumFarSize();
  138. Vector4 viewportParams(farVector.mX, farVector.mY, farVector.mZ, 0.0f);
  139. renderer->setVertexShaderConstant(getVSRegister(VSP_FRUSTUMSIZE), viewportParams);
  140. }
  141. // Set node transforms
  142. if (node)
  143. {
  144. const Matrix4x3* model = &node->getWorldTransform();
  145. const Matrix4x3* view = &mCamera->getInverseWorldTransform();
  146. const Matrix4* projection = &mCamera->getProjection();
  147. const void* modelSrc = node;
  148. const void* viewSrc = mCamera;
  149. node->overrideTransforms(mBatchIndex, *mCamera, &model, &view);
  150. // See if the node actually adjusted the transforms, and set the sources accordingly
  151. // so that we can avoid setting the same transforms over again
  152. if (model == &Matrix4x3::sIdentity)
  153. modelSrc = mCamera;
  154. if (view != &mCamera->getInverseWorldTransform())
  155. viewSrc = node;
  156. if (vs->needParameterUpdate(VSP_MODEL, modelSrc))
  157. renderer->setVertexShaderConstant(getVSRegister(VSP_MODEL), *model);
  158. if (vs->needParameterUpdate(VSP_MODELVIEWPROJ, modelSrc))
  159. renderer->setVertexShaderConstant(getVSRegister(VSP_MODELVIEWPROJ), (*projection) * (*view) * (*model));
  160. if ((shadowMap) && (vs->needParameterUpdate(VSP_SHADOWPROJ, light)))
  161. {
  162. Camera& shadowCamera = light->getShadowCamera();
  163. const Matrix4x3& shadowView = shadowCamera.getInverseWorldTransform();
  164. Matrix4 shadowProj = shadowCamera.getProjection();
  165. Matrix4 texAdjust = Matrix4::sIdentity;
  166. float offset = 0.5f + 0.5f / (float)shadowMap->getWidth();
  167. texAdjust.setTranslation(Vector3(offset, offset, 0.0f));
  168. texAdjust.setScale(Vector3(0.5f, -0.5f, 1.0f));
  169. renderer->setVertexShaderConstant(getVSRegister(VSP_SHADOWPROJ), texAdjust * shadowProj * shadowView);
  170. }
  171. if ((light) && (vs->needParameterUpdate(VSP_SPOTPROJ, light)))
  172. {
  173. Matrix4x3 spotView;
  174. Quaternion rotation(Vector3(0.0f, 0.0f, 1.0f), light->getDirection());
  175. spotView.define(light->getWorldPosition(), light->getWorldRotation() * rotation, 1.0f);
  176. Matrix4 spotProj;
  177. memset(&spotProj, 0, sizeof(spotProj));
  178. // Make the projected light slightly smaller than the shadow map to prevent light spill
  179. float h = 1.005f / tanf(light->getFov() * M_DEGTORAD * 0.5f);
  180. float w = h / light->getAspectRatio();
  181. spotProj.m00 = w;
  182. spotProj.m11 = h;
  183. spotProj.m22 = 1.0f / max(light->getRange(), M_EPSILON);
  184. spotProj.m32 = 1.0f;
  185. Matrix4 texAdjust = Matrix4::sIdentity;
  186. texAdjust.setTranslation(Vector3(0.5f, 0.5f, 0.0f));
  187. texAdjust.setScale(Vector3(0.5f, -0.5f, 1.0f));
  188. renderer->setVertexShaderConstant(getVSRegister(VSP_SPOTPROJ), texAdjust * spotProj * spotView.getInverse());
  189. }
  190. if (vs->needParameterUpdate(VSP_VIEWINVERSE, mCamera))
  191. renderer->setVertexShaderConstant(getVSRegister(VSP_VIEWINVERSE), mCamera->getWorldTransform());
  192. if (vs->needParameterUpdate(VSP_VIEWPROJ, viewSrc))
  193. renderer->setVertexShaderConstant(getVSRegister(VSP_VIEWPROJ), (*projection) * (*view));
  194. }
  195. // Set material's vertex shader parameters
  196. if (mTechnique)
  197. {
  198. const std::map<VSParameter, Vector4>& parameters = mTechnique->getVertexShaderParameters();
  199. for (std::map<VSParameter, Vector4>::const_iterator i = parameters.begin(); i != parameters.end(); ++i)
  200. {
  201. if (vs->needParameterUpdate(i->first, mTechnique))
  202. renderer->setVertexShaderConstant(getVSRegister(i->first), i->second);
  203. }
  204. }
  205. if (vs->needParameterUpdate(VSP_VIEWRIGHTVECTOR, mCamera))
  206. renderer->setVertexShaderConstant(getVSRegister(VSP_VIEWRIGHTVECTOR), mCamera->getRightVector());
  207. if (vs->needParameterUpdate(VSP_VIEWUPVECTOR, mCamera))
  208. renderer->setVertexShaderConstant(getVSRegister(VSP_VIEWUPVECTOR), mCamera->getUpVector());
  209. // Set node's instance & skinning parameters
  210. if (node->getNodeFlags() & NODE_GEOMETRY)
  211. {
  212. GeometryNode* geom = static_cast<GeometryNode*>(node);
  213. const float* data;
  214. unsigned count;
  215. if (vs->hasParameter(VSP_MODELSKINMATRICES))
  216. {
  217. if (geom->getVertexShaderParameter(mBatchIndex, VSP_MODELSKINMATRICES, &data, &count))
  218. {
  219. if (vs->needParameterUpdate(VSP_MODELSKINMATRICES, data))
  220. renderer->setVertexShaderConstant(getVSRegister(VSP_MODELSKINMATRICES), data, count);
  221. }
  222. }
  223. if (vs->hasParameter(VSP_MODELINSTANCES))
  224. {
  225. if (geom->getVertexShaderParameter(mBatchIndex, VSP_MODELINSTANCES, &data, &count))
  226. {
  227. if (vs->needParameterUpdate(VSP_MODELINSTANCES, data))
  228. renderer->setVertexShaderConstant(getVSRegister(VSP_MODELINSTANCES), data, count);
  229. }
  230. }
  231. }
  232. // Set light-related parameters
  233. if (light)
  234. {
  235. if (ps->needParameterUpdate(PSP_LIGHTATTEN, light))
  236. {
  237. Vector4 lightAtten(1.0f / max(light->getRange(), M_EPSILON), 0.0f, 0.0f, 0.0f);
  238. renderer->setPixelShaderConstant(getPSRegister(PSP_LIGHTATTEN), lightAtten);
  239. }
  240. if (ps->needParameterUpdate(PSP_LIGHTCOLOR, light))
  241. {
  242. float fade = 1.0f;
  243. float fadeEnd = light->getDrawDistance();
  244. float fadeStart = light->getFadeDistance();
  245. // Do fade calculation for light if both fade & draw distance defined
  246. if ((light->getLightType() != LIGHT_DIRECTIONAL) && (fadeEnd != 0.0f) && (fadeStart != 0.0f) && (fadeStart < fadeEnd))
  247. fade = min(1.0f - (light->getDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
  248. renderer->setPixelShaderConstant(getPSRegister(PSP_LIGHTCOLOR), Vector4(light->getColor().getRGB(), light->getSpecularIntensity()) * fade);
  249. }
  250. if (ps->needParameterUpdate(PSP_LIGHTDIR, light))
  251. renderer->setPixelShaderConstant(getPSRegister(PSP_LIGHTDIR), -(light->getWorldRotation() * light->getDirection()));
  252. if (ps->needParameterUpdate(PSP_LIGHTPOS, light))
  253. renderer->setPixelShaderConstant(getPSRegister(PSP_LIGHTPOS), light->getWorldPosition() - mCamera->getWorldPosition());
  254. if (ps->needParameterUpdate(PSP_LIGHTSPLITS, light))
  255. {
  256. float nearFadeRange = light->getNearFadeRange();
  257. float farFadeRange = light->getFarFadeRange();
  258. float nearFadeStart = light->getNearSplit() - nearFadeRange;
  259. float farFadeStart = light->getFarSplit() - farFadeRange;
  260. float depthRange = mCamera->getFarClip();
  261. renderer->setPixelShaderConstant(getPSRegister(PSP_LIGHTSPLITS),
  262. Vector4(nearFadeStart / depthRange, 1.0f / (nearFadeRange / depthRange),
  263. farFadeStart / depthRange, 1.0f / (farFadeRange / depthRange)));
  264. }
  265. }
  266. // Set material's pixel shader parameters
  267. if (mTechnique)
  268. {
  269. const std::map<PSParameter, Vector4>& parameters = mTechnique->getPixelShaderParameters();
  270. for (std::map<PSParameter, Vector4>::const_iterator i = parameters.begin(); i != parameters.end(); ++i)
  271. {
  272. if (ps->needParameterUpdate(i->first, mTechnique))
  273. renderer->setPixelShaderConstant(getPSRegister(i->first), i->second);
  274. }
  275. }
  276. // Set shadow & spotlight projection parameters
  277. if (shadowMap)
  278. {
  279. if (ps->needParameterUpdate(PSP_SAMPLEOFFSETS, shadowMap))
  280. {
  281. float invWidth = 1.0f / (float)shadowMap->getWidth();
  282. renderer->setPixelShaderConstant(getPSRegister(PSP_SAMPLEOFFSETS),
  283. Vector4(0.5f * invWidth, -0.5f * invWidth, 0.0f, 0.0f));
  284. }
  285. if (ps->needParameterUpdate(PSP_SHADOWINTENSITY, light))
  286. {
  287. float intensity = light->getShadowIntensity();
  288. float fadeStart = light->getShadowFadeDistance();
  289. float fadeEnd = light->getShadowDistance();
  290. if ((fadeStart > 0.0f) && (fadeEnd > 0.0f) && (fadeEnd > fadeStart))
  291. intensity = lerp(intensity, 1.0f, clamp((light->getDistance() - fadeStart) / (fadeEnd - fadeStart), 0.0f, 1.0f));
  292. float pcfValues = (1.0f - intensity) * 0.25f;
  293. renderer->setPixelShaderConstant(getPSRegister(PSP_SHADOWINTENSITY), Vector4(pcfValues, intensity, 0.0f, 0.0f));
  294. }
  295. if (ps->needParameterUpdate(PSP_SHADOWPROJ, light))
  296. {
  297. Camera& shadowCamera = light->getShadowCamera();
  298. const Matrix4x3& shadowView = shadowCamera.getInverseWorldTransform();
  299. Matrix4 shadowProj = shadowCamera.getProjection();
  300. Matrix4x3 viewPos = Matrix4x3::sIdentity;
  301. viewPos.setTranslation(mCamera->getWorldPosition());
  302. Matrix4 texAdjust = Matrix4::sIdentity;
  303. float offset = 0.5f + 0.5f / (float)shadowMap->getWidth();
  304. texAdjust.setTranslation(Vector3(offset, offset, 0.0f));
  305. texAdjust.setScale(Vector3(0.5f, -0.5f, 1.0f));
  306. renderer->setPixelShaderConstant(getPSRegister(PSP_SHADOWPROJ),
  307. texAdjust * shadowProj * shadowView * viewPos);
  308. }
  309. }
  310. if ((light) && (ps->needParameterUpdate(PSP_SPOTPROJ, light)))
  311. {
  312. Matrix4x3 spotView;
  313. Quaternion rotation(Vector3(0.0f, 0.0f, 1.0f), light->getDirection());
  314. spotView.define(light->getWorldPosition(), light->getWorldRotation() * rotation, 1.0f);
  315. Matrix4 spotProj;
  316. memset(&spotProj, 0, sizeof(spotProj));
  317. // Make the projected light slightly smaller than the shadow map to prevent light spill
  318. float h = 1.005f / tanf(light->getFov() * M_DEGTORAD * 0.5f);
  319. float w = h / light->getAspectRatio();
  320. spotProj.m00 = w;
  321. spotProj.m11 = h;
  322. spotProj.m22 = 1.0f / max(light->getRange(), M_EPSILON);
  323. spotProj.m32 = 1.0f;
  324. Matrix4x3 viewPos = Matrix4x3::sIdentity;
  325. viewPos.setTranslation(mCamera->getWorldPosition());
  326. Matrix4 texAdjust = Matrix4::sIdentity;
  327. texAdjust.setTranslation(Vector3(0.5f, 0.5f, 0.0f));
  328. texAdjust.setScale(Vector3(0.5f, -0.5f, 1.0f));
  329. renderer->setPixelShaderConstant(getPSRegister(PSP_SPOTPROJ), texAdjust * spotProj * spotView.getInverse() * viewPos);
  330. }
  331. // Draw
  332. mGeometry->draw(renderer);
  333. }