From b2a450a3087fb8393024876f6069a7cec9855bfd Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Tue, 9 Apr 2024 19:21:10 -0500 Subject: #1126 gltf scene import prototype (#1172) * #1126 GLTF Scene import initial prototype (working geometry import for some assets) * #1126 WIP -- Expand support for more vertex formats, PoC material import, shadow support, scale support * #1126 move GLTF implementation to newview/gltf * #1126 Refactor attribute loading to be less copy/pasta for each combination of types * #1126 Partially working object selection. Ability to have multiple scenes at once. Helpful message on how to use the preview button. * #1126 Add bounding box debug display and untangle GLTF raycast from LLVOVolume raycast * #1126 Working raycast on GLTF scenes. * #1126 Remove some #pragma optimize offs --- indra/newview/gltf/primitive.cpp | 480 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 480 insertions(+) create mode 100644 indra/newview/gltf/primitive.cpp (limited to 'indra/newview/gltf/primitive.cpp') diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp new file mode 100644 index 0000000000..dca3ccf706 --- /dev/null +++ b/indra/newview/gltf/primitive.cpp @@ -0,0 +1,480 @@ +/** + * @file primitive.cpp + * @brief LL GLTF Implementation + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "asset.h" +#include "../lltinygltfhelper.h" + +using namespace LL::GLTF; + +#ifndef __PRETTY_FUNCTION__ +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif + +// copy one vec3 from src to dst +template +void copyVec2(S* src, T& dst) +{ + LL_ERRS() << "TODO: implement " << __PRETTY_FUNCTION__ << LL_ENDL; +} + +// copy one vec3 from src to dst +template +void copyVec3(S* src, T& dst) +{ + LL_ERRS() << "TODO: implement " << __PRETTY_FUNCTION__ << LL_ENDL; +} + +// copy one vec4 from src to dst +template +void copyVec4(S* src, T& dst) +{ + LL_ERRS() << "TODO: implement " << __PRETTY_FUNCTION__ << LL_ENDL; +} + +template<> +void copyVec2(F32* src, LLVector2& dst) +{ + dst.set(src[0], src[1]); +} + +template<> +void copyVec3(F32* src, LLVector4a& dst) +{ + dst.load3(src); +} + +template<> +void copyVec3(U16* src, LLColor4U& dst) +{ + dst.set(src[0], src[1], src[2], 255); +} + +template<> +void copyVec4(F32* src, LLVector4a& dst) +{ + dst.loadua(src); +} + +// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy +template +void copyVec2(S* src, LLStrider dst, S32 stride, S32 count) +{ + for (S32 i = 0; i < count; ++i) + { + copyVec2(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } +} + +// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy +template +void copyVec3(S* src, LLStrider dst, S32 stride, S32 count) +{ + for (S32 i = 0; i < count; ++i) + { + copyVec3(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } +} + +// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy +template +void copyVec4(S* src, LLStrider dst, S32 stride, S32 count) +{ + for (S32 i = 0; i < count; ++i) + { + copyVec3(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } +} + +template +void copyAttributeArray(Asset& asset, const Accessor& accessor, const S* src, LLStrider& dst, S32 byteStride) +{ + if (accessor.mType == TINYGLTF_TYPE_VEC2) + { + S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride; + copyVec2((S*)src, dst, stride, accessor.mCount); + } + else if (accessor.mType == TINYGLTF_TYPE_VEC3) + { + S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride; + copyVec3((S*)src, dst, stride, accessor.mCount); + } + else if (accessor.mType == TINYGLTF_TYPE_VEC4) + { + S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride; + copyVec4((S*)src, dst, stride, accessor.mCount); + } + else + { + LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL; + } +} + +template +void Primitive::copyAttribute(Asset& asset, S32 accessorIdx, LLStrider& dst) +{ + const Accessor& accessor = asset.mAccessors[accessorIdx]; + const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView]; + const Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; + const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; + + if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT) + { + copyAttributeArray(asset, accessor, (const F32*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) + { + copyAttributeArray(asset, accessor, (const U16*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) + { + copyAttributeArray(asset, accessor, (const U32*)src, dst, bufferView.mByteStride); + } + else + + { + LL_ERRS() << "Unsupported component type" << LL_ENDL; + } +} + +void Primitive::allocateGLResources(Asset& asset) +{ + // allocate vertex buffer + // We diverge from the intent of the GLTF format here to work with our existing render pipeline + // GLTF wants us to copy the buffer views into GPU storage as is and build render commands that source that data. + // For our engine, though, it's better to rearrange the buffers at load time into a layout that's more consistent. + // The GLTF native approach undoubtedly works well if you can count on VAOs, but VAOs perform much worse with our scenes. + + // get the number of vertices + U32 numVertices = 0; + for (auto& it : mAttributes) + { + const Accessor& accessor = asset.mAccessors[it.second]; + numVertices = accessor.mCount; + break; + } + + // get the number of indices + U32 numIndices = 0; + if (mIndices != INVALID_INDEX) + { + const Accessor& accessor = asset.mAccessors[mIndices]; + numIndices = accessor.mCount; + } + + // create vertex buffer + mVertexBuffer = new LLVertexBuffer(ATTRIBUTE_MASK); + mVertexBuffer->allocateBuffer(numVertices, numIndices); + + bool needs_color = true; + bool needs_texcoord = true; + bool needs_normal = true; + bool needs_tangent = true; + + // load vertex data + for (auto& it : mAttributes) + { + const std::string& attribName = it.first; + + // load vertex data + if (attribName == "POSITION") + { + // load position data + LLStrider dst; + mVertexBuffer->getVertexStrider(dst); + + copyAttribute(asset, it.second, dst); + } + else if (attribName == "NORMAL") + { + needs_normal = false; + // load normal data + LLStrider dst; + mVertexBuffer->getNormalStrider(dst); + + copyAttribute(asset, it.second, dst); + } + else if (attribName == "TANGENT") + { + needs_tangent = false; + // load tangent data + + LLStrider dst; + mVertexBuffer->getTangentStrider(dst); + + copyAttribute(asset, it.second, dst); + } + else if (attribName == "COLOR_0") + { + needs_color = false; + // load color data + + LLStrider dst; + mVertexBuffer->getColorStrider(dst); + + copyAttribute(asset, it.second, dst); + } + else if (attribName == "TEXCOORD_0") + { + needs_texcoord = false; + // load texcoord data + LLStrider dst; + mVertexBuffer->getTexCoord0Strider(dst); + + LLStrider tc = dst; + copyAttribute(asset, it.second, dst); + + // convert to OpenGL coordinate space + for (U32 i = 0; i < numVertices; ++i) + { + tc->mV[1] = 1.0f - tc->mV[1];; + tc++; + } + } + } + + // copy index buffer + if (mIndices != INVALID_INDEX) + { + const Accessor& accessor = asset.mAccessors[mIndices]; + const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView]; + const Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; + + const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; + + LLStrider dst; + mVertexBuffer->getIndexStrider(dst); + mIndexArray.resize(numIndices); + + if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) + { + for (U32 i = 0; i < numIndices; ++i) + { + *(dst++) = (U16) * (U32*)src; + src += sizeof(U32); + } + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) + { + for (U32 i = 0; i < numIndices; ++i) + { + *(dst++) = *(U16*)src; + src += sizeof(U16); + } + } + else + { + LL_ERRS("GLTF") << "Unsupported component type for indices" << LL_ENDL; + } + + U16* idx = (U16*)mVertexBuffer->getMappedIndices(); + for (U32 i = 0; i < numIndices; ++i) + { + mIndexArray[i] = idx[i]; + } + } + + // fill in default values for missing attributes + if (needs_color) + { // set default color + LLStrider dst; + mVertexBuffer->getColorStrider(dst); + for (U32 i = 0; i < numVertices; ++i) + { + *(dst++) = LLColor4U(255, 255, 255, 255); + } + } + + if (needs_texcoord) + { // set default texcoord + LLStrider dst; + mVertexBuffer->getTexCoord0Strider(dst); + for (U32 i = 0; i < numVertices; ++i) + { + *(dst++) = LLVector2(0.0f, 0.0f); + } + } + + if (needs_normal) + { // set default normal + LLStrider dst; + mVertexBuffer->getNormalStrider(dst); + for (U32 i = 0; i < numVertices; ++i) + { + *(dst++) = LLVector4a(0.0f, 0.0f, 1.0f, 0.0f); + } + } + + if (needs_tangent) + { // TODO: generate tangents if needed + LLStrider dst; + mVertexBuffer->getTangentStrider(dst); + for (U32 i = 0; i < numVertices; ++i) + { + *(dst++) = LLVector4a(1.0f, 0.0f, 0.0f, 1.0f); + } + } + + mPositions.resize(numVertices); + mTexCoords.resize(numVertices); + mNormals.resize(numVertices); + mTangents.resize(numVertices); + + LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); + LLVector2* tc = (LLVector2*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_TEXCOORD0)); + LLVector4a* norm = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_NORMAL)); + LLVector4a* tangent = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_TANGENT)); + for (U32 i = 0; i < numVertices; ++i) + { + mPositions[i] = pos[i]; + mTexCoords[i] = tc[i]; + mNormals[i] = norm[i]; + mTangents[i] = tangent[i]; + } + createOctree(); + + mVertexBuffer->unmapBuffer(); +} + +void Primitive::createOctree() +{ + // create octree + mOctree = new LLVolumeOctree(); + + if (mMode == TINYGLTF_MODE_TRIANGLES) + { + F32 scaler = 0.25f; + + const U32 num_triangles = mVertexBuffer->getNumIndices() / 3; + // Initialize all the triangles we need + mOctreeTriangles.resize(num_triangles); + + LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); + U16* indices = (U16*)mVertexBuffer->getMappedIndices(); + + for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) + { //for each triangle + const U32 index = triangle_index * 3; + LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; + const LLVector4a& v0 = pos[indices[index]]; + const LLVector4a& v1 = pos[indices[index + 1]]; + const LLVector4a& v2 = pos[indices[index + 2]]; + + //store pointers to vertex data + tri->mV[0] = &v0; + tri->mV[1] = &v1; + tri->mV[2] = &v2; + + //store indices + tri->mIndex[0] = indices[index]; + tri->mIndex[1] = indices[index + 1]; + tri->mIndex[2] = indices[index + 2]; + + //get minimum point + LLVector4a min = v0; + min.setMin(min, v1); + min.setMin(min, v2); + + //get maximum point + LLVector4a max = v0; + max.setMax(max, v1); + max.setMax(max, v2); + + //compute center + LLVector4a center; + center.setAdd(min, max); + center.mul(0.5f); + + tri->mPositionGroup = center; + + //compute "radius" + LLVector4a size; + size.setSub(max, min); + + tri->mRadius = size.getLength3().getF32() * scaler; + + //insert + mOctree->insert(tri); + } + } + else + { + LL_ERRS() << "Unsupported Primitive mode" << LL_ENDL; + } + + //remove unneeded octree layers + while (!mOctree->balance()) {} + + //calculate AABB for each node + LLVolumeOctreeRebound rebound; + rebound.traverse(mOctree); +} + +const LLVolumeTriangle* Primitive::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent_out) +{ + if (mOctree.isNull()) + { + return nullptr; + } + + LLVector4a dir; + dir.setSub(end, start); + + F32 closest_t = 2.f; // must be larger than 1 + + //create a proxy LLVolumeFace for the raycast + LLVolumeFace face; + face.mPositions = mPositions.data(); + face.mTexCoords = mTexCoords.data(); + face.mNormals = mNormals.data(); + face.mTangents = mTangents.data(); + face.mIndices = mIndexArray.data(); + + face.mNumIndices = mIndexArray.size(); + face.mNumVertices = mPositions.size(); + + LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out); + intersect.traverse(mOctree); + + // null out proxy data so it doesn't get freed + face.mPositions = face.mNormals = face.mTangents = nullptr; + face.mIndices = nullptr; + face.mTexCoords = nullptr; + + return intersect.mHitTriangle; +} + +Primitive::~Primitive() +{ + mOctree = nullptr; +} + -- cgit v1.2.3 From 720f7d7ef5d06366cdbae51cd67a6883e994880b Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Wed, 10 Apr 2024 11:25:07 -0500 Subject: Fix mac build (#1182) * Fix mac build * Mac build take 2 * Mac build take 3 --- indra/newview/gltf/primitive.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'indra/newview/gltf/primitive.cpp') diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index dca3ccf706..71654dcfdd 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -9,7 +9,7 @@ * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; - * version 2.1 of the License only. + * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -24,34 +24,38 @@ * $/LicenseInfo$ */ +#include "../llviewerprecompiledheaders.h" + #include "asset.h" #include "../lltinygltfhelper.h" using namespace LL::GLTF; -#ifndef __PRETTY_FUNCTION__ -#define __PRETTY_FUNCTION__ __FUNCSIG__ +#ifdef _MSC_VER +#define LL_FUNCSIG __FUNCSIG__ +#else +#define LL_FUNCSIG __PRETTY_FUNCTION__ #endif // copy one vec3 from src to dst template void copyVec2(S* src, T& dst) { - LL_ERRS() << "TODO: implement " << __PRETTY_FUNCTION__ << LL_ENDL; + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; } // copy one vec3 from src to dst template void copyVec3(S* src, T& dst) { - LL_ERRS() << "TODO: implement " << __PRETTY_FUNCTION__ << LL_ENDL; + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; } // copy one vec4 from src to dst template void copyVec4(S* src, T& dst) { - LL_ERRS() << "TODO: implement " << __PRETTY_FUNCTION__ << LL_ENDL; + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; } template<> -- cgit v1.2.3 From bc93177ea0788a245554882b6d721eae2e057206 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Wed, 17 Apr 2024 16:12:49 -0500 Subject: 1176 integrate llgltfnode with selection manager and llmaniptranslate/rotate (#1258) * #1176 Somewhat working GLTF Node support for translate tool * #1176 Missing file from last commit * #1176 Better translation for rotated nodes. * #1176 Fix for objects snapping back to original position * #1176 GLTF Samples compatibility pass -- attempt at improving rotation manip support, incidental cleanup, GLTF node debug display * #1176 Clean out some unused and not working functions. * #1176 Fix for mac build, incidental cleanup * Mac build fix --- indra/newview/gltf/primitive.cpp | 180 +++++++++++++++++++++++++++++++-------- 1 file changed, 145 insertions(+), 35 deletions(-) (limited to 'indra/newview/gltf/primitive.cpp') diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index 71654dcfdd..b5d59e1b24 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -162,10 +162,25 @@ void Primitive::copyAttribute(Asset& asset, S32 accessorIdx, LLStrider& dst) { copyAttributeArray(asset, accessor, (const U32*)src, dst, bufferView.mByteStride); } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) + { + copyAttributeArray(asset, accessor, (const U8*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_SHORT) + { + copyAttributeArray(asset, accessor, (const S16*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_BYTE) + { + copyAttributeArray(asset, accessor, (const S8*)src, dst, bufferView.mByteStride); + } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) + { + copyAttributeArray(asset, accessor, (const F64*)src, dst, bufferView.mByteStride); + } else - { - LL_ERRS() << "Unsupported component type" << LL_ENDL; + LL_ERRS("GLTF") << "Unsupported component type" << LL_ENDL; } } @@ -179,11 +194,11 @@ void Primitive::allocateGLResources(Asset& asset) // get the number of vertices U32 numVertices = 0; - for (auto& it : mAttributes) + if (!mAttributes.empty()) { - const Accessor& accessor = asset.mAccessors[it.second]; + auto it = mAttributes.begin(); + const Accessor& accessor = asset.mAccessors[it->second]; numVertices = accessor.mCount; - break; } // get the number of indices @@ -294,6 +309,14 @@ void Primitive::allocateGLResources(Asset& asset) src += sizeof(U16); } } + else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) + { + for (U32 i = 0; i < numIndices; ++i) + { + *(dst++) = *(U8*)src; + src += sizeof(U8); + } + } else { LL_ERRS("GLTF") << "Unsupported component type for indices" << LL_ENDL; @@ -317,6 +340,22 @@ void Primitive::allocateGLResources(Asset& asset) } } + // bake material basecolor into color array + if (mMaterial != INVALID_INDEX) + { + const Material& material = asset.mMaterials[mMaterial]; + LLColor4 baseColor = material.mMaterial->mBaseColor; + LLStrider dst; + mVertexBuffer->getColorStrider(dst); + + for (U32 i = 0; i < numVertices; ++i) + { + LLColor4 col = *dst; + *dst = LLColor4U(baseColor * col); + dst++; + } + } + if (needs_texcoord) { // set default texcoord LLStrider dst; @@ -368,15 +407,51 @@ void Primitive::allocateGLResources(Asset& asset) mVertexBuffer->unmapBuffer(); } +void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2) +{ + //store pointers to vertex data + tri->mV[0] = &v0; + tri->mV[1] = &v1; + tri->mV[2] = &v2; + + //store indices + tri->mIndex[0] = i0; + tri->mIndex[1] = i1; + tri->mIndex[2] = i2; + + //get minimum point + LLVector4a min = v0; + min.setMin(min, v1); + min.setMin(min, v2); + + //get maximum point + LLVector4a max = v0; + max.setMax(max, v1); + max.setMax(max, v2); + + //compute center + LLVector4a center; + center.setAdd(min, max); + center.mul(0.5f); + + tri->mPositionGroup = center; + + //compute "radius" + LLVector4a size; + size.setSub(max, min); + + tri->mRadius = size.getLength3().getF32() * scaler; +} + void Primitive::createOctree() { // create octree mOctree = new LLVolumeOctree(); + F32 scaler = 0.25f; + if (mMode == TINYGLTF_MODE_TRIANGLES) { - F32 scaler = 0.25f; - const U32 num_triangles = mVertexBuffer->getNumIndices() / 3; // Initialize all the triangles we need mOctreeTriangles.resize(num_triangles); @@ -388,47 +463,82 @@ void Primitive::createOctree() { //for each triangle const U32 index = triangle_index * 3; LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; - const LLVector4a& v0 = pos[indices[index]]; - const LLVector4a& v1 = pos[indices[index + 1]]; - const LLVector4a& v2 = pos[indices[index + 2]]; + S32 i0 = indices[index]; + S32 i1 = indices[index + 1]; + S32 i2 = indices[index + 2]; + + const LLVector4a& v0 = pos[i0]; + const LLVector4a& v1 = pos[i1]; + const LLVector4a& v2 = pos[i2]; + + initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); + + //insert + mOctree->insert(tri); + } + } + else if (mMode == TINYGLTF_MODE_TRIANGLE_STRIP) + { + const U32 num_triangles = mVertexBuffer->getNumIndices() - 2; + // Initialize all the triangles we need + mOctreeTriangles.resize(num_triangles); - //store pointers to vertex data - tri->mV[0] = &v0; - tri->mV[1] = &v1; - tri->mV[2] = &v2; + LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); + U16* indices = (U16*)mVertexBuffer->getMappedIndices(); - //store indices - tri->mIndex[0] = indices[index]; - tri->mIndex[1] = indices[index + 1]; - tri->mIndex[2] = indices[index + 2]; + for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) + { //for each triangle + const U32 index = triangle_index + 2; + LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; + S32 i0 = indices[index]; + S32 i1 = indices[index - 1]; + S32 i2 = indices[index - 2]; + + const LLVector4a& v0 = pos[i0]; + const LLVector4a& v1 = pos[i1]; + const LLVector4a& v2 = pos[i2]; - //get minimum point - LLVector4a min = v0; - min.setMin(min, v1); - min.setMin(min, v2); + initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); - //get maximum point - LLVector4a max = v0; - max.setMax(max, v1); - max.setMax(max, v2); + //insert + mOctree->insert(tri); + } + } + else if (mMode == TINYGLTF_MODE_TRIANGLE_FAN) + { + const U32 num_triangles = mVertexBuffer->getNumIndices() - 2; + // Initialize all the triangles we need + mOctreeTriangles.resize(num_triangles); - //compute center - LLVector4a center; - center.setAdd(min, max); - center.mul(0.5f); + LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); + U16* indices = (U16*)mVertexBuffer->getMappedIndices(); - tri->mPositionGroup = center; + for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) + { //for each triangle + const U32 index = triangle_index + 2; + LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; + S32 i0 = indices[0]; + S32 i1 = indices[index - 1]; + S32 i2 = indices[index - 2]; - //compute "radius" - LLVector4a size; - size.setSub(max, min); + const LLVector4a& v0 = pos[i0]; + const LLVector4a& v1 = pos[i1]; + const LLVector4a& v2 = pos[i2]; - tri->mRadius = size.getLength3().getF32() * scaler; + initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); //insert mOctree->insert(tri); } } + else if (mMode == TINYGLTF_MODE_POINTS || + mMode == TINYGLTF_MODE_LINE || + mMode == TINYGLTF_MODE_LINE_LOOP || + mMode == TINYGLTF_MODE_LINE_STRIP) + { + // nothing to do, no volume... maybe add some collision geometry around these primitive types? + } + else { LL_ERRS() << "Unsupported Primitive mode" << LL_ENDL; -- cgit v1.2.3 From cadc1a02cc7289dabd368dd1a1d237c042e9f82e Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Wed, 24 Apr 2024 09:51:15 -0500 Subject: 1285 GLTF Animation Prototype --- indra/newview/gltf/primitive.cpp | 488 ++++++++++++--------------------------- 1 file changed, 147 insertions(+), 341 deletions(-) (limited to 'indra/newview/gltf/primitive.cpp') diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index b5d59e1b24..b57a0af18d 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -27,163 +27,12 @@ #include "../llviewerprecompiledheaders.h" #include "asset.h" +#include "buffer_util.h" + #include "../lltinygltfhelper.h" using namespace LL::GLTF; -#ifdef _MSC_VER -#define LL_FUNCSIG __FUNCSIG__ -#else -#define LL_FUNCSIG __PRETTY_FUNCTION__ -#endif - -// copy one vec3 from src to dst -template -void copyVec2(S* src, T& dst) -{ - LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; -} - -// copy one vec3 from src to dst -template -void copyVec3(S* src, T& dst) -{ - LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; -} - -// copy one vec4 from src to dst -template -void copyVec4(S* src, T& dst) -{ - LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; -} - -template<> -void copyVec2(F32* src, LLVector2& dst) -{ - dst.set(src[0], src[1]); -} - -template<> -void copyVec3(F32* src, LLVector4a& dst) -{ - dst.load3(src); -} - -template<> -void copyVec3(U16* src, LLColor4U& dst) -{ - dst.set(src[0], src[1], src[2], 255); -} - -template<> -void copyVec4(F32* src, LLVector4a& dst) -{ - dst.loadua(src); -} - -// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy -template -void copyVec2(S* src, LLStrider dst, S32 stride, S32 count) -{ - for (S32 i = 0; i < count; ++i) - { - copyVec2(src, *dst); - dst++; - src = (S*)((U8*)src + stride); - } -} - -// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy -template -void copyVec3(S* src, LLStrider dst, S32 stride, S32 count) -{ - for (S32 i = 0; i < count; ++i) - { - copyVec3(src, *dst); - dst++; - src = (S*)((U8*)src + stride); - } -} - -// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy -template -void copyVec4(S* src, LLStrider dst, S32 stride, S32 count) -{ - for (S32 i = 0; i < count; ++i) - { - copyVec3(src, *dst); - dst++; - src = (S*)((U8*)src + stride); - } -} - -template -void copyAttributeArray(Asset& asset, const Accessor& accessor, const S* src, LLStrider& dst, S32 byteStride) -{ - if (accessor.mType == TINYGLTF_TYPE_VEC2) - { - S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride; - copyVec2((S*)src, dst, stride, accessor.mCount); - } - else if (accessor.mType == TINYGLTF_TYPE_VEC3) - { - S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride; - copyVec3((S*)src, dst, stride, accessor.mCount); - } - else if (accessor.mType == TINYGLTF_TYPE_VEC4) - { - S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride; - copyVec4((S*)src, dst, stride, accessor.mCount); - } - else - { - LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL; - } -} - -template -void Primitive::copyAttribute(Asset& asset, S32 accessorIdx, LLStrider& dst) -{ - const Accessor& accessor = asset.mAccessors[accessorIdx]; - const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView]; - const Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; - const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; - - if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT) - { - copyAttributeArray(asset, accessor, (const F32*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) - { - copyAttributeArray(asset, accessor, (const U16*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) - { - copyAttributeArray(asset, accessor, (const U32*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) - { - copyAttributeArray(asset, accessor, (const U8*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_SHORT) - { - copyAttributeArray(asset, accessor, (const S16*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_BYTE) - { - copyAttributeArray(asset, accessor, (const S8*)src, dst, bufferView.mByteStride); - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) - { - copyAttributeArray(asset, accessor, (const F64*)src, dst, bufferView.mByteStride); - } - else - { - LL_ERRS("GLTF") << "Unsupported component type" << LL_ENDL; - } -} - void Primitive::allocateGLResources(Asset& asset) { // allocate vertex buffer @@ -192,219 +41,138 @@ void Primitive::allocateGLResources(Asset& asset) // For our engine, though, it's better to rearrange the buffers at load time into a layout that's more consistent. // The GLTF native approach undoubtedly works well if you can count on VAOs, but VAOs perform much worse with our scenes. - // get the number of vertices - U32 numVertices = 0; - if (!mAttributes.empty()) - { - auto it = mAttributes.begin(); - const Accessor& accessor = asset.mAccessors[it->second]; - numVertices = accessor.mCount; - } - - // get the number of indices - U32 numIndices = 0; - if (mIndices != INVALID_INDEX) - { - const Accessor& accessor = asset.mAccessors[mIndices]; - numIndices = accessor.mCount; - } - - // create vertex buffer - mVertexBuffer = new LLVertexBuffer(ATTRIBUTE_MASK); - mVertexBuffer->allocateBuffer(numVertices, numIndices); - - bool needs_color = true; - bool needs_texcoord = true; - bool needs_normal = true; - bool needs_tangent = true; - // load vertex data for (auto& it : mAttributes) { const std::string& attribName = it.first; + Accessor& accessor = asset.mAccessors[it.second]; // load vertex data if (attribName == "POSITION") { - // load position data - LLStrider dst; - mVertexBuffer->getVertexStrider(dst); - - copyAttribute(asset, it.second, dst); + copy(asset, accessor, mPositions); } else if (attribName == "NORMAL") { - needs_normal = false; - // load normal data - LLStrider dst; - mVertexBuffer->getNormalStrider(dst); - - copyAttribute(asset, it.second, dst); + copy(asset, accessor, mNormals); } else if (attribName == "TANGENT") { - needs_tangent = false; - // load tangent data - - LLStrider dst; - mVertexBuffer->getTangentStrider(dst); - - copyAttribute(asset, it.second, dst); + copy(asset, accessor, mTangents); } else if (attribName == "COLOR_0") { - needs_color = false; - // load color data - - LLStrider dst; - mVertexBuffer->getColorStrider(dst); - - copyAttribute(asset, it.second, dst); + copy(asset, accessor, mColors); } else if (attribName == "TEXCOORD_0") { - needs_texcoord = false; - // load texcoord data - LLStrider dst; - mVertexBuffer->getTexCoord0Strider(dst); - - LLStrider tc = dst; - copyAttribute(asset, it.second, dst); - - // convert to OpenGL coordinate space - for (U32 i = 0; i < numVertices; ++i) - { - tc->mV[1] = 1.0f - tc->mV[1];; - tc++; - } + copy(asset, accessor, mTexCoords); + } + else if (attribName == "JOINTS_0") + { + copy(asset, accessor, mJoints); + } + else if (attribName == "WEIGHTS_0") + { + copy(asset, accessor, mWeights); } } // copy index buffer if (mIndices != INVALID_INDEX) { - const Accessor& accessor = asset.mAccessors[mIndices]; - const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView]; - const Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; + Accessor& accessor = asset.mAccessors[mIndices]; + copy(asset, accessor, mIndexArray); + } - const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; + U32 mask = ATTRIBUTE_MASK; + + if (!mWeights.empty()) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } - LLStrider dst; - mVertexBuffer->getIndexStrider(dst); - mIndexArray.resize(numIndices); + mVertexBuffer = new LLVertexBuffer(mask); + mVertexBuffer->allocateBuffer(mPositions.size(), mIndexArray.size()*2); // double the size of the index buffer for 32-bit indices - if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) - { - for (U32 i = 0; i < numIndices; ++i) - { - *(dst++) = (U16) * (U32*)src; - src += sizeof(U32); - } - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) - { - for (U32 i = 0; i < numIndices; ++i) - { - *(dst++) = *(U16*)src; - src += sizeof(U16); - } - } - else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) - { - for (U32 i = 0; i < numIndices; ++i) - { - *(dst++) = *(U8*)src; - src += sizeof(U8); - } - } - else - { - LL_ERRS("GLTF") << "Unsupported component type for indices" << LL_ENDL; - } + mVertexBuffer->setBuffer(); + mVertexBuffer->setPositionData(mPositions.data()); - U16* idx = (U16*)mVertexBuffer->getMappedIndices(); - for (U32 i = 0; i < numIndices; ++i) - { - mIndexArray[i] = idx[i]; - } + if (!mIndexArray.empty()) + { + mVertexBuffer->setIndexData(mIndexArray.data()); } - // fill in default values for missing attributes - if (needs_color) - { // set default color - LLStrider dst; - mVertexBuffer->getColorStrider(dst); - for (U32 i = 0; i < numVertices; ++i) - { - *(dst++) = LLColor4U(255, 255, 255, 255); - } + if (mTexCoords.empty()) + { + mTexCoords.resize(mPositions.size()); + } + + // flip texcoord y, upload, then flip back (keep the off-spec data in vram only) + for (auto& tc : mTexCoords) + { + tc[1] = 1.f - tc[1]; } + mVertexBuffer->setTexCoordData(mTexCoords.data()); + for (auto& tc : mTexCoords) + { + tc[1] = 1.f - tc[1]; + } + + if (mColors.empty()) + { + mColors.resize(mPositions.size(), LLColor4U::white); + } + // bake material basecolor into color array if (mMaterial != INVALID_INDEX) { const Material& material = asset.mMaterials[mMaterial]; LLColor4 baseColor = material.mMaterial->mBaseColor; - LLStrider dst; - mVertexBuffer->getColorStrider(dst); - - for (U32 i = 0; i < numVertices; ++i) + for (auto& dst : mColors) { - LLColor4 col = *dst; - *dst = LLColor4U(baseColor * col); - dst++; + dst = LLColor4U(baseColor * LLColor4(dst)); } } - if (needs_texcoord) - { // set default texcoord - LLStrider dst; - mVertexBuffer->getTexCoord0Strider(dst); - for (U32 i = 0; i < numVertices; ++i) - { - *(dst++) = LLVector2(0.0f, 0.0f); - } - } + mVertexBuffer->setColorData(mColors.data()); - if (needs_normal) - { // set default normal - LLStrider dst; - mVertexBuffer->getNormalStrider(dst); - for (U32 i = 0; i < numVertices; ++i) - { - *(dst++) = LLVector4a(0.0f, 0.0f, 1.0f, 0.0f); - } + if (mNormals.empty()) + { + mNormals.resize(mPositions.size(), LLVector4a(0, 0, 1, 0)); } + + mVertexBuffer->setNormalData(mNormals.data()); - if (needs_tangent) - { // TODO: generate tangents if needed - LLStrider dst; - mVertexBuffer->getTangentStrider(dst); - for (U32 i = 0; i < numVertices; ++i) - { - *(dst++) = LLVector4a(1.0f, 0.0f, 0.0f, 1.0f); - } + if (mTangents.empty()) + { + // TODO: generate tangents if needed + mTangents.resize(mPositions.size(), LLVector4a(1, 0, 0, 1)); } - mPositions.resize(numVertices); - mTexCoords.resize(numVertices); - mNormals.resize(numVertices); - mTangents.resize(numVertices); + mVertexBuffer->setTangentData(mTangents.data()); - LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); - LLVector2* tc = (LLVector2*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_TEXCOORD0)); - LLVector4a* norm = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_NORMAL)); - LLVector4a* tangent = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_TANGENT)); - for (U32 i = 0; i < numVertices; ++i) + if (!mWeights.empty()) { - mPositions[i] = pos[i]; - mTexCoords[i] = tc[i]; - mNormals[i] = norm[i]; - mTangents[i] = tangent[i]; + std::vector weight_data; + weight_data.resize(mWeights.size()); + + F32 max_weight = 1.f - FLT_EPSILON*100.f; + LLVector4a maxw(max_weight, max_weight, max_weight, max_weight); + for (U32 i = 0; i < mWeights.size(); ++i) + { + LLVector4a& w = weight_data[i]; + w.setMin(mWeights[i], maxw); + w.add(mJoints[i]); + }; + + mVertexBuffer->setWeight4Data(weight_data.data()); } + createOctree(); - mVertexBuffer->unmapBuffer(); + mVertexBuffer->unbind(); } void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2) @@ -456,20 +224,17 @@ void Primitive::createOctree() // Initialize all the triangles we need mOctreeTriangles.resize(num_triangles); - LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); - U16* indices = (U16*)mVertexBuffer->getMappedIndices(); - for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) { //for each triangle const U32 index = triangle_index * 3; LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; - S32 i0 = indices[index]; - S32 i1 = indices[index + 1]; - S32 i2 = indices[index + 2]; + S32 i0 = mIndexArray[index]; + S32 i1 = mIndexArray[index + 1]; + S32 i2 = mIndexArray[index + 2]; - const LLVector4a& v0 = pos[i0]; - const LLVector4a& v1 = pos[i1]; - const LLVector4a& v2 = pos[i2]; + const LLVector4a& v0 = mPositions[i0]; + const LLVector4a& v1 = mPositions[i1]; + const LLVector4a& v2 = mPositions[i2]; initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); @@ -483,20 +248,17 @@ void Primitive::createOctree() // Initialize all the triangles we need mOctreeTriangles.resize(num_triangles); - LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); - U16* indices = (U16*)mVertexBuffer->getMappedIndices(); - for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) { //for each triangle const U32 index = triangle_index + 2; LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; - S32 i0 = indices[index]; - S32 i1 = indices[index - 1]; - S32 i2 = indices[index - 2]; + S32 i0 = mIndexArray[index]; + S32 i1 = mIndexArray[index - 1]; + S32 i2 = mIndexArray[index - 2]; - const LLVector4a& v0 = pos[i0]; - const LLVector4a& v1 = pos[i1]; - const LLVector4a& v2 = pos[i2]; + const LLVector4a& v0 = mPositions[i0]; + const LLVector4a& v1 = mPositions[i1]; + const LLVector4a& v2 = mPositions[i2]; initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); @@ -510,20 +272,17 @@ void Primitive::createOctree() // Initialize all the triangles we need mOctreeTriangles.resize(num_triangles); - LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); - U16* indices = (U16*)mVertexBuffer->getMappedIndices(); - for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) { //for each triangle const U32 index = triangle_index + 2; LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; - S32 i0 = indices[0]; - S32 i1 = indices[index - 1]; - S32 i2 = indices[index - 2]; + S32 i0 = mIndexArray[0]; + S32 i1 = mIndexArray[index - 1]; + S32 i2 = mIndexArray[index - 2]; - const LLVector4a& v0 = pos[i0]; - const LLVector4a& v1 = pos[i1]; - const LLVector4a& v2 = pos[i2]; + const LLVector4a& v0 = mPositions[i0]; + const LLVector4a& v1 = mPositions[i1]; + const LLVector4a& v2 = mPositions[i2]; initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); @@ -571,7 +330,7 @@ const LLVolumeTriangle* Primitive::lineSegmentIntersect(const LLVector4a& start, face.mTexCoords = mTexCoords.data(); face.mNormals = mNormals.data(); face.mTangents = mTangents.data(); - face.mIndices = mIndexArray.data(); + face.mIndices = nullptr; // unreferenced face.mNumIndices = mIndexArray.size(); face.mNumVertices = mPositions.size(); @@ -592,3 +351,50 @@ Primitive::~Primitive() mOctree = nullptr; } + +const Primitive& Primitive::operator=(const tinygltf::Primitive& src) +{ + // load material + mMaterial = src.material; + + // load mode + mMode = src.mode; + + // load indices + mIndices = src.indices; + + // load attributes + for (auto& it : src.attributes) + { + mAttributes[it.first] = it.second; + } + + switch (mMode) + { + case TINYGLTF_MODE_POINTS: + mGLMode = LLRender::POINTS; + break; + case TINYGLTF_MODE_LINE: + mGLMode = LLRender::LINES; + break; + case TINYGLTF_MODE_LINE_LOOP: + mGLMode = LLRender::LINE_LOOP; + break; + case TINYGLTF_MODE_LINE_STRIP: + mGLMode = LLRender::LINE_STRIP; + break; + case TINYGLTF_MODE_TRIANGLES: + mGLMode = LLRender::TRIANGLES; + break; + case TINYGLTF_MODE_TRIANGLE_STRIP: + mGLMode = LLRender::TRIANGLE_STRIP; + break; + case TINYGLTF_MODE_TRIANGLE_FAN: + mGLMode = LLRender::TRIANGLE_FAN; + break; + default: + mGLMode = GL_TRIANGLES; + } + + return *this; +} -- cgit v1.2.3