llgltfmaterialpreview.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /**
  2. * @file llgltfmaterialpreview.cpp
  3. *
  4. * $LicenseInfo:firstyear=2023&license=viewerlgpl$
  5. * Second Life Viewer Source Code
  6. * Copyright (C) 2023, Linden Research, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation;
  11. * version 2.1 of the License only.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  23. * $/LicenseInfo$
  24. */
  25. #include "llviewerprecompiledheaders.h"
  26. #include <memory>
  27. #include "llgltfmaterialpreview.h"
  28. #include "llavatarappearancedefines.h"
  29. #include "llvolumemgr.h"
  30. #include "llpipeline.h"
  31. #include "llselectmgr.h"
  32. #include "llviewercamera.h"
  33. #include "llviewercontrol.h"
  34. #include "llviewerobject.h"
  35. #include "llviewershadermgr.h"
  36. #include "llviewertexturelist.h"
  37. constexpr S32 FULLY_LOADED = 0;
  38. constexpr S32 NOT_LOADED = 99;
  39. // LLGLTFPreviewTexture::MaterialLoadLevels sub-class
  40. bool LLGLTFPreviewTexture::MaterialLoadLevels::isFullyLoaded() const
  41. {
  42. for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
  43. {
  44. if (mLevels[i] != FULLY_LOADED)
  45. {
  46. return false;
  47. }
  48. }
  49. return true;
  50. }
  51. LLGLTFPreviewTexture::MaterialLoadLevels::MaterialLoadLevels()
  52. {
  53. for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
  54. {
  55. mLevels[i] = NOT_LOADED;
  56. }
  57. }
  58. bool LLGLTFPreviewTexture::MaterialLoadLevels::operator<(const MaterialLoadLevels& other) const
  59. {
  60. bool less = false;
  61. for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
  62. {
  63. if ((*this)[i] > other[i])
  64. {
  65. return false;
  66. }
  67. less |= (*this)[i] < other[i];
  68. }
  69. return less;
  70. }
  71. bool LLGLTFPreviewTexture::MaterialLoadLevels::operator>(const MaterialLoadLevels& other) const
  72. {
  73. bool great = false;
  74. for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
  75. {
  76. if ((*this)[i] < other[i])
  77. {
  78. return false;
  79. }
  80. great |= (*this)[i] > other[i];
  81. }
  82. return great;
  83. }
  84. // Helper functions
  85. static void fetch_tex_for_ui(LLPointer<LLViewerFetchedTexture>& texp,
  86. const LLUUID& id)
  87. {
  88. if (texp.isNull() && id.notNull())
  89. {
  90. if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(id))
  91. {
  92. LLViewerObject* objp = gSelectMgr.getSelection()->getFirstObject();
  93. if (objp)
  94. {
  95. LLViewerTexture* imgp = objp->getBakedTextureForMagicId(id);
  96. texp = imgp ? imgp->asFetched() : NULL;
  97. }
  98. }
  99. else
  100. {
  101. texp =
  102. LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true,
  103. LLGLTexture::BOOST_PREVIEW,
  104. LLViewerTexture::LOD_TEXTURE);
  105. }
  106. }
  107. if (texp)
  108. {
  109. texp->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
  110. texp->forceToSaveRawImage(0);
  111. }
  112. }
  113. // Note: does not use the same conventions as texture discard level. Lower is
  114. // better.
  115. static S32 get_texture_load_level(LLViewerFetchedTexture* texp)
  116. {
  117. if (!texp)
  118. {
  119. return FULLY_LOADED;
  120. }
  121. S32 raw_level = texp->getDiscardLevel();
  122. return raw_level < 0 ? NOT_LOADED : raw_level;
  123. }
  124. static LLGLTFPreviewTexture::MaterialLoadLevels get_load_levels(LLFetchedGLTFMaterial* matp)
  125. {
  126. llassert(!matp->isFetching());
  127. using MaterialTextures =
  128. LLPointer<LLViewerFetchedTexture>*[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT];
  129. MaterialTextures textures;
  130. textures[BASECOLIDX] = &matp->mBaseColorTexture;
  131. textures[NORMALIDX] = &matp->mNormalTexture;
  132. textures[MROUGHIDX] = &matp->mMetallicRoughnessTexture;
  133. textures[EMISSIVEIDX] = &matp->mEmissiveTexture;
  134. LLGLTFPreviewTexture::MaterialLoadLevels levels;
  135. for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
  136. {
  137. fetch_tex_for_ui(*textures[i], matp->mTextureId[i]);
  138. levels[i] = get_texture_load_level(*textures[i]);
  139. }
  140. return levels;
  141. }
  142. //static
  143. LLPointer<LLViewerTexture> LLGLTFPreviewTexture::getPreview(LLFetchedGLTFMaterial* matp)
  144. {
  145. if (!matp || matp->isFetching())
  146. {
  147. return nullptr;
  148. }
  149. LLGLTFPreviewTexture::MaterialLoadLevels levels = get_load_levels(matp);
  150. for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
  151. {
  152. if (levels[i] == NOT_LOADED)
  153. {
  154. return nullptr;
  155. }
  156. }
  157. return new LLGLTFPreviewTexture(matp);
  158. }
  159. LLGLTFPreviewTexture::LLGLTFPreviewTexture(LLFetchedGLTFMaterial* matp,
  160. S32 width)
  161. : LLViewerDynamicTexture(width, width, 4, EOrder::ORDER_MIDDLE, false),
  162. mGLTFMaterial(matp),
  163. mShouldRender(true)
  164. {
  165. }
  166. //virtual
  167. bool LLGLTFPreviewTexture::needsRender()
  168. {
  169. if (!mShouldRender && mBestLoad.isFullyLoaded())
  170. {
  171. return false;
  172. }
  173. MaterialLoadLevels current_load = get_load_levels(mGLTFMaterial.get());
  174. if (current_load < mBestLoad)
  175. {
  176. mShouldRender = true;
  177. mBestLoad = current_load;
  178. return true;
  179. }
  180. return false;
  181. }
  182. //virtual
  183. void LLGLTFPreviewTexture::preRender(bool clear_depth)
  184. {
  185. if (mShouldRender)
  186. {
  187. LLViewerDynamicTexture::preRender(clear_depth);
  188. }
  189. }
  190. class GLTFPreviewModel
  191. {
  192. public:
  193. GLTFPreviewModel(LLDrawInfo* infop, const LLMatrix4& mat)
  194. : mDrawInfo(infop),
  195. mModelMatrix(mat)
  196. {
  197. mDrawInfo->mModelMatrix = &mModelMatrix;
  198. }
  199. GLTFPreviewModel(GLTFPreviewModel&) = delete;
  200. ~GLTFPreviewModel()
  201. {
  202. // No model matrix necromancy
  203. llassert(gGLLastMatrix != &mModelMatrix);
  204. gGLLastMatrix = NULL;
  205. }
  206. public:
  207. LLPointer<LLDrawInfo> mDrawInfo;
  208. LLMatrix4 mModelMatrix; // Referenced by mDrawInfo
  209. };
  210. using PreviewSpherePart = std::unique_ptr<GLTFPreviewModel>;
  211. using PreviewSphere = std::vector<PreviewSpherePart>;
  212. // Like LLVolumeGeometryManager::registerFace but without batching or
  213. // too-many-indices/vertices checking.
  214. static PreviewSphere create_preview_sphere(LLFetchedGLTFMaterial* matp,
  215. const LLMatrix4& model_matrix)
  216. {
  217. const LLColor4U vertex_color(matp->mBaseColor);
  218. LLPrimitive prim;
  219. prim.setPCode(LL_PCODE_VOLUME);
  220. LLVolumeParams params;
  221. params.setType(LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE);
  222. params.setBeginAndEndS(0.f, 1.f);
  223. params.setBeginAndEndT(0.f, 1.f);
  224. params.setRatio(1, 1);
  225. params.setShear(0, 0);
  226. constexpr auto MAX_LOD = LLVolumeLODGroup::NUM_LODS - 1;
  227. prim.setVolume(params, MAX_LOD);
  228. LLVolume* volp = prim.getVolume();
  229. for (LLVolumeFace& face : volp->getVolumeFaces())
  230. {
  231. face.createTangents();
  232. }
  233. PreviewSphere sphere;
  234. sphere.reserve(volp->getNumFaces());
  235. constexpr U32 mask = LLVertexBuffer::MAP_VERTEX |
  236. LLVertexBuffer::MAP_NORMAL |
  237. LLVertexBuffer::MAP_TEXCOORD0 |
  238. LLVertexBuffer::MAP_COLOR |
  239. LLVertexBuffer::MAP_TANGENT;
  240. LLPointer<LLVertexBuffer> bufp = new LLVertexBuffer(mask);
  241. U32 nv = 0;
  242. U32 ni = 0;
  243. for (LLVolumeFace& face : volp->getVolumeFaces())
  244. {
  245. nv += face.mNumVertices;
  246. ni += face.mNumIndices;
  247. }
  248. bufp->allocateBuffer(nv, ni);
  249. // UV hacks
  250. // Higher factor helps to see more details on the preview sphere
  251. const LLVector2 uv_factor(2.f, 2.f);
  252. // Offset places center of material in center of view
  253. const LLVector2 uv_offset(-0.5f, -0.5f);
  254. LLStrider<U16> indices;
  255. LLStrider<LLVector4a> positions;
  256. LLStrider<LLVector4a> normals;
  257. LLStrider<LLVector2> texcoords;
  258. LLStrider<LLColor4U> colors;
  259. LLStrider<LLVector4a> tangents;
  260. bufp->getIndexStrider(indices);
  261. bufp->getVertexStrider(positions);
  262. bufp->getNormalStrider(normals);
  263. bufp->getTexCoord0Strider(texcoords);
  264. bufp->getColorStrider(colors);
  265. bufp->getTangentStrider(tangents);
  266. U32 index_offset = 0;
  267. U32 vertex_offset = 0;
  268. for (const LLVolumeFace& face : volp->getVolumeFaces())
  269. {
  270. for (S32 i = 0; i < face.mNumIndices; ++i)
  271. {
  272. *indices++ = face.mIndices[i] + vertex_offset;
  273. }
  274. for (S32 v = 0; v < face.mNumVertices; ++v)
  275. {
  276. *positions++ = face.mPositions[v];
  277. *normals++ = face.mNormals[v];
  278. LLVector2 uv(face.mTexCoords[v]);
  279. uv.scaleVec(uv_factor);
  280. uv += uv_offset;
  281. *texcoords++ = uv;
  282. *colors++ = vertex_color;
  283. *tangents++ = face.mTangents[v];
  284. }
  285. LLPointer<LLDrawInfo> infop = new LLDrawInfo(vertex_offset,
  286. vertex_offset +
  287. face.mNumVertices - 1,
  288. face.mNumIndices,
  289. index_offset,
  290. NULL, bufp.get());
  291. infop->mGLTFMaterial = matp;
  292. sphere.emplace_back(std::make_unique<GLTFPreviewModel>(infop,
  293. model_matrix));
  294. index_offset += face.mNumIndices;
  295. vertex_offset += face.mNumVertices;
  296. }
  297. bufp->unmapBuffer();
  298. return sphere;
  299. }
  300. static void set_preview_sphere_material(PreviewSphere& sphere,
  301. LLFetchedGLTFMaterial* matp)
  302. {
  303. if (sphere.empty())
  304. {
  305. llassert(false);
  306. return;
  307. }
  308. const LLColor4U vertex_color(matp->mBaseColor);
  309. // See comments about unmapBuffer in llvertexbuffer.h
  310. for (PreviewSpherePart& part : sphere)
  311. {
  312. LLDrawInfo* infop = part->mDrawInfo.get();
  313. infop->mGLTFMaterial = matp;
  314. LLVertexBuffer* bufp = infop->mVertexBuffer.get();
  315. LLStrider<LLColor4U> colors;
  316. const S32 count = infop->mEnd - infop->mStart + 1;
  317. bufp->getColorStrider(colors, infop->mStart, count);
  318. for (S32 i = 0; i < count; ++i)
  319. {
  320. *colors++ = vertex_color;
  321. }
  322. bufp->unmapBuffer();
  323. }
  324. }
  325. static PreviewSphere& get_preview_sphere(LLFetchedGLTFMaterial* matp,
  326. const LLMatrix4& model_matrix)
  327. {
  328. static PreviewSphere sphere;
  329. if (sphere.empty())
  330. {
  331. sphere = create_preview_sphere(matp, model_matrix);
  332. }
  333. else
  334. {
  335. set_preview_sphere_material(sphere, matp);
  336. }
  337. return sphere;
  338. }
  339. //virtual
  340. bool LLGLTFPreviewTexture::render()
  341. {
  342. if (!mShouldRender || !gUsePBRShaders)
  343. {
  344. return false;
  345. }
  346. glClearColor(0, 0, 0, 0);
  347. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  348. LLGLDepthTest(GL_FALSE);
  349. LLGLDisable scissor(GL_SCISSOR_TEST);
  350. bool old_depth_of_field = LLPipeline::RenderDepthOfField;
  351. LLPipeline::RenderDepthOfField = false;
  352. bool old_glow = LLPipeline::RenderGlow;
  353. LLPipeline::RenderGlow = false;
  354. bool old_space_refl = LLPipeline::RenderScreenSpaceReflections;
  355. LLPipeline::RenderScreenSpaceReflections = false;
  356. U32 old_samples = LLPipeline::RenderFSAASamples;
  357. LLPipeline::RenderFSAASamples = 0;
  358. LLPipeline::RenderTargetPack* old_pack = gPipeline.mRT;
  359. gPipeline.mRT = &gPipeline.mAuxillaryRT;
  360. gPipeline.mReflectionMapManager.forceDefaultProbeAndUpdateUniforms();
  361. LLViewerCamera camera;
  362. // Calculate the object distance at which the object of a given radius will
  363. // span the partial width of the screen given by fill_ratio. Assume the
  364. // primitive has a scale of 1 (this is the default).
  365. constexpr F32 fill_ratio = 0.8f;
  366. constexpr F32 object_radius = 0.5f;
  367. // Negative coordinate shows the textures on the sphere right-side up, when
  368. // combined with the UV hacks in create_preview_sphere
  369. static const LLVector3 obj_pos(0.f,
  370. -(object_radius / fill_ratio) *
  371. tanf(camera.getDefaultFOV()),
  372. 0.f);
  373. LLMatrix4 object_transform;
  374. object_transform.translate(obj_pos);
  375. // Set up camera and viewport
  376. camera.lookAt(LLVector3::zero, obj_pos);
  377. camera.setAspect(mFullHeight / mFullWidth);
  378. const LLRect texture_rect(0, mFullHeight, mFullWidth, 0);
  379. camera.setPerspective(NOT_FOR_SELECTION, texture_rect.mLeft,
  380. texture_rect.mBottom, texture_rect.getWidth(),
  381. texture_rect.getHeight(), false, camera.getNear(),
  382. MAX_FAR_CLIP * 2.f);
  383. // Generate sphere object on-the-fly. Discard afterwards (vertex buffer is
  384. // discarded, but the sphere should be cached in LLVolumeMgr).
  385. PreviewSphere& sphere = get_preview_sphere(mGLTFMaterial.get(),
  386. object_transform);
  387. // Setup a proper preview lighting and freeze it.
  388. HBPreviewLighting preview_lighting;
  389. LLRenderTarget& screen = gPipeline.mAuxillaryRT.mScreen;
  390. LLRenderTarget& depth = gPipeline.mAuxillaryRT.mDeferredScreen;
  391. // *HACK: Force reset of the model matrix
  392. gGLLastMatrix = NULL;
  393. #if 0
  394. if (mGLTFMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_OPAQUE ||
  395. mGLTFMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK)
  396. {
  397. // *TODO: Opaque/alpha mask rendering
  398. }
  399. else
  400. #endif
  401. {
  402. // Alpha blend rendering
  403. screen.bindTarget();
  404. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  405. LLGLSLShader& shader = gDeferredPBRAlphaProgram;
  406. gPipeline.bindDeferredShader(shader);
  407. shader.uniform1f(LLShaderMgr::DENSITY_MULTIPLIER, 0.f);
  408. // Ignore shadows (if enabled)
  409. for (U32 i = 0; i < 6; ++i)
  410. {
  411. S32 chan =
  412. shader.getTextureChannel(LLShaderMgr::DEFERRED_SHADOW0 + i);
  413. if (chan != -1)
  414. {
  415. gGL.getTexUnit(chan)->bind(LLViewerFetchedTexture::sWhiteImagep,
  416. true);
  417. }
  418. }
  419. for (PreviewSpherePart& part : sphere)
  420. {
  421. LLRenderPass::pushGLTFBatch(*part->mDrawInfo);
  422. }
  423. gPipeline.unbindDeferredShader(shader);
  424. screen.flush();
  425. }
  426. gPipeline.copyScreenSpaceReflections(&screen, &gPipeline.mSceneMap);
  427. gPipeline.generateLuminance(&screen, &gPipeline.mLuminanceMap);
  428. constexpr bool DO_NOT_USE_HISTORY = false;
  429. gPipeline.generateExposure(&gPipeline.mLuminanceMap,
  430. &gPipeline.mExposureMap, DO_NOT_USE_HISTORY);
  431. gPipeline.gammaCorrect(&screen, &gPipeline.mPostMap);
  432. LLVertexBuffer::unbind();
  433. gPipeline.generateGlow(&gPipeline.mPostMap);
  434. gPipeline.combineGlow(&gPipeline.mPostMap, &screen);
  435. gPipeline.renderDoF(&screen, &gPipeline.mPostMap);
  436. gPipeline.applyFXAA(&gPipeline.mPostMap, &screen);
  437. // *HACK: restore mExposureMap (it will be consumed by generateExposure()
  438. // at next frame).
  439. gPipeline.mExposureMap.swapFBORefs(gPipeline.mLastExposure);
  440. // Final render
  441. gDeferredPostNoDoFProgram.bind();
  442. // From LLPipeline::renderFinalize: "Whatever is last in the above post
  443. // processing chain should _always_ be rendered directly here. If not,
  444. // expect problems."
  445. gDeferredPostNoDoFProgram.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE,
  446. &screen);
  447. gDeferredPostNoDoFProgram.bindTexture(LLShaderMgr::DEFERRED_DEPTH,
  448. &depth, true);
  449. {
  450. LLGLDepthTest depth_test(GL_TRUE, GL_TRUE, GL_ALWAYS);
  451. gPipeline.mScreenTriangleVB->setBuffer();
  452. gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
  453. }
  454. gDeferredPostNoDoFProgram.unbind();
  455. // Clean up
  456. gPipeline.mReflectionMapManager.forceDefaultProbeAndUpdateUniforms(false);
  457. gPipeline.mRT = old_pack;
  458. LLPipeline::RenderFSAASamples = old_samples;
  459. LLPipeline::RenderScreenSpaceReflections = old_space_refl;
  460. LLPipeline::RenderGlow = old_glow;
  461. LLPipeline::RenderDepthOfField = old_depth_of_field;
  462. return true;
  463. }
  464. //virtual
  465. void LLGLTFPreviewTexture::postRender(bool success)
  466. {
  467. if (mShouldRender)
  468. {
  469. mShouldRender = false;
  470. LLViewerDynamicTexture::postRender(success);
  471. }
  472. }