TerrainPatch.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Core/Context.h"
  5. #include "../Graphics/Camera.h"
  6. #include "../Graphics/DebugRenderer.h"
  7. #include "../Graphics/Geometry.h"
  8. #include "../Graphics/Material.h"
  9. #include "../Graphics/OcclusionBuffer.h"
  10. #include "../Graphics/OctreeQuery.h"
  11. #include "../Graphics/Terrain.h"
  12. #include "../Graphics/TerrainPatch.h"
  13. #include "../GraphicsAPI/IndexBuffer.h"
  14. #include "../GraphicsAPI/VertexBuffer.h"
  15. #include "../IO/Log.h"
  16. #include "../Scene/Node.h"
  17. #include "../DebugNew.h"
  18. namespace Urho3D
  19. {
  20. static const float LOD_CONSTANT = 1.0f / 150.0f;
  21. extern const char* GEOMETRY_CATEGORY;
  22. TerrainPatch::TerrainPatch(Context* context) :
  23. Drawable(context, DrawableTypes::Geometry),
  24. geometry_(new Geometry(context)),
  25. maxLodGeometry_(new Geometry(context)),
  26. occlusionGeometry_(new Geometry(context)),
  27. vertexBuffer_(new VertexBuffer(context)),
  28. coordinates_(IntVector2::ZERO),
  29. lodLevel_(0)
  30. {
  31. geometry_->SetVertexBuffer(0, vertexBuffer_);
  32. maxLodGeometry_->SetVertexBuffer(0, vertexBuffer_);
  33. occlusionGeometry_->SetVertexBuffer(0, vertexBuffer_);
  34. batches_.Resize(1);
  35. batches_[0].geometry_ = geometry_;
  36. batches_[0].geometryType_ = GEOM_STATIC_NOINSTANCING;
  37. }
  38. TerrainPatch::~TerrainPatch() = default;
  39. void TerrainPatch::RegisterObject(Context* context)
  40. {
  41. context->RegisterFactory<TerrainPatch>();
  42. }
  43. void TerrainPatch::ProcessRayQuery(const RayOctreeQuery& query, Vector<RayQueryResult>& results)
  44. {
  45. RayQueryLevel level = query.level_;
  46. switch (level)
  47. {
  48. case RAY_AABB:
  49. Drawable::ProcessRayQuery(query, results);
  50. break;
  51. case RAY_OBB:
  52. case RAY_TRIANGLE:
  53. {
  54. Matrix3x4 inverse(node_->GetWorldTransform().Inverse());
  55. Ray localRay = query.ray_.Transformed(inverse);
  56. float distance = localRay.HitDistance(boundingBox_);
  57. Vector3 normal = -query.ray_.direction_;
  58. if (level == RAY_TRIANGLE && distance < query.maxDistance_)
  59. {
  60. Vector3 geometryNormal;
  61. distance = geometry_->GetHitDistance(localRay, &geometryNormal);
  62. normal = (node_->GetWorldTransform() * Vector4(geometryNormal, 0.0f)).Normalized();
  63. }
  64. if (distance < query.maxDistance_)
  65. {
  66. RayQueryResult result;
  67. result.position_ = query.ray_.origin_ + distance * query.ray_.direction_;
  68. result.normal_ = normal;
  69. result.distance_ = distance;
  70. result.drawable_ = this;
  71. result.node_ = node_;
  72. result.subObject_ = NINDEX;
  73. results.Push(result);
  74. }
  75. }
  76. break;
  77. case RAY_TRIANGLE_UV:
  78. URHO3D_LOGWARNING("RAY_TRIANGLE_UV query level is not supported for TerrainPatch component");
  79. break;
  80. }
  81. }
  82. void TerrainPatch::UpdateBatches(const FrameInfo& frame)
  83. {
  84. const Matrix3x4& worldTransform = node_->GetWorldTransform();
  85. distance_ = frame.camera_->GetDistance(GetWorldBoundingBox().Center());
  86. float scale = worldTransform.Scale().DotProduct(DOT_SCALE);
  87. lodDistance_ = frame.camera_->GetLodDistance(distance_, scale, lodBias_);
  88. batches_[0].distance_ = distance_;
  89. batches_[0].worldTransform_ = &worldTransform;
  90. i32 newLodLevel = 0;
  91. for (i32 i = 0; i < lodErrors_.Size(); ++i)
  92. {
  93. if (lodErrors_[i] / lodDistance_ > LOD_CONSTANT)
  94. break;
  95. else
  96. newLodLevel = i;
  97. }
  98. lodLevel_ = GetCorrectedLodLevel(newLodLevel);
  99. }
  100. void TerrainPatch::UpdateGeometry(const FrameInfo& frame)
  101. {
  102. if (vertexBuffer_->IsDataLost())
  103. {
  104. if (owner_)
  105. owner_->CreatePatchGeometry(this);
  106. else
  107. vertexBuffer_->ClearDataLost();
  108. }
  109. if (owner_)
  110. owner_->UpdatePatchLod(this);
  111. }
  112. UpdateGeometryType TerrainPatch::GetUpdateGeometryType()
  113. {
  114. // Because there is a latency in starting worker thread updates, and the update of terrain patch LOD should not take
  115. // much time, always update in the main thread
  116. return UPDATE_MAIN_THREAD;
  117. }
  118. Geometry* TerrainPatch::GetLodGeometry(i32 batchIndex, i32 level)
  119. {
  120. assert(batchIndex >= 0);
  121. assert(level >= 0 || level == NINDEX);
  122. if (!level)
  123. return maxLodGeometry_;
  124. else
  125. return geometry_;
  126. }
  127. i32 TerrainPatch::GetNumOccluderTriangles()
  128. {
  129. // Check that the material is suitable for occlusion (default material always is)
  130. Material* mat = batches_[0].material_;
  131. if (mat && !mat->GetOcclusion())
  132. return 0;
  133. else
  134. return occlusionGeometry_->GetIndexCount() / 3;
  135. }
  136. bool TerrainPatch::DrawOcclusion(OcclusionBuffer* buffer)
  137. {
  138. // Check that the material is suitable for occlusion (default material always is) and set culling mode
  139. Material* material = batches_[0].material_;
  140. if (material)
  141. {
  142. if (!material->GetOcclusion())
  143. return true;
  144. buffer->SetCullMode(material->GetCullMode());
  145. }
  146. else
  147. buffer->SetCullMode(CULL_CCW);
  148. const byte* vertexData;
  149. i32 vertexSize;
  150. const byte* indexData;
  151. i32 indexSize;
  152. const Vector<VertexElement>* elements;
  153. occlusionGeometry_->GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
  154. // Check for valid geometry data
  155. if (!vertexData || !indexData || !elements || VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR3, SEM_POSITION) != 0)
  156. return false;
  157. // Draw and check for running out of triangles
  158. return buffer->AddTriangles(node_->GetWorldTransform(), vertexData, vertexSize, indexData, indexSize, occlusionGeometry_->GetIndexStart(),
  159. occlusionGeometry_->GetIndexCount());
  160. }
  161. void TerrainPatch::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  162. {
  163. // Intentionally no operation
  164. }
  165. void TerrainPatch::SetOwner(Terrain* terrain)
  166. {
  167. owner_ = terrain;
  168. }
  169. void TerrainPatch::SetNeighbors(TerrainPatch* north, TerrainPatch* south, TerrainPatch* west, TerrainPatch* east)
  170. {
  171. north_ = north;
  172. south_ = south;
  173. west_ = west;
  174. east_ = east;
  175. }
  176. void TerrainPatch::SetMaterial(Material* material)
  177. {
  178. batches_[0].material_ = material;
  179. }
  180. void TerrainPatch::SetBoundingBox(const BoundingBox& box)
  181. {
  182. boundingBox_ = box;
  183. OnMarkedDirty(node_);
  184. }
  185. void TerrainPatch::SetCoordinates(const IntVector2& coordinates)
  186. {
  187. coordinates_ = coordinates;
  188. }
  189. void TerrainPatch::ResetLod()
  190. {
  191. lodLevel_ = 0;
  192. }
  193. Geometry* TerrainPatch::GetGeometry() const
  194. {
  195. return geometry_;
  196. }
  197. Geometry* TerrainPatch::GetMaxLodGeometry() const
  198. {
  199. return maxLodGeometry_;
  200. }
  201. Geometry* TerrainPatch::GetOcclusionGeometry() const
  202. {
  203. return occlusionGeometry_;
  204. }
  205. VertexBuffer* TerrainPatch::GetVertexBuffer() const
  206. {
  207. return vertexBuffer_;
  208. }
  209. Terrain* TerrainPatch::GetOwner() const
  210. {
  211. return owner_;
  212. }
  213. void TerrainPatch::OnWorldBoundingBoxUpdate()
  214. {
  215. worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
  216. }
  217. i32 TerrainPatch::GetCorrectedLodLevel(i32 lodLevel)
  218. {
  219. assert(lodLevel >= 0);
  220. if (north_)
  221. lodLevel = Min(lodLevel, north_->GetLodLevel() + 1);
  222. if (south_)
  223. lodLevel = Min(lodLevel, south_->GetLodLevel() + 1);
  224. if (west_)
  225. lodLevel = Min(lodLevel, west_->GetLodLevel() + 1);
  226. if (east_)
  227. lodLevel = Min(lodLevel, east_->GetLodLevel() + 1);
  228. return lodLevel;
  229. }
  230. }