DecalSet.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2012 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 "Batch.h"
  25. #include "Camera.h"
  26. #include "Context.h"
  27. #include "DecalSet.h"
  28. #include "Geometry.h"
  29. #include "GeometryUtils.h"
  30. #include "Graphics.h"
  31. #include "Log.h"
  32. #include "Node.h"
  33. #include "Profiler.h"
  34. #include "Scene.h"
  35. #include "SceneEvents.h"
  36. #include "StaticModel.h"
  37. #include "VertexBuffer.h"
  38. #include "DebugNew.h"
  39. static const Vector3 DOT_SCALE(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
  40. static const unsigned DEFAULT_MAX_VERTICES = 1024;
  41. inline Vector3 ClipEdge(const Vector3& v0, const Vector3& v1, float d0, float d1)
  42. {
  43. float t = d0 / (d0 - d1);
  44. return v0 + t * (v1 - v0);
  45. }
  46. inline Vector2 ClipEdge(const Vector2& v0, const Vector2& v1, float d0, float d1)
  47. {
  48. float t = d0 / (d0 - d1);
  49. return v0 + t * (v1 - v0);
  50. }
  51. void Decal::CalculateBoundingBox()
  52. {
  53. boundingBox_.Clear();
  54. for (unsigned i = 0; i < vertices_.Size(); ++i)
  55. boundingBox_.Merge(vertices_[i].position_);
  56. }
  57. OBJECTTYPESTATIC(DecalSet);
  58. DecalSet::DecalSet(Context* context) :
  59. Drawable(context),
  60. geometry_(new Geometry(context)),
  61. vertexBuffer_(new VertexBuffer(context_)),
  62. numVertices_(0),
  63. maxVertices_(DEFAULT_MAX_VERTICES),
  64. bufferSizeDirty_(true),
  65. bufferDirty_(true),
  66. boundingBoxDirty_(true)
  67. {
  68. drawableFlags_ = DRAWABLE_GEOMETRY;
  69. geometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1);
  70. batches_.Resize(1);
  71. batches_[0].geometry_ = geometry_;
  72. }
  73. DecalSet::~DecalSet()
  74. {
  75. }
  76. void DecalSet::RegisterObject(Context* context)
  77. {
  78. context->RegisterFactory<DecalSet>();
  79. /// \todo Register attributes
  80. }
  81. void DecalSet::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
  82. {
  83. // Do not return raycast hits
  84. }
  85. void DecalSet::UpdateBatches(const FrameInfo& frame)
  86. {
  87. const Matrix3x4& worldTransform = node_->GetWorldTransform();
  88. distance_ = frame.camera_->GetDistance(GetWorldBoundingBox().Center());
  89. float scale = GetWorldBoundingBox().Size().DotProduct(DOT_SCALE);
  90. lodDistance_ = frame.camera_->GetLodDistance(distance_, scale, lodBias_);
  91. batches_[0].distance_ = distance_;
  92. batches_[0].worldTransform_ = &worldTransform;
  93. }
  94. void DecalSet::UpdateGeometry(const FrameInfo& frame)
  95. {
  96. if (bufferSizeDirty_ || vertexBuffer_->IsDataLost())
  97. UpdateBufferSize();
  98. if (bufferDirty_)
  99. UpdateVertexBuffer();
  100. }
  101. UpdateGeometryType DecalSet::GetUpdateGeometryType()
  102. {
  103. if (bufferDirty_ || bufferSizeDirty_ || vertexBuffer_->IsDataLost())
  104. return UPDATE_MAIN_THREAD;
  105. else
  106. return UPDATE_NONE;
  107. }
  108. void DecalSet::SetMaterial(Material* material)
  109. {
  110. batches_[0].material_ = material;
  111. MarkNetworkUpdate();
  112. }
  113. void DecalSet::SetMaxVertices(unsigned num)
  114. {
  115. if (num != maxVertices_)
  116. {
  117. bufferSizeDirty_ = true;
  118. maxVertices_ = num;
  119. while (decals_.Size() && numVertices_ > maxVertices_)
  120. RemoveDecals(1);
  121. }
  122. }
  123. bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive, float normalCutoff, float depthBias)
  124. {
  125. PROFILE(AddDecal);
  126. if (!node_)
  127. return false;
  128. if (!target || !target->GetNode())
  129. {
  130. LOGERROR("Null target drawable for decal");
  131. return false;
  132. }
  133. Matrix3x4 targetTransform = target->GetNode()->GetWorldTransform().Inverse();
  134. // Build the decal frustum
  135. Frustum decalFrustum;
  136. Matrix3x4 frustumTransform = targetTransform * Matrix3x4(worldPosition, worldRotation, 1.0f);
  137. decalFrustum.DefineOrtho(size, aspectRatio, 1.0, 0.0f, depth, frustumTransform);
  138. Vector3 biasVector = targetTransform * Vector4(worldRotation * (Vector3::BACK * depthBias), 0.0f);
  139. Vector3 decalNormal = (targetTransform * Vector4(worldRotation * Vector3::BACK, 0.0f)).Normalized();
  140. decals_.Resize(decals_.Size() + 1);
  141. Decal& newDecal = decals_.Back();
  142. newDecal.timeToLive_ = timeToLive;
  143. Vector<PODVector<DecalVertex> > faces;
  144. PODVector<DecalVertex> tempFace;
  145. // Special handling for static models, as they may use LOD: use the fixed software LOD level for decals
  146. StaticModel* staticModel = dynamic_cast<StaticModel*>(target);
  147. if (staticModel)
  148. {
  149. for (unsigned i = 0; i < staticModel->GetNumGeometries(); ++i)
  150. GetFaces(faces, staticModel->GetSoftwareGeometry(i), decalFrustum, decalNormal, normalCutoff);
  151. }
  152. else
  153. {
  154. // Else use the Drawable API to find out the source geometries
  155. const Vector<SourceBatch>& batches = target->GetBatches();
  156. for (unsigned i = 0; i < batches.Size(); ++i)
  157. GetFaces(faces, batches[i].geometry_, decalFrustum, decalNormal, normalCutoff);
  158. }
  159. // Clip the acquired faces against all frustum planes
  160. for (unsigned i = 0; i < NUM_FRUSTUM_PLANES; ++i)
  161. {
  162. for (unsigned j = 0; j < faces.Size(); ++j)
  163. {
  164. PODVector<DecalVertex>& face = faces[j];
  165. if (face.Empty())
  166. continue;
  167. tempFace.Resize(face.Size() + 2);
  168. unsigned outVertices = ClipPolygon((float*)&face[0], (float*)&tempFace[0], face.Size(), sizeof(DecalVertex), decalFrustum.planes_[i]);
  169. tempFace.Resize(outVertices);
  170. face = tempFace;
  171. }
  172. }
  173. // Now triangulate the resulting faces into decal vertices
  174. for (unsigned i = 0; i < faces.Size(); ++i)
  175. {
  176. PODVector<DecalVertex>& face = faces[i];
  177. if (face.Size() < 3)
  178. continue;
  179. for (unsigned j = 2; j < face.Size(); ++j)
  180. {
  181. newDecal.vertices_.Push(face[0]);
  182. newDecal.vertices_.Push(face[j - 1]);
  183. newDecal.vertices_.Push(face[j]);
  184. }
  185. }
  186. // Check if resulted in no triangles
  187. if (newDecal.vertices_.Empty())
  188. {
  189. decals_.Pop();
  190. return true;
  191. }
  192. if (newDecal.vertices_.Size() > maxVertices_)
  193. {
  194. LOGWARNING("Can not add decal, vertex count " + String(newDecal.vertices_.Size()) + " exceeds maximum " +
  195. String(maxVertices_));
  196. decals_.Pop();
  197. return false;
  198. }
  199. newDecal.vertices_.Compact();
  200. numVertices_ += newDecal.vertices_.Size();
  201. // Finally transform vertices to the DecalSet's local space
  202. Matrix3x4 decalTransform = node_->GetWorldTransform().Inverse() * target->GetNode()->GetWorldTransform();
  203. CalculateUVs(newDecal, frustumTransform.Inverse(), size, aspectRatio, depth, topLeftUV, bottomRightUV);
  204. TransformVertices(newDecal, decalTransform, biasVector);
  205. newDecal.CalculateBoundingBox();
  206. // Remove oldest decals if total vertices exceeded
  207. while (decals_.Size() && numVertices_ > maxVertices_)
  208. RemoveDecals(1);
  209. LOGDEBUG("Added decal with " + String(newDecal.vertices_.Size()) + " vertices");
  210. MarkDecalsDirty();
  211. return true;
  212. }
  213. void DecalSet::RemoveDecals(unsigned num)
  214. {
  215. while (decals_.Size() && num)
  216. {
  217. RemoveDecal(decals_.Begin());
  218. --num;
  219. }
  220. }
  221. void DecalSet::RemoveAllDecals()
  222. {
  223. if (!decals_.Empty())
  224. {
  225. decals_.Clear();
  226. numVertices_ = 0;
  227. MarkDecalsDirty();
  228. }
  229. }
  230. Material* DecalSet::GetMaterial() const
  231. {
  232. return batches_[0].material_;
  233. }
  234. void DecalSet::OnNodeSet(Node* node)
  235. {
  236. Drawable::OnNodeSet(node);
  237. if (node)
  238. {
  239. Scene* scene = GetScene();
  240. if (scene)
  241. SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(DecalSet, HandleScenePostUpdate));
  242. }
  243. }
  244. void DecalSet::OnWorldBoundingBoxUpdate()
  245. {
  246. if (boundingBoxDirty_)
  247. CalculateBoundingBox();
  248. worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
  249. }
  250. void DecalSet::GetFaces(Vector<PODVector<DecalVertex> >& faces, Geometry* geometry, const Frustum& frustum, const Vector3& decalNormal, float normalCutoff)
  251. {
  252. if (!geometry)
  253. return;
  254. const unsigned char* vertexData;
  255. unsigned vertexSize;
  256. const unsigned char* indexData;
  257. unsigned indexSize;
  258. geometry->GetRawData(vertexData, vertexSize, indexData, indexSize);
  259. if (!vertexData || !indexData)
  260. {
  261. LOGWARNING("Can not add decal, object does not have CPU-side geometry data");
  262. return;
  263. }
  264. unsigned indexStart = geometry->GetIndexStart();
  265. unsigned indexCount = geometry->GetIndexCount();
  266. bool hasNormals = vertexSize >= 6 * sizeof(float);
  267. const unsigned char* srcData = (const unsigned char*)vertexData;
  268. // 16-bit indices
  269. if (indexSize == sizeof(unsigned short))
  270. {
  271. const unsigned short* indices = ((const unsigned short*)indexData) + indexStart;
  272. const unsigned short* indicesEnd = indices + indexCount;
  273. while (indices < indicesEnd)
  274. {
  275. const Vector3& v0 = *((const Vector3*)(&srcData[indices[0] * vertexSize]));
  276. const Vector3& v1 = *((const Vector3*)(&srcData[indices[1] * vertexSize]));
  277. const Vector3& v2 = *((const Vector3*)(&srcData[indices[2] * vertexSize]));
  278. const Vector3& n0 = hasNormals ? *((const Vector3*)(&srcData[indices[0] * vertexSize + 3 * sizeof(float)])) :
  279. Vector3::ZERO;
  280. const Vector3& n1 = hasNormals ? *((const Vector3*)(&srcData[indices[1] * vertexSize + 3 * sizeof(float)])) :
  281. Vector3::ZERO;
  282. const Vector3& n2 = hasNormals ? *((const Vector3*)(&srcData[indices[2] * vertexSize + 3 * sizeof(float)])) :
  283. Vector3::ZERO;
  284. if (!hasNormals || decalNormal.DotProduct((n0 + n1 + n2) / 3.0f) >= normalCutoff)
  285. {
  286. // First check coarsely against all planes to avoid adding unnecessary faces to the clipping algorithm
  287. bool outside = false;
  288. for (unsigned i = PLANE_FAR; i < NUM_FRUSTUM_PLANES; --i)
  289. {
  290. const Plane& plane = frustum.planes_[i];
  291. if (plane.Distance(v0) < 0.0f && plane.Distance(v1) < 0.0f && plane.Distance(v2) < 0.0f)
  292. {
  293. outside = true;
  294. break;
  295. }
  296. }
  297. if (!outside)
  298. {
  299. faces.Resize(faces.Size() + 1);
  300. PODVector<DecalVertex>& face = faces.Back();
  301. face.Push(DecalVertex(v0, n0, Vector2::ZERO));
  302. face.Push(DecalVertex(v1, n1, Vector2::ZERO));
  303. face.Push(DecalVertex(v2, n2, Vector2::ZERO));
  304. }
  305. }
  306. indices += 3;
  307. }
  308. }
  309. // 32-bit indices
  310. else
  311. {
  312. const unsigned* indices = ((const unsigned*)indexData) + indexStart;
  313. const unsigned* indicesEnd = indices + indexCount;
  314. while (indices < indicesEnd)
  315. {
  316. const Vector3& v0 = *((const Vector3*)(&srcData[indices[0] * vertexSize]));
  317. const Vector3& v1 = *((const Vector3*)(&srcData[indices[1] * vertexSize]));
  318. const Vector3& v2 = *((const Vector3*)(&srcData[indices[2] * vertexSize]));
  319. const Vector3& n0 = hasNormals ? *((const Vector3*)(&srcData[indices[0] * vertexSize + 3 * sizeof(float)])) :
  320. Vector3::ZERO;
  321. const Vector3& n1 = hasNormals ? *((const Vector3*)(&srcData[indices[1] * vertexSize + 3 * sizeof(float)])) :
  322. Vector3::ZERO;
  323. const Vector3& n2 = hasNormals ? *((const Vector3*)(&srcData[indices[2] * vertexSize + 3 * sizeof(float)])) :
  324. Vector3::ZERO;
  325. if (!hasNormals || decalNormal.DotProduct((n0 + n1 + n2) / 3.0f) >= normalCutoff)
  326. {
  327. bool outside = false;
  328. for (unsigned i = PLANE_FAR; i < NUM_FRUSTUM_PLANES; --i)
  329. {
  330. const Plane& plane = frustum.planes_[i];
  331. if (plane.Distance(v0) < 0.0f && plane.Distance(v1) < 0.0f && plane.Distance(v2) < 0.0f)
  332. {
  333. outside = true;
  334. break;
  335. }
  336. }
  337. if (!outside)
  338. {
  339. faces.Resize(faces.Size() + 1);
  340. PODVector<DecalVertex>& face = faces.Back();
  341. face.Push(DecalVertex(v0, n0, Vector2::ZERO));
  342. face.Push(DecalVertex(v1, n1, Vector2::ZERO));
  343. face.Push(DecalVertex(v2, n2, Vector2::ZERO));
  344. }
  345. }
  346. indices += 3;
  347. }
  348. }
  349. }
  350. void DecalSet::CalculateUVs(Decal& decal, const Matrix3x4& view, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV)
  351. {
  352. Matrix4 projection(Matrix4::ZERO);
  353. float h = (1.0f / (size * 0.5f));
  354. float w = h / aspectRatio;
  355. float q = 1.0f / depth;
  356. float r = 0.0f;
  357. projection.m00_ = w;
  358. projection.m11_ = h;
  359. projection.m22_ = q;
  360. projection.m23_ = r;
  361. projection.m33_ = 1.0f;
  362. Matrix4 viewProj = projection * view;
  363. for (PODVector<DecalVertex>::Iterator i = decal.vertices_.Begin(); i != decal.vertices_.End(); ++i)
  364. {
  365. Vector3 projected = viewProj * i->position_;
  366. i->texCoord_ = Vector2(
  367. Lerp(topLeftUV.x_, bottomRightUV.x_, projected.x_ * 0.5f + 0.5f),
  368. Lerp(bottomRightUV.y_, topLeftUV.y_, projected.y_ * 0.5f + 0.5f)
  369. );
  370. }
  371. }
  372. void DecalSet::TransformVertices(Decal& decal, const Matrix3x4& transform, const Vector3& biasVector)
  373. {
  374. for (PODVector<DecalVertex>::Iterator i = decal.vertices_.Begin(); i != decal.vertices_.End(); ++i)
  375. {
  376. i->position_ = transform * (i->position_ + biasVector);
  377. i->normal_ = (transform * i->normal_).Normalized();
  378. }
  379. }
  380. List<Decal>::Iterator DecalSet::RemoveDecal(List<Decal>::Iterator i)
  381. {
  382. numVertices_ -= i->vertices_.Size();
  383. MarkDecalsDirty();
  384. return decals_.Erase(i);
  385. }
  386. void DecalSet::MarkDecalsDirty()
  387. {
  388. if (!boundingBoxDirty_)
  389. {
  390. boundingBoxDirty_ = true;
  391. OnMarkedDirty(node_);
  392. }
  393. bufferDirty_ = true;
  394. }
  395. void DecalSet::CalculateBoundingBox()
  396. {
  397. boundingBox_.Clear();
  398. for (List<Decal>::ConstIterator i = decals_.Begin(); i != decals_.End(); ++i)
  399. boundingBox_.Merge(i->boundingBox_);
  400. boundingBoxDirty_ = false;
  401. }
  402. void DecalSet::UpdateBufferSize()
  403. {
  404. if (vertexBuffer_->GetVertexCount() != maxVertices_)
  405. {
  406. vertexBuffer_->SetSize(maxVertices_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1);
  407. bufferDirty_ = true;
  408. }
  409. bufferSizeDirty_ = false;
  410. }
  411. void DecalSet::UpdateVertexBuffer()
  412. {
  413. geometry_->SetDrawRange(TRIANGLE_LIST, 0, 0, 0, numVertices_);
  414. float* dest = (float*)vertexBuffer_->Lock(0, numVertices_);
  415. if (dest)
  416. {
  417. for (List<Decal>::ConstIterator i = decals_.Begin(); i != decals_.End(); ++i)
  418. {
  419. for (unsigned j = 0; j < i->vertices_.Size(); ++j)
  420. {
  421. const DecalVertex& vertex = i->vertices_[j];
  422. *dest++ = vertex.position_.x_;
  423. *dest++ = vertex.position_.y_;
  424. *dest++ = vertex.position_.z_;
  425. *dest++ = vertex.normal_.x_;
  426. *dest++ = vertex.normal_.y_;
  427. *dest++ = vertex.normal_.z_;
  428. *dest++ = vertex.texCoord_.x_;
  429. *dest++ = vertex.texCoord_.y_;
  430. }
  431. }
  432. vertexBuffer_->Unlock();
  433. }
  434. vertexBuffer_->ClearDataLost();
  435. bufferDirty_ = false;
  436. }
  437. void DecalSet::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
  438. {
  439. using namespace ScenePostUpdate;
  440. float timeStep = eventData[P_TIMESTEP].GetFloat();
  441. for (List<Decal>::Iterator i = decals_.Begin(); i != decals_.End();)
  442. {
  443. i->timer_ += timeStep;
  444. // Remove the decal if time to live expired
  445. if (i->timeToLive_ > 0.0f && i->timer_ > i->timeToLive_)
  446. i = RemoveDecal(i);
  447. else
  448. ++i;
  449. }
  450. }