llgltfscenemanager.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /**
  2. * @file llgltfscenemanager.cpp
  3. * @brief LLGLTFSceneManager class implementation.
  4. *
  5. * $LicenseInfo:firstyear=2024&license=viewergpl$
  6. *
  7. * Copyright (c) 2024, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "tinygltf/tiny_gltf.h"
  34. #include "llgltfscenemanager.h"
  35. #include "llrender.h"
  36. #include "llrenderutils.h" // For gl_draw_box_outline()
  37. #include "llappviewer.h"
  38. #include "llpipeline.h"
  39. #include "lltinygltfhelper.h"
  40. #include "llviewerobjectlist.h"
  41. #include "llviewershadermgr.h"
  42. #include "llviewerwindow.h" // For gDebugRaycast*
  43. using namespace LLGLTF;
  44. //static
  45. LLGLTFSceneManager::objects_set_t LLGLTFSceneManager::sObjects;
  46. //static
  47. void LLGLTFSceneManager::cleanup()
  48. {
  49. sObjects.clear();
  50. }
  51. //static
  52. std::string LLGLTFSceneManager::load(const std::string& filename,
  53. const LLUUID& handle_obj_id)
  54. {
  55. LLViewerObject* objp = gObjectList.findObject(handle_obj_id);
  56. if (!objp || objp->isDead() || !objp->asVolume() ||
  57. objp->mDrawable.isNull() || objp->isAttachment())
  58. {
  59. // *TODO: translate
  60. return "No valid object to act as a handle for the gLTF scene.";
  61. }
  62. if (filename.empty())
  63. {
  64. objp->mGLTFAsset = NULL;
  65. objects_set_t::iterator it = sObjects.find(objp);
  66. if (it != sObjects.end())
  67. {
  68. sObjects.erase(it);
  69. }
  70. // Ensure the draw info will be regenerated, so to show the handle
  71. // object. HB
  72. objp->markForUpdate(true);
  73. // No error
  74. return "";
  75. }
  76. tinygltf::Model model;
  77. if (!LLTinyGLTFHelper::loadModel(filename, model))
  78. {
  79. // *TODO: translate
  80. return "TinyGLTF could not load this model.";
  81. }
  82. LLPointer<Asset> assetp = new Asset();
  83. *assetp = model;
  84. // Bind a shader to satisfy LLVertexBuffer assertions
  85. gDebugProgram.bind();
  86. if (!assetp->allocateGLResources(filename, model))
  87. {
  88. // For now, this is the only identified cause for an failure. HB
  89. // *TODO: translate
  90. return "Too many vertices used in a primitive.";
  91. }
  92. assetp->updateTransforms();
  93. objp->mGLTFAsset = assetp;
  94. sObjects.emplace(objp);
  95. // Ensure the draw info will be regenerated, so to hide the handle
  96. // object. HB
  97. objp->markForUpdate(true);
  98. // No error
  99. return "";
  100. }
  101. //static
  102. bool LLGLTFSceneManager::lineSegmentIntersect(LLVOVolume* volp, Asset* assetp,
  103. const LLVector4a& start,
  104. const LLVector4a& end,
  105. S32 face, bool, bool,
  106. S32* node_hitp, S32* prim_hitp,
  107. LLVector4a* interp,
  108. LLVector2* tcoordp,
  109. LLVector4a* normp,
  110. LLVector4a* tgtp)
  111. {
  112. LLVector4a local_start, local_end, p, n, tn;
  113. LLVector2 tc;
  114. if (interp)
  115. {
  116. p = *interp;
  117. }
  118. if (tcoordp)
  119. {
  120. tc = *tcoordp;
  121. }
  122. if (normp)
  123. {
  124. n = *normp;
  125. }
  126. if (tgtp)
  127. {
  128. tn = *tgtp;
  129. }
  130. // Line segment intersection test 'start' and 'end' should be in agent
  131. // space. Volume space and asset space should be the same coordinate frame.
  132. // Results should be transformed back to agent space.
  133. LLMatrix4a asset_to_agent = volp->getGLTFAssetToAgentTransform();
  134. LLMatrix4a agent_to_asset = asset_to_agent;
  135. agent_to_asset.invert();
  136. agent_to_asset.affineTransform(start, local_start);
  137. agent_to_asset.affineTransform(end, local_end);
  138. S32 hit_node_index = assetp->lineSegmentIntersect(local_start, local_end,
  139. &p, &tc, &n, &tn,
  140. prim_hitp);
  141. if (hit_node_index < 0)
  142. {
  143. return false;
  144. }
  145. local_end = p;
  146. if (node_hitp)
  147. {
  148. *node_hitp = hit_node_index;
  149. }
  150. if (interp)
  151. {
  152. asset_to_agent.affineTransform(p, *interp);
  153. }
  154. if (normp)
  155. {
  156. LLVector3 v_n(n.getF32ptr());
  157. normp->load3(volp->volumeDirectionToAgent(v_n).mV);
  158. normp->normalize3fast();
  159. }
  160. if (tgtp)
  161. {
  162. LLVector3 v_tn(tn.getF32ptr());
  163. LLVector4a trans_tangent;
  164. trans_tangent.load3(volp->volumeDirectionToAgent(v_tn).mV);
  165. LLVector4Logical mask;
  166. mask.clear();
  167. mask.setElement<3>();
  168. tgtp->setSelectWithMask(mask, tn, trans_tangent);
  169. tgtp->normalize3fast();
  170. }
  171. if (tcoordp)
  172. {
  173. *tcoordp = tc;
  174. }
  175. return true;
  176. }
  177. //static
  178. LLDrawable* LLGLTFSceneManager::lineSegmentIntersect(const LLVector4a& start,
  179. const LLVector4a& end,
  180. bool pick_transparent,
  181. bool pick_rigged,
  182. S32* node_hitp,
  183. S32* prim_hitp,
  184. LLVector4a* interp,
  185. LLVector2* tcoordp,
  186. LLVector4a* normp,
  187. LLVector4a* tgtp)
  188. {
  189. LLDrawable* drawp = NULL;
  190. LLVector4a local_end = end;
  191. LLVector4a position;
  192. for (objects_set_t::iterator it = sObjects.begin(), end = sObjects.end();
  193. it != end; )
  194. {
  195. LLVOVolume* volp = it->get()->asVolume();
  196. if (!volp || volp->isDead() || volp->mGLTFAsset.isNull())
  197. {
  198. it = sObjects.erase(it);
  199. continue;
  200. }
  201. // Temporary debug: always double check objects that have GLTF scenes
  202. // hanging off of them even if the ray does not intersect the object
  203. // bounds.
  204. if (lineSegmentIntersect(volp, volp->mGLTFAsset,start, local_end, -1,
  205. pick_transparent, pick_rigged, node_hitp, prim_hitp, &position,
  206. tcoordp, normp, tgtp))
  207. {
  208. local_end = position;
  209. if (interp)
  210. {
  211. *interp = position;
  212. }
  213. drawp = volp->mDrawable;
  214. }
  215. ++it;
  216. }
  217. return drawp;
  218. }
  219. //static
  220. void LLGLTFSceneManager::update()
  221. {
  222. for (objects_set_t::iterator it = sObjects.begin(), end = sObjects.end();
  223. it != end; )
  224. {
  225. LLViewerObject* objp = it->get();
  226. if (objp->isDead() || objp->mGLTFAsset.isNull())
  227. {
  228. it = sObjects.erase(it);
  229. }
  230. else
  231. {
  232. objp->mGLTFAsset->update();
  233. ++it;
  234. }
  235. }
  236. }
  237. //static
  238. void LLGLTFSceneManager::render(bool opaque, bool rigged)
  239. {
  240. gGL.matrixMode(LLRender::MM_MODELVIEW);
  241. for (objects_set_t::iterator it = sObjects.begin(), end = sObjects.end();
  242. it != end; )
  243. {
  244. LLViewerObject* objp = it->get();
  245. if (objp->isDead() || objp->mGLTFAsset.isNull())
  246. {
  247. it = sObjects.erase(it);
  248. continue;
  249. }
  250. LLMatrix4a mat = objp->getGLTFAssetToAgentTransform();
  251. mat.matMul(mat, gGLModelView);
  252. gGL.pushMatrix();
  253. Asset* assetp = objp->mGLTFAsset;
  254. assetp->updateRenderTransforms(mat);
  255. assetp->render(opaque, rigged);
  256. gGL.popMatrix();
  257. ++it;
  258. }
  259. }
  260. // This function assumes that the appropriate shader is already bound and the
  261. // model view matrix for the asset is already set.
  262. static void draw_asset_box(LLViewerObject* objp, Asset* assetp)
  263. {
  264. gGL.pushMatrix();
  265. for (auto& node : assetp->mNodes)
  266. {
  267. if (node.mMesh == INVALID_INDEX)
  268. {
  269. continue;
  270. }
  271. Mesh& mesh = assetp->mMeshes[node.mMesh];
  272. gGL.loadMatrix(node.mRenderMatrix.getF32ptr());
  273. // Draw bounding box of mesh primitives
  274. gGL.color3f(0.f, 1.f, 1.f);
  275. for (auto& primitive : mesh.mPrimitives)
  276. {
  277. LLVolumeOctree* octreep = primitive.mOctree.get();
  278. if (octreep)
  279. {
  280. LLVolumeOctreeListenerNoOwnership* listenerp =
  281. (LLVolumeOctreeListenerNoOwnership*)octreep->getListener(0);
  282. if (listenerp)
  283. {
  284. LLVector4a center = listenerp->mBounds[0];
  285. LLVector4a size = listenerp->mBounds[1];
  286. gl_draw_box_outline(center, size);
  287. }
  288. }
  289. }
  290. }
  291. gGL.popMatrix();
  292. }
  293. //static
  294. void LLGLTFSceneManager::renderDebug()
  295. {
  296. gDebugProgram.bind();
  297. LLGLDisable cullface(GL_CULL_FACE);
  298. LLGLEnable blend(GL_BLEND);
  299. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  300. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  301. gPipeline.disableLights();
  302. // Force update all mRenderMatrix, not just nodes with meshes
  303. for (objects_set_t::iterator it = sObjects.begin(), end = sObjects.end();
  304. it != end; ++it)
  305. {
  306. LLViewerObject* objp = it->get();
  307. if (objp->isDead() || objp->mGLTFAsset.isNull())
  308. {
  309. continue;
  310. }
  311. LLMatrix4a mat = objp->getGLTFAssetToAgentTransform();
  312. mat.matMul(mat, gGLModelView);
  313. for (auto& node : objp->mGLTFAsset->mNodes)
  314. {
  315. node.mRenderMatrix.matMul(node.mAssetMatrix, mat);
  316. }
  317. }
  318. if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
  319. {
  320. for (objects_set_t::iterator it = sObjects.begin(),
  321. end = sObjects.end();
  322. it != end; ++it)
  323. {
  324. LLViewerObject* objp = it->get();
  325. if (!objp->isDead() && objp->mGLTFAsset.notNull())
  326. {
  327. draw_asset_box(objp, objp->mGLTFAsset);
  328. }
  329. }
  330. }
  331. if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NODES))
  332. {
  333. // Render nodes hierarchy
  334. for (U32 i = 0; i < 2; ++i)
  335. {
  336. LLGLDepthTest depth(GL_TRUE, i ? GL_TRUE : GL_FALSE,
  337. i ? GL_LEQUAL : GL_GREATER);
  338. LLGLState blend(GL_BLEND, i ? GL_FALSE : GL_TRUE);
  339. gGL.pushMatrix();
  340. for (objects_set_t::iterator it = sObjects.begin(),
  341. end = sObjects.end();
  342. it != end; ++it)
  343. {
  344. LLViewerObject* objp = it->get();
  345. if (objp->isDead() || objp->mGLTFAsset.isNull())
  346. {
  347. continue;
  348. }
  349. Asset* assetp = objp->mGLTFAsset;
  350. LLMatrix4a mat = objp->getGLTFAssetToAgentTransform();
  351. mat.matMul(mat, gGLModelView);
  352. for (auto& node : assetp->mNodes)
  353. {
  354. node.mRenderMatrix.matMul(node.mAssetMatrix, mat);
  355. gGL.loadMatrix(node.mRenderMatrix.getF32ptr());
  356. // Render x-axis red, y-axis green, z-axis blue
  357. gGL.color4f(1.f, 0.f, 0.f, 0.5f);
  358. gGL.begin(LLRender::LINES);
  359. gGL.vertex3f(0.f, 0.f, 0.f);
  360. gGL.vertex3f(1.f, 0.f, 0.f);
  361. gGL.end(true);
  362. gGL.color4f(0.f, 1.f, 0.f, 0.5f);
  363. gGL.begin(LLRender::LINES);
  364. gGL.vertex3f(0.f, 0.f, 0.f);
  365. gGL.vertex3f(0.f, 1.f, 0.f);
  366. gGL.end(true);
  367. gGL.color4f(0.f, 0.f, 1.f, 0.5f);
  368. gGL.begin(LLRender::LINES);
  369. gGL.vertex3f(0.f, 0.f, 0.f);
  370. gGL.vertex3f(0.f, 0.f, 1.f);
  371. gGL.end(true);
  372. // Render path to child nodes cyan
  373. gGL.color4f(0.f, 1.f, 1.f, 0.5f);
  374. gGL.begin(LLRender::LINES);
  375. for (auto& child_idx : node.mChildren)
  376. {
  377. Node& child = assetp->mNodes[child_idx];
  378. gGL.vertex3f(0.f, 0.f, 0.f);
  379. gGL.vertex3fv(child.mMatrix.getTranslation().getF32ptr());
  380. }
  381. gGL.end(true);
  382. }
  383. }
  384. gGL.popMatrix();
  385. }
  386. }
  387. if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
  388. {
  389. S32 node_hit = -1;
  390. S32 prim_hit = -1;
  391. LLVector4a inter;
  392. LLDrawable* drawp = lineSegmentIntersect(gDebugRaycastStart,
  393. gDebugRaycastEnd, true, true,
  394. &node_hit, &prim_hit, &inter,
  395. NULL, NULL, NULL);
  396. if (drawp && !drawp->isDead() && drawp->getVObj() &&
  397. node_hit >= 0 && prim_hit >= 0)
  398. {
  399. Asset* assetp = drawp->getVObj()->mGLTFAsset;
  400. Node* nodep = &assetp->mNodes[node_hit];
  401. Primitive* primp =
  402. &assetp->mMeshes[nodep->mMesh].mPrimitives[prim_hit];
  403. gGL.pushMatrix();
  404. gGL.flush();
  405. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  406. gGL.color3f(1.f, 0.f, 1.f);
  407. gl_draw_box_outline(inter, LLVector4a(0.1f, 0.1f, 0.1f, 0.f));
  408. gGL.loadMatrix(nodep->mRenderMatrix.getF32ptr());
  409. LLVolumeOctree* octreep = primp->mOctree.get();
  410. if (octreep)
  411. {
  412. LLVolumeOctreeListenerNoOwnership* listenerp =
  413. (LLVolumeOctreeListenerNoOwnership*)octreep->getListener(0);
  414. if (listenerp)
  415. {
  416. gl_draw_box_outline(listenerp->mBounds[0],
  417. listenerp->mBounds[1]);
  418. }
  419. }
  420. gGL.flush();
  421. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  422. gGL.popMatrix();
  423. }
  424. }
  425. gDebugProgram.unbind();
  426. }