Merge "Support Short and Byte weight of gltf skinning" into devel/master
authorSeungho BAEK <sbsh.baek@samsung.com>
Thu, 27 Apr 2023 04:29:38 +0000 (04:29 +0000)
committerGerrit Code Review <gerrit@review>
Thu, 27 Apr 2023 04:29:38 +0000 (04:29 +0000)
automated-tests/src/dali-scene3d/utc-Dali-MeshDefinition.cpp
dali-scene3d/internal/graphics/shaders/default-physically-based-shader.frag
dali-scene3d/internal/loader/gltf2-util.cpp
dali-scene3d/public-api/loader/mesh-definition.cpp
dali-scene3d/public-api/loader/mesh-definition.h

index 377e68d..5ee5617 100644 (file)
@@ -17,7 +17,8 @@
 
 #include <vector>
 
-#include "dali-scene3d/public-api/loader/mesh-definition.h"
+#include <dali-scene3d/public-api/loader/mesh-definition.h>
+#include <dali-scene3d/public-api/loader/buffer-definition.h>
 #include <dali-test-suite-utils.h>
 
 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<float>(), std::vector<float>()}), std::move(sparseBlob), 0};
+  meshDefinition.mJoints0 =
+    MeshDefinition::Accessor{
+      std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0};
+  meshDefinition.mWeights0 =
+    MeshDefinition::Accessor{
+      std::move(MeshDefinition::Blob{0, 8, 0, (uint16_t)8, std::vector<float>(), std::vector<float>()}), 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<float*>(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<float>(), std::vector<float>()}), std::move(sparseBlob), 0};
+  meshDefinition.mJoints0 =
+    MeshDefinition::Accessor{
+      std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector<float>(), std::vector<float>()}), std::move(sparseBlob), 0};
+  meshDefinition.mWeights0 =
+    MeshDefinition::Accessor{
+      std::move(MeshDefinition::Blob{0, 16, 0, (uint16_t)16, std::vector<float>(), std::vector<float>()}), 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<float*>(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;
+}
index 1508bf1..bfcc18b 100644 (file)
@@ -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
index 330a2c0..219f207 100644 (file)
@@ -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)
         {
index 948cb89..444eb37 100644 (file)
@@ -211,6 +211,41 @@ void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Acces
   raw.mAttribs.push_back({"aJoints", Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
 }
 
+template<typename T>
+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<uint8_t> 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<float*>(buffer.data());
+    const auto end    = inBuffer + inBufferSize;
+    while(inBuffer != end)
+    {
+      const auto value = *reinterpret_cast<T*>(inBuffer);
+      // Normalize weight value. value /= 255 for uint8_t weight, and value /= 65535 for uint16_t weight.
+      *floats = static_cast<float>(value) / static_cast<float>((1 << (sizeof(T) * 8)) - 1);
+
+      inBuffer += sizeof(T);
+      ++floats;
+    }
+  }
+  raw.mAttribs.push_back({"aWeights", Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
+}
+
 template<bool use32BitsIndices, typename IndexProviderType = IndexProvider<use32BitsIndices>>
 bool GenerateNormals(MeshDefinition::RawData& raw)
 {
@@ -947,20 +982,20 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector&
       ReadJointAccessor<float>(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<uint8_t> 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<uint16_t>(raw, mWeights0, streamWeight, pathWeight);
+    }
+    else if(MaskMatch(mFlags, U8_WEIGHT))
+    {
+      ReadWeightAccessor<uint8_t>(raw, mWeights0, streamWeight, pathWeight);
+    }
+    else
+    {
+      ReadWeightAccessor<float>(raw, mWeights0, streamWeight, pathWeight);
     }
-
-    raw.mAttribs.push_back({"aWeights", Property::VECTOR4, static_cast<uint32_t>(bufferSize / sizeof(Vector4)), std::move(buffer)});
   }
 
   // Calculate the Blob for the blend shapes.
index eceb795..570537e 100644 (file)
@@ -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