From 0bfa28ced8c1320cf9ae739ccb4d082197d204bb Mon Sep 17 00:00:00 2001 From: seungho baek Date: Mon, 24 Apr 2023 19:55:06 +0900 Subject: [PATCH] Support Short and Byte weight of gltf skinning Change-Id: I4817c40b049e5b3984b66cc9fabe731ae0bc4582 Signed-off-by: seungho baek --- .../src/dali-scene3d/utc-Dali-MeshDefinition.cpp | 76 +++++++++++++++++++++- .../shaders/default-physically-based-shader.frag | 2 +- dali-scene3d/internal/loader/gltf2-util.cpp | 6 ++ dali-scene3d/public-api/loader/mesh-definition.cpp | 55 +++++++++++++--- dali-scene3d/public-api/loader/mesh-definition.h | 2 + 5 files changed, 129 insertions(+), 12 deletions(-) diff --git a/automated-tests/src/dali-scene3d/utc-Dali-MeshDefinition.cpp b/automated-tests/src/dali-scene3d/utc-Dali-MeshDefinition.cpp index 377e68d..5ee5617 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-MeshDefinition.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-MeshDefinition.cpp @@ -17,7 +17,8 @@ #include -#include "dali-scene3d/public-api/loader/mesh-definition.h" +#include +#include #include using namespace Dali; @@ -99,3 +100,76 @@ int UtcDaliMeshDefinitionBlobApplyMinMaxBothEmpty(void) END_TEST; } +int UtcDaliMeshDefinitionByteSkinWeight(void) +{ + float data8[8] = {0.003922, 0.062745, 0.250980, 0.098039, 0.937255, 0.749020, 0.741176, 0.937255}; + + BufferDefinition bufferDefinition; + bufferDefinition.mUri = "data:application/base64,ARBAGe+/ve+/vT9hc2RmYXNkZmFzZGZhc2RmYXNkZmE="; + bufferDefinition.mByteLength = 32; + BufferDefinition::Vector buffers; + buffers.push_back(std::move(bufferDefinition)); + + MeshDefinition meshDefinition; + meshDefinition.mFlags = MeshDefinition::U16_JOINT_IDS | MeshDefinition::U8_WEIGHT; + MeshDefinition::SparseBlob sparseBlob; + meshDefinition.mPositions = + MeshDefinition::Accessor{ + std::move(MeshDefinition::Blob{0, 12, 0, (uint16_t)12, std::vector(), std::vector()}), std::move(sparseBlob), 0}; + meshDefinition.mJoints0 = + MeshDefinition::Accessor{ + std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector(), std::vector()}), std::move(sparseBlob), 0}; + meshDefinition.mWeights0 = + MeshDefinition::Accessor{ + std::move(MeshDefinition::Blob{0, 8, 0, (uint16_t)8, std::vector(), std::vector()}), std::move(sparseBlob), 0}; + + MeshDefinition::RawData rawData = meshDefinition.LoadRaw("", buffers); + + DALI_TEST_EQUALS(rawData.mAttribs.size(), 4, TEST_LOCATION); + DALI_TEST_EQUALS(rawData.mAttribs[3].mName, "aWeights", TEST_LOCATION); + DALI_TEST_EQUALS(rawData.mAttribs[3].mNumElements, 2, TEST_LOCATION); + float* value = reinterpret_cast(rawData.mAttribs[3].mData.data()); + for(uint32_t i = 0; i < rawData.mAttribs[3].mNumElements * 4; ++i) + { + DALI_TEST_EQUALS(*value, data8[i], TEST_LOCATION); + value++; + } + END_TEST; +} + +int UtcDaliMeshDefinitionShortSkinWeight(void) +{ + float data8[8] = {0.062516, 0.098634, 0.749752, 0.936492, 0.741207, 0.379873, 0.392386, 0.380468}; + + BufferDefinition bufferDefinition; + bufferDefinition.mUri = "data:application/base64,ARBAGe+/ve+/vT9hc2RmYXNkZmFzZGZhc2RmYXNkZmE="; + bufferDefinition.mByteLength = 32; + BufferDefinition::Vector buffers; + buffers.push_back(std::move(bufferDefinition)); + + MeshDefinition meshDefinition; + meshDefinition.mFlags = MeshDefinition::U16_JOINT_IDS | MeshDefinition::U16_WEIGHT; + MeshDefinition::SparseBlob sparseBlob; + meshDefinition.mPositions = + MeshDefinition::Accessor{ + std::move(MeshDefinition::Blob{0, 12, 0, (uint16_t)12, std::vector(), std::vector()}), std::move(sparseBlob), 0}; + meshDefinition.mJoints0 = + MeshDefinition::Accessor{ + std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector(), std::vector()}), std::move(sparseBlob), 0}; + meshDefinition.mWeights0 = + MeshDefinition::Accessor{ + std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector(), std::vector()}), std::move(sparseBlob), 0}; + + MeshDefinition::RawData rawData = meshDefinition.LoadRaw("", buffers); + + DALI_TEST_EQUALS(rawData.mAttribs.size(), 4, TEST_LOCATION); + DALI_TEST_EQUALS(rawData.mAttribs[3].mName, "aWeights", TEST_LOCATION); + DALI_TEST_EQUALS(rawData.mAttribs[3].mNumElements, 2, TEST_LOCATION); + float* value = reinterpret_cast(rawData.mAttribs[3].mData.data()); + for(uint32_t i = 0; i < rawData.mAttribs[3].mNumElements * 4; ++i) + { + DALI_TEST_EQUALS(*value, data8[i], TEST_LOCATION); + value++; + } + END_TEST; +} diff --git a/dali-scene3d/internal/graphics/shaders/default-physically-based-shader.frag b/dali-scene3d/internal/graphics/shaders/default-physically-based-shader.frag index 1508bf1..bfcc18b 100644 --- a/dali-scene3d/internal/graphics/shaders/default-physically-based-shader.frag +++ b/dali-scene3d/internal/graphics/shaders/default-physically-based-shader.frag @@ -116,7 +116,7 @@ void main() // The albedo may be defined from a base texture or a flat color #ifdef BASECOLOR_TEX lowp vec4 baseColor = texture(sAlbedoAlpha, vUV); - baseColor = vec4(linear(baseColor.rgb), baseColor.w) * uColorFactor; + baseColor = vColor * vec4(linear(baseColor.rgb), baseColor.w) * uColorFactor; #else // BASECOLOR_TEX lowp vec4 baseColor = vColor * uColorFactor; #endif // BASECOLOR_TEX diff --git a/dali-scene3d/internal/loader/gltf2-util.cpp b/dali-scene3d/internal/loader/gltf2-util.cpp index 330a2c0..219f207 100644 --- a/dali-scene3d/internal/loader/gltf2-util.cpp +++ b/dali-scene3d/internal/loader/gltf2-util.cpp @@ -759,6 +759,12 @@ void ConvertMeshes(const gltf2::Document& document, ConversionContext& context) meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_JOINT_IDS; DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_JOINT_IDS) || iFind->second->mComponentType == gltf2::Component::FLOAT); } + if(iFind->first == gltf2::Attribute::WEIGHTS_0) + { + meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_WEIGHT; + meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_WEIGHT; + DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_WEIGHT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_WEIGHT) || iFind->second->mComponentType == gltf2::Component::FLOAT); + } } else if(needNormalsTangents) { diff --git a/dali-scene3d/public-api/loader/mesh-definition.cpp b/dali-scene3d/public-api/loader/mesh-definition.cpp index a485e97..f75498b 100644 --- a/dali-scene3d/public-api/loader/mesh-definition.cpp +++ b/dali-scene3d/public-api/loader/mesh-definition.cpp @@ -211,6 +211,41 @@ void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Acces raw.mAttribs.push_back({"aJoints", Property::VECTOR4, static_cast(outBufferSize / sizeof(Vector4)), std::move(buffer)}); } +template +void ReadWeightAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath) +{ + constexpr auto sizeofBlobUnit = sizeof(T) * 4; + + DALI_ASSERT_ALWAYS(((accessor.mBlob.mLength % sizeofBlobUnit == 0) || + accessor.mBlob.mStride >= sizeofBlobUnit) && + "weights buffer length not a multiple of element size"); + const auto inBufferSize = accessor.mBlob.GetBufferSize(); + const auto outBufferSize = (sizeof(Vector4) / sizeofBlobUnit) * inBufferSize; + + std::vector buffer(outBufferSize); + auto inBuffer = buffer.data() + outBufferSize - inBufferSize; + if(!ReadAccessor(accessor, source, inBuffer)) + { + ExceptionFlinger(ASSERT_LOCATION) << "Failed to read weights from '" << meshPath << "'."; + } + + if constexpr(sizeofBlobUnit != sizeof(Vector4)) + { + auto floats = reinterpret_cast(buffer.data()); + const auto end = inBuffer + inBufferSize; + while(inBuffer != end) + { + const auto value = *reinterpret_cast(inBuffer); + // Normalize weight value. value /= 255 for uint8_t weight, and value /= 65535 for uint16_t weight. + *floats = static_cast(value) / static_cast((1 << (sizeof(T) * 8)) - 1); + + inBuffer += sizeof(T); + ++floats; + } + } + raw.mAttribs.push_back({"aWeights", Property::VECTOR4, static_cast(outBufferSize / sizeof(Vector4)), std::move(buffer)}); +} + template> bool GenerateNormals(MeshDefinition::RawData& raw) { @@ -944,20 +979,20 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& ReadJointAccessor(raw, mJoints0, streamJoint, pathJoint); } - DALI_ASSERT_ALWAYS(((mWeights0.mBlob.mLength % sizeof(Vector4) == 0) || - mWeights0.mBlob.mStride >= sizeof(Vector4)) && - "Weights buffer length not a multiple of element size"); - const auto bufferSize = mWeights0.mBlob.GetBufferSize(); - std::vector buffer(bufferSize); - std::string pathWeight; auto& streamWeight = GetAvailableData(fileStream, meshPath, buffers[mWeights0.mBufferIdx], pathWeight); - if(!ReadAccessor(mWeights0, streamWeight, buffer.data())) + if(MaskMatch(mFlags, U16_WEIGHT)) { - ExceptionFlinger(ASSERT_LOCATION) << "Failed to read weights from '" << pathWeight << "'."; + ReadWeightAccessor(raw, mWeights0, streamWeight, pathWeight); + } + else if(MaskMatch(mFlags, U8_WEIGHT)) + { + ReadWeightAccessor(raw, mWeights0, streamWeight, pathWeight); + } + else + { + ReadWeightAccessor(raw, mWeights0, streamWeight, pathWeight); } - - raw.mAttribs.push_back({"aWeights", Property::VECTOR4, static_cast(bufferSize / sizeof(Vector4)), std::move(buffer)}); } // Calculate the Blob for the blend shapes. diff --git a/dali-scene3d/public-api/loader/mesh-definition.h b/dali-scene3d/public-api/loader/mesh-definition.h index eceb795..570537e 100644 --- a/dali-scene3d/public-api/loader/mesh-definition.h +++ b/dali-scene3d/public-api/loader/mesh-definition.h @@ -52,6 +52,8 @@ struct DALI_SCENE3D_API MeshDefinition U8_INDICES = NthBit(2), // default is unsigned short U16_JOINT_IDS = NthBit(3), // default is floats U8_JOINT_IDS = NthBit(4), + U16_WEIGHT = NthBit(5), // default is floats + U8_WEIGHT = NthBit(6), }; enum Attributes -- 2.7.4