Fix gltf animation's 0 frame behavior. 22/288422/2
authorEunki, Hong <eunkiki.hong@samsung.com>
Thu, 16 Feb 2023 09:10:10 +0000 (18:10 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 16 Feb 2023 10:58:10 +0000 (19:58 +0900)
Current dali animation's KeyFrame didn't determine when the time is out of frame.
But gltf 2.0 spec say that we must clamp the time as input range.

To match the spec, make the 0 frame's animation keyframe value.

Change-Id: I2831d9f44c2e21ad12b40fa4b52c1d4e4b1d8e9a
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/resources/AnimatedMorphCubeAnimateNonZeroFrame.gltf [new file with mode: 0644]
automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp
dali-scene3d/public-api/loader/gltf2-loader.cpp

diff --git a/automated-tests/resources/AnimatedMorphCubeAnimateNonZeroFrame.gltf b/automated-tests/resources/AnimatedMorphCubeAnimateNonZeroFrame.gltf
new file mode 100644 (file)
index 0000000..08c8daf
--- /dev/null
@@ -0,0 +1,282 @@
+{\r
+  "accessors": [\r
+    {\r
+      "bufferView": 0,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 1,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 2,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.0100000035,\r
+        0.0100000035,\r
+        0.01\r
+      ],\r
+      "min": [\r
+        -0.0100000044,\r
+        -0.0100000054,\r
+        -0.01\r
+      ]\r
+    },\r
+    {\r
+      "bufferView": 3,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "name": "thin"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.0,\r
+        0.01893253,\r
+        0.0\r
+      ],\r
+      "min": [\r
+        0.0,\r
+        0.0,\r
+        0.0\r
+      ],\r
+      "name": "thin"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "name": "thin"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "name": "angle"\r
+    },\r
+    {\r
+      "bufferView": 7,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.0,\r
+        0.0198908355,\r
+        0.0\r
+      ],\r
+      "min": [\r
+        0.0,\r
+        0.0,\r
+        0.0\r
+      ],\r
+      "name": "angle"\r
+    },\r
+    {\r
+      "bufferView": 8,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "name": "angle"\r
+    },\r
+    {\r
+      "bufferView": 9,\r
+      "componentType": 5123,\r
+      "count": 36,\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 10,\r
+      "componentType": 5126,\r
+      "count": 127,\r
+      "type": "SCALAR",\r
+      "max": [\r
+        4.19999743\r
+      ],\r
+      "min": [\r
+        0.03\r
+      ]\r
+    },\r
+    {\r
+      "bufferView": 11,\r
+      "componentType": 5126,\r
+      "count": 254,\r
+      "type": "SCALAR"\r
+    }\r
+  ],\r
+  "animations": [\r
+    {\r
+      "channels": [\r
+        {\r
+          "sampler": 0,\r
+          "target": {\r
+            "node": 0,\r
+            "path": "weights"\r
+          }\r
+        }\r
+      ],\r
+      "samplers": [\r
+        {\r
+          "input": 10,\r
+          "interpolation": "LINEAR",\r
+          "output": 11\r
+        }\r
+      ],\r
+      "name": "Square"\r
+    }\r
+  ],\r
+  "asset": {\r
+    "generator": "glTF Tools for Unity",\r
+    "version": "2.0"\r
+  },\r
+  "bufferViews": [\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 288,\r
+      "byteLength": 384\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 672,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 960,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1248,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1536,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1824,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 2112,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 2400,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 2688,\r
+      "byteLength": 72\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 2760,\r
+      "byteLength": 508\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 3268,\r
+      "byteLength": 1016\r
+    }\r
+  ],\r
+  "buffers": [\r
+    {\r
+      "uri": "AnimatedMorphCube.bin",\r
+      "byteLength": 4284\r
+    }\r
+  ],\r
+  "meshes": [\r
+    {\r
+      "primitives": [\r
+        {\r
+          "attributes": {\r
+            "NORMAL": 0,\r
+            "TANGENT": 1,\r
+            "POSITION": 2\r
+          },\r
+          "indices": 9,\r
+          "material": 0,\r
+          "targets": [\r
+            {\r
+              "NORMAL": 3,\r
+              "POSITION": 4,\r
+              "TANGENT": 5\r
+            },\r
+            {\r
+              "NORMAL": 6,\r
+              "POSITION": 7,\r
+              "TANGENT": 8\r
+            }\r
+          ]\r
+        }\r
+      ],\r
+      "weights": [\r
+        0.0,\r
+        0.0\r
+      ],\r
+      "name": "Cube"\r
+    }\r
+  ],\r
+  "materials": [\r
+    {\r
+      "pbrMetallicRoughness": {\r
+        "baseColorFactor": [\r
+          0.6038274,\r
+          0.6038274,\r
+          0.6038274,\r
+          1.0\r
+        ],\r
+        "metallicFactor": 0.0,\r
+        "roughnessFactor": 0.5\r
+      },\r
+      "name": "Material"\r
+    }\r
+  ],\r
+  "nodes": [\r
+    {\r
+      "mesh": 0,\r
+      "rotation": [\r
+        0.0,\r
+        0.7071067,\r
+        -0.7071068,\r
+        0.0\r
+      ],\r
+      "scale": [\r
+        100.0,\r
+        100.0,\r
+        100.0\r
+      ],\r
+      "name": "AnimatedMorphCube"\r
+    }\r
+  ],\r
+  "scene": 0,\r
+  "scenes": [\r
+    {\r
+      "nodes": [\r
+        0\r
+      ]\r
+    }\r
+  ]\r
+}
\ No newline at end of file
index 357d2a8..a485f0f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -55,8 +55,7 @@ namespace
 {
 struct Context
 {
-  ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type)
-  {
+  ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type) {
     return TEST_RESOURCE_DIR "/";
   };
 
@@ -494,8 +493,7 @@ int UtcDaliGltfLoaderSuccessShort(void)
   TestApplication app;
 
   const std::string resourcePath = TEST_RESOURCE_DIR "/";
-  auto              pathProvider = [resourcePath](ResourceType::Value)
-  {
+  auto              pathProvider = [resourcePath](ResourceType::Value) {
     return resourcePath;
   };
 
@@ -503,6 +501,7 @@ int UtcDaliGltfLoaderSuccessShort(void)
   for(auto modelName : {
         "2CylinderEngine",
         "AnimatedMorphCube",
+        "AnimatedMorphCubeAnimateNonZeroFrame",
         "AnimatedMorphSphere",
         "AnimatedTriangle",
         "BoxAnimated",
index 69bcd51..532bbb6 100644 (file)
@@ -988,6 +988,7 @@ float LoadDataFromAccessors(ConversionContext& context, const gltf2::Accessor& i
 
   LoadDataFromAccessor<float>(context, output.mBufferView->mBuffer.GetIndex(), inputDataBuffer, input.mBufferView->mByteOffset + input.mByteOffset, inputDataBufferSize);
   LoadDataFromAccessor<T>(context, output.mBufferView->mBuffer.GetIndex(), outputDataBuffer, output.mBufferView->mByteOffset + output.mByteOffset, outputDataBufferSize);
+  ApplyAccessorMinMax(input, reinterpret_cast<float*>(inputDataBuffer.begin()));
   ApplyAccessorMinMax(output, reinterpret_cast<float*>(outputDataBuffer.begin()));
 
   return inputDataBuffer[input.mCount - 1u];
@@ -1004,6 +1005,12 @@ float LoadKeyFrames(ConversionContext& context, const gt::Animation::Channel& ch
 
   const float duration = std::max(LoadDataFromAccessors<T>(context, input, output, inputDataBuffer, outputDataBuffer), AnimationDefinition::MIN_DURATION_SECONDS);
 
+  // Set first frame value as first keyframe (gltf animation spec)
+  if(input.mCount > 0 && !Dali::EqualsZero(inputDataBuffer[0]))
+  {
+    keyFrames.Add(0.0f, outputDataBuffer[0]);
+  }
+
   for(uint32_t i = 0; i < input.mCount; ++i)
   {
     keyFrames.Add(inputDataBuffer[i] / duration, outputDataBuffer[i]);
@@ -1020,7 +1027,7 @@ float LoadBlendShapeKeyFrames(ConversionContext& context, const gt::Animation::C
   Vector<float> inputDataBuffer;
   Vector<float> outputDataBuffer;
 
-  const float duration = LoadDataFromAccessors<float>(context, input, output, inputDataBuffer, outputDataBuffer);
+  const float duration = std::max(LoadDataFromAccessors<float>(context, input, output, inputDataBuffer, outputDataBuffer), AnimationDefinition::MIN_DURATION_SECONDS);
 
   char        weightNameBuffer[32];
   auto        prefixSize    = snprintf(weightNameBuffer, sizeof(weightNameBuffer), "%s[", BLEND_SHAPE_WEIGHTS_UNIFORM.c_str());
@@ -1035,6 +1042,13 @@ float LoadBlendShapeKeyFrames(ConversionContext& context, const gt::Animation::C
     animatedProperty.mPropertyName = std::string(weightNameBuffer);
 
     animatedProperty.mKeyFrames = KeyFrames::New();
+
+    // Set first frame value as first keyframe (gltf animation spec)
+    if(input.mCount > 0 && !Dali::EqualsZero(inputDataBuffer[0]))
+    {
+      animatedProperty.mKeyFrames.Add(0.0f, outputDataBuffer[weightIndex]);
+    }
+
     for(uint32_t i = 0; i < input.mCount; ++i)
     {
       animatedProperty.mKeyFrames.Add(inputDataBuffer[i] / duration, outputDataBuffer[i * endWeightIndex + weightIndex]);