123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796 |
- /**
- * @file llgltfasset.cpp
- * @brief LL GLTF Implementation
- *
- * $LicenseInfo:firstyear=2024&license=viewergpl$
- *
- * Copyright (c) 2024, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "linden_common.h"
- #include "tinygltf/tiny_gltf.h"
- #include "llgltfasset.h"
- #include "llgltfaccessor.h"
- #include "llshadermgr.h"
- #include "llvolumeoctree.h"
- // Global variable defined in newview (llappviewer.h)
- extern F32 gFrameTimeSeconds;
- // External functions from LLFetchedGLTFMaterial. HB
- extern LLGLTFMaterial* create_fetch_material();
- extern void bind_fetched_material(LLGLTFMaterial* matp);
- // External function from LLTinyGLTFHelper. HB
- extern void get_material_from_model(const std::string& filename,
- const tinygltf::Model& model, S32 mat_idx,
- LLGLTFMaterial* matp,
- std::string& mat_name, bool flip);
- using namespace LLGLTF;
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Node class
- ///////////////////////////////////////////////////////////////////////////////
- Node::Node()
- : mParent(INVALID_INDEX),
- mMesh(INVALID_INDEX),
- mSkin(INVALID_INDEX),
- mMatrixValid(false),
- mTRSValid(false),
- mNeedsApplyMatrix(false)
- {
- }
- void Node::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview)
- {
- mRenderMatrix.matMul(mMatrix, modelview);
- for (auto& idx : mChildren)
- {
- Node& child = asset.mNodes[idx];
- child.updateRenderTransforms(asset, mRenderMatrix);
- }
- }
- void Node::updateTransforms(Asset& asset, const LLMatrix4a& parent_mat)
- {
- makeMatrixValid();
- mAssetMatrix.matMul(mMatrix, parent_mat);
- mAssetMatrixInv = mAssetMatrix;
- mAssetMatrixInv.invert();
- S32 my_index = this - &asset.mNodes[0];
- for (auto& idx : mChildren)
- {
- Node& child = asset.mNodes[idx];
- child.mParent = my_index;
- child.updateTransforms(asset, mAssetMatrix);
- }
- }
- void Node::makeMatrixValid()
- {
- if (!mMatrixValid && mTRSValid)
- {
- // t = sc * rot * trans;
- // t = trans * rot * sc; // Best so far, still wrong on negative scale
- // t = sc * trans * rot;
- glh::matrix4f rot, trans, sc;
- mRotation.get_value(rot);
- trans.set_translate(mTranslation);
- sc.set_scale(mScale);
- glh::matrix4f t = trans * sc * rot;
- mMatrix.loadu(t.m);
- mMatrixValid = true;
- }
- }
- void Node::makeTRSValid()
- {
- if (!mTRSValid && mMatrixValid)
- {
- glh::matrix4f t(mMatrix.getF32ptr());
- glh::vec4f p = t.get_column(3);
- mTranslation.set_value(p.v[0], p.v[1], p.v[2]);
- mScale.set_value(t.get_column(0).length(), t.get_column(1).length(),
- t.get_column(2).length());
- mRotation.set_value(t);
- mTRSValid = true;
- }
- }
- void Node::setRotation(const glh::quaternionf& q)
- {
- makeTRSValid();
- mRotation = q;
- mMatrixValid = false;
- }
- void Node::setTranslation(const glh::vec3f& t)
- {
- makeTRSValid();
- mTranslation = t;
- mMatrixValid = false;
- }
- void Node::setScale(const glh::vec3f& s)
- {
- makeTRSValid();
- mScale = s;
- mMatrixValid = false;
- }
- const Node& Node::operator=(const tinygltf::Node& src)
- {
- F32* dst_mat = mMatrix.getF32ptr();
- if (src.matrix.size() == 16)
- {
- // Node has a transformation matrix, just copy it
- for (U32 i = 0; i < 16; ++i)
- {
- dst_mat[i] = (F32)src.matrix[i];
- }
- mMatrixValid = true;
- }
- else if (!src.rotation.empty() || !src.translation.empty() ||
- !src.scale.empty())
- {
- // Node has rotation/translation/scale, convert to matrix
- if (src.rotation.size() == 4)
- {
- mRotation = glh::quaternionf((F32)src.rotation[0],
- (F32)src.rotation[1],
- (F32)src.rotation[2],
- (F32)src.rotation[3]);
- }
- if (src.translation.size() == 3)
- {
- mTranslation = glh::vec3f((F32)src.translation[0],
- (F32)src.translation[1],
- (F32)src.translation[2]);
- }
- glh::vec3f scale;
- if (src.scale.size() == 3)
- {
- mScale = glh::vec3f((F32)src.scale[0], (F32)src.scale[1],
- (F32)src.scale[2]);
- }
- else
- {
- mScale.set_value(1.f, 1.f, 1.f);
- }
- mTRSValid = true;
- }
- else
- {
- // Node specifies no transformation, set to identity
- mMatrix.setIdentity();
- }
- mChildren = src.children;
- mMesh = src.mesh;
- mSkin = src.skin;
- mName = src.name;
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Asset class
- ///////////////////////////////////////////////////////////////////////////////
- Asset::Asset()
- {
- mLastUpdateTime = gFrameTimeSeconds;
- }
- void Asset::updateTransforms()
- {
- for (auto& scene : mScenes)
- {
- scene.updateTransforms(*this);
- }
- }
- void Asset::updateRenderTransforms(const LLMatrix4a& modelview)
- {
- #if 0
- // Traverse hierarchy and update render transforms from scratch
- for (auto& scene : mScenes)
- {
- scene.updateRenderTransforms(*this, modelview);
- }
- #else
- // Use mAssetMatrix to update render transforms from node list
- for (auto& node : mNodes)
- {
- //if (node.mMesh != INVALID_INDEX)
- {
- node.mRenderMatrix.matMul(node.mAssetMatrix, modelview);
- }
- }
- #endif
- }
- S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
- LLVector4a* intersectp, LLVector2* tcoordp,
- LLVector4a* normalp, LLVector4a* tangentp,
- S32* prim_hitp)
- {
- S32 node_hit = -1;
- S32 primitive_hit = -1;
- LLVector4a p, local_start, local_end;
- LLVector4a asset_end = end;
- for (auto& node : mNodes)
- {
- if (node.mMesh != INVALID_INDEX)
- {
- bool new_hit = false;
- // Transform start and end to this node's local space
- node.mAssetMatrixInv.affineTransform(start, local_start);
- node.mAssetMatrixInv.affineTransform(asset_end, local_end);
- Mesh& mesh = mMeshes[node.mMesh];
- for (auto& primitive : mesh.mPrimitives)
- {
- const LLVolumeTriangle* tri =
- primitive.lineSegmentIntersect(local_start, local_end, &p,
- tcoordp, normalp, tangentp);
- if (tri)
- {
- new_hit = true;
- local_end = p;
- // Pointer math to get the node index
- node_hit = &node - &mNodes[0];
- llassert(&mNodes[node_hit] == &node);
- // Pointer math to get the primitive index
- primitive_hit = &primitive - &mesh.mPrimitives[0];
- llassert(&mesh.mPrimitives[primitive_hit] == &primitive);
- }
- }
- if (new_hit)
- {
- // Shorten line segment on hit
- node.mAssetMatrix.affineTransform(p, asset_end);
- // Transform results back to asset space
- if (intersectp)
- {
- *intersectp = asset_end;
- }
- if (normalp || tangentp)
- {
- LLMatrix4 normal_mat4(node.mAssetMatrixInv.getF32ptr());
- normal_mat4.transpose();
- LLMatrix4a norm_mat;
- norm_mat.loadu(normal_mat4.getF32ptr());
- if (normalp)
- {
- LLVector4a n = *normalp;
- F32 w = n.getF32ptr()[3];
- n.getF32ptr()[3] = 0.0f;
- norm_mat.affineTransform(n, *normalp);
- normalp->getF32ptr()[3] = w;
- }
- if (tangentp)
- {
- LLVector4a t = *tangentp;
- F32 w = t.getF32ptr()[3];
- t.getF32ptr()[3] = 0.0f;
- norm_mat.affineTransform(t, *tangentp);
- tangentp->getF32ptr()[3] = w;
- }
- }
- }
- }
- }
- if (node_hit != -1)
- {
- if (prim_hitp)
- {
- *prim_hitp = primitive_hit;
- }
- }
- return node_hit;
- }
- void Asset::render(bool opaque, bool rigged)
- {
- if (rigged)
- {
- gGL.loadIdentity();
- }
- for (auto& node : mNodes)
- {
- if (node.mSkin != INVALID_INDEX)
- {
- if (rigged)
- {
- Skin& skin = mSkins[node.mSkin];
- skin.uploadMatrixPalette(*this, node);
- }
- else
- {
- // Skip static nodes if we are rendering rigged
- continue;
- }
- }
- else if (rigged)
- {
- // Skip rigged nodes if we are not rendering rigged
- continue;
- }
- if (node.mMesh != INVALID_INDEX)
- {
- Mesh& mesh = mMeshes[node.mMesh];
- for (auto& primitive : mesh.mPrimitives)
- {
- if (!rigged)
- {
- gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix);
- }
- bool cull = true;
- if (primitive.mMaterial != INVALID_INDEX)
- {
- Material& material = mMaterials[primitive.mMaterial];
- if ((material.mMaterial->mAlphaMode ==
- LLGLTFMaterial::ALPHA_MODE_BLEND) == opaque)
- {
- continue;
- }
- bind_fetched_material(material.mMaterial);
- cull = !material.mMaterial->mDoubleSided;
- }
- else
- {
- if (!opaque)
- {
- continue;
- }
- bind_fetched_material(NULL);
- }
- LLVertexBuffer* buffp = primitive.mVertexBuffer;
- if (!buffp) continue;
- LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0);
- buffp->setBuffer();
- U32 num_indices = buffp->getNumIndices();
- if (num_indices > 0)
- {
- buffp->draw(primitive.mGLMode, num_indices, 0);
- }
- else
- {
- buffp->drawArrays(primitive.mGLMode, 0,
- buffp->getNumVerts());
- }
- }
- }
- }
- }
- void Asset::renderOpaque()
- {
- render(true);
- }
- void Asset::renderTransparent()
- {
- render(false);
- }
- void Asset::update()
- {
- F32 dt = gFrameTimeSeconds - mLastUpdateTime;
- if (dt <= 0.f)
- {
- return;
- }
- mLastUpdateTime = gFrameTimeSeconds;
- if (mAnimations.size() > 0)
- {
- #if 0 // For now, these settings are not even listed in LL's viewer
- // app_settings/settings.xml, so they default to 0 and 1.f
- // respectively. If configuration is ever to be provided, just use
- // static variables in the LLGLTF::Asset class and setter methods to
- // set them on viewer launch from llappviewer.cpp, and on change from
- // llviewercontrol.cpp... HB
- static LLCachedControl<U32> anim_idx(gSavedSettings,
- "GLTFAnimationIndex", 0);
- static LLCachedControl<F32> anim_speed(gSavedSettings,
- "GLTFAnimationSpeed", 1.f);
- U32 idx = llclamp(anim_idx(), 0U, mAnimations.size() - 1);
- #else
- constexpr U32 idx = 0;
- constexpr F32 anim_speed = 1.f;
- #endif
- mAnimations[idx].update(*this, dt * anim_speed);
- }
- updateTransforms();
- }
- bool Asset::allocateGLResources(const std::string& filename,
- const tinygltf::Model& model)
- {
- // Do images first as materials may depend on images
- for (auto& image : mImages)
- {
- image.allocateGLResources();
- }
- // Do materials before meshes as meshes may depend on materials
- for (size_t i = 0, count = mMaterials.size(); i < count; ++i)
- {
- mMaterials[i].allocateGLResources(*this);
- get_material_from_model(filename, model, i, mMaterials[i].mMaterial,
- mMaterials[i].mName, true);
- }
- for (auto& mesh : mMeshes)
- {
- if (!mesh.allocateGLResources(*this))
- {
- // Too many vertice: aborted ! HB
- return false;
- }
- }
- for (auto& animation : mAnimations)
- {
- animation.allocateGLResources(*this);
- }
- for (auto& skin : mSkins)
- {
- skin.allocateGLResources(*this);
- }
- return true;
- }
- const Asset& Asset::operator=(const tinygltf::Model& src)
- {
- size_t count = src.scenes.size();
- mScenes.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mScenes[i] = src.scenes[i];
- }
- count = src.nodes.size();
- mNodes.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mNodes[i] = src.nodes[i];
- }
- count = src.meshes.size();
- mMeshes.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mMeshes[i] = src.meshes[i];
- }
- count = src.materials.size();
- mMaterials.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mMaterials[i] = src.materials[i];
- }
- count = src.buffers.size();
- mBuffers.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mBuffers[i] = src.buffers[i];
- }
- count = src.bufferViews.size();
- mBufferViews.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mBufferViews[i] = src.bufferViews[i];
- }
- count = src.textures.size();
- mTextures.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mTextures[i] = src.textures[i];
- }
- count = src.samplers.size();
- mSamplers.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mSamplers[i] = src.samplers[i];
- }
- count = src.images.size();
- mImages.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mImages[i] = src.images[i];
- }
- count = src.accessors.size();
- mAccessors.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mAccessors[i] = src.accessors[i];
- }
- count = src.animations.size();
- mAnimations.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mAnimations[i] = src.animations[i];
- }
- count = src.skins.size();
- mSkins.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mSkins[i] = src.skins[i];
- }
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Material class
- ///////////////////////////////////////////////////////////////////////////////
- const Material& Material::operator=(const tinygltf::Material& src)
- {
- mName = src.name;
- return *this;
- }
- void Material::allocateGLResources(Asset& asset)
- {
- // Allocate material
- mMaterial = create_fetch_material();
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Mesh class
- ///////////////////////////////////////////////////////////////////////////////
- const Mesh& Mesh::operator=(const tinygltf::Mesh& src)
- {
- size_t count = src.primitives.size();
- mPrimitives.resize(count);
- for (size_t i = 0; i < count; ++i)
- {
- mPrimitives[i] = src.primitives[i];
- }
- mWeights = src.weights;
- mName = src.name;
- return *this;
- }
- bool Mesh::allocateGLResources(Asset& asset)
- {
- for (auto& primitive : mPrimitives)
- {
- if (!primitive.allocateGLResources(asset))
- {
- // Too many vertice: aborted ! HB
- return false;
- }
- }
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Scene class
- ///////////////////////////////////////////////////////////////////////////////
- void Scene::updateTransforms(Asset& asset)
- {
- LLMatrix4a identity;
- identity.setIdentity();
- for (auto& idx : mNodes)
- {
- Node& node = asset.mNodes[idx];
- node.updateTransforms(asset, identity);
- }
- }
- void Scene::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview)
- {
- for (auto& idx : mNodes)
- {
- Node& node = asset.mNodes[idx];
- node.updateRenderTransforms(asset, modelview);
- }
- }
- const Scene& Scene::operator=(const tinygltf::Scene& src)
- {
- mNodes = src.nodes;
- mName = src.name;
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Texture class
- ///////////////////////////////////////////////////////////////////////////////
- Texture::Texture()
- : mSampler(INVALID_INDEX),
- mSource(INVALID_INDEX)
- {
- }
- const Texture& Texture::operator=(const tinygltf::Texture& src)
- {
- mSampler = src.sampler;
- mSource = src.source;
- mName = src.name;
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Image class
- ///////////////////////////////////////////////////////////////////////////////
- const Image& Image::operator=(const tinygltf::Image& src)
- {
- mName = src.name;
- mUri = src.uri;
- mMimeType = src.mimeType;
- mData = src.image;
- mWidth = src.width;
- mHeight = src.height;
- mComponent = src.component;
- mBits = src.bits;
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Sampler class
- ///////////////////////////////////////////////////////////////////////////////
- const Sampler& Sampler::operator=(const tinygltf::Sampler& src)
- {
- mMagFilter = src.magFilter;
- mMinFilter = src.minFilter;
- mWrapS = src.wrapS;
- mWrapT = src.wrapT;
- mName = src.name;
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Skin class
- ///////////////////////////////////////////////////////////////////////////////
- Skin::Skin()
- : mInverseBindMatrices(INVALID_INDEX),
- mSkeleton(INVALID_INDEX)
- {
- }
- const Skin& Skin::operator=(const tinygltf::Skin& src)
- {
- mName = src.name;
- mSkeleton = src.skeleton;
- mInverseBindMatrices = src.inverseBindMatrices;
- mJoints = src.joints;
- return *this;
- }
- void Skin::uploadMatrixPalette(Asset& asset, Node& node)
- {
- // Prepare matrix palette
- // Model view will be applied by the shader, so assume matrix palette is in
- // asset space
- std::vector<glh::matrix4f> t_mp;
- t_mp.resize(mJoints.size());
- for (U32 i = 0; i < mJoints.size(); ++i)
- {
- Node& joint = asset.mNodes[mJoints[i]];
- //t_mp[i].set_value(joint.mRenderMatrix.getF32ptr());
- //t_mp[i] = t_mp[i] * mInverseBindMatricesData[i];
- //t_mp[i].set_value(joint.mRenderMatrix.getF32ptr());
- //t_mp[i] = mInverseBindMatricesData[i] * t_mp[i];
- t_mp[i].set_value(joint.mRenderMatrix.getF32ptr());
- t_mp[i] = t_mp[i] * mInverseBindMatricesData[i];
- }
- std::vector<F32> glmp;
- glmp.resize(mJoints.size() * 12);
- F32* mp = glmp.data();
- for (U32 i = 0; i < mJoints.size(); ++i)
- {
- F32* m = (F32*)t_mp[i].m;
- U32 idx = i * 12;
- mp[idx + 0] = m[0];
- mp[idx + 1] = m[1];
- mp[idx + 2] = m[2];
- mp[idx + 3] = m[12];
- mp[idx + 4] = m[4];
- mp[idx + 5] = m[5];
- mp[idx + 6] = m[6];
- mp[idx + 7] = m[13];
- mp[idx + 8] = m[8];
- mp[idx + 9] = m[9];
- mp[idx + 10] = m[10];
- mp[idx + 11] = m[14];
- }
- LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLShaderMgr::AVATAR_MATRIX,
- mJoints.size(), GL_FALSE,
- (F32*)glmp.data());
- }
|