[NUI.Scene3D] Make API to apply ModelMotion
authorEunki Hong <eunkiki.hong@samsung.com>
Fri, 28 Apr 2023 01:30:00 +0000 (10:30 +0900)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Mon, 22 May 2023 10:12:20 +0000 (19:12 +0900)
Make a prototype of MotionData settor & Animation generator

Let we can use two type of motion as index
- MotionTransformIndex
- BlendShapeIndex

MotionTransformIndex can control only Position / Orientation / Scale.
and, BlendShape can control only BlendShape.

Currently a lots of case are not supported.
But we can test MotionData usecase by "string" ModelNodeId + "int" blendshape

Signed-off-by: Eunki Hong <eunkiki.hong@samsung.com>
13 files changed:
src/Tizen.NUI.Scene3D/src/internal/Controls/Model.cs [new file with mode: 0755]
src/Tizen.NUI.Scene3D/src/public/Controls/Model.cs
src/Tizen.NUI.Scene3D/src/public/ModelMotion/BlendShapeIndex.cs [new file with mode: 0644]
src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionData.cs [new file with mode: 0644]
src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionIndex.cs [new file with mode: 0644]
src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionTransformIndex.cs [new file with mode: 0644]
src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionValue.cs [new file with mode: 0644]
test/Tizen.NUI.Scene3D.Sample/Scene3DSample.cs
test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/Base_AO.png [new file with mode: 0644]
test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/ColorSwatches.png [new file with mode: 0644]
test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/MorphStressTest.bin [new file with mode: 0644]
test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/MorphStressTest.gltf [new file with mode: 0644]
test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/TinyGrid.png [new file with mode: 0644]

diff --git a/src/Tizen.NUI.Scene3D/src/internal/Controls/Model.cs b/src/Tizen.NUI.Scene3D/src/internal/Controls/Model.cs
new file mode 100755 (executable)
index 0000000..2386593
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using System.ComponentModel;
+using Tizen.NUI;
+using Tizen.NUI.Binding;
+using Tizen.NUI.BaseComponents;
+
+namespace Tizen.NUI.Scene3D
+{
+    public partial class Model
+    {
+        internal Animation InternalGenerateMotionDataAnimation(MotionData motionData, int durationMilliSeconds)
+        {
+            if (motionData == null || motionData.MotionValues == null)
+            {
+                Tizen.Log.Error("NUI", $"MotionData was null\n");
+                return null;
+            }
+
+            Lazy<Animation> ret = new Lazy<Animation>(() => new Animation(durationMilliSeconds));
+
+            foreach (var indexValuePair in motionData.MotionValues)
+            {
+                var motionIndex = indexValuePair.Item1;
+                var motionValue = indexValuePair.Item2;
+
+                if (motionIndex == null || motionValue == null || motionValue.Type == MotionValue.ValueType.Invalid)
+                {
+                    continue;
+                }
+
+                // TODO : Make we use ModelNode instead of Animatable. Currently, ModelNode have some problem.
+                if (motionIndex.ModelNodeId != null)
+                {
+                    Animatable modelNode = null;
+                    if (motionIndex.ModelNodeId.Type == PropertyKey.KeyType.String)
+                    {
+                        modelNode = FindChildAnimatableByName(motionIndex.ModelNodeId.StringKey);
+                    }
+                    else if (motionIndex.ModelNodeId.Type == PropertyKey.KeyType.Index)
+                    {
+                        // TODO : Not implement yet.
+                    }
+
+                    if (modelNode != null)
+                    {
+                        KeyFrames keyFrames = null;
+                        if (motionValue.Type == MotionValue.ValueType.KeyFrames)
+                        {
+                            keyFrames = motionValue.KeyFramesValue;
+                        }
+                        else if (motionValue.Type == MotionValue.ValueType.Property)
+                        {
+                            // Generate stable keyframe animation here.
+                            keyFrames = new KeyFrames();
+                            keyFrames.Add(0.0f, motionValue.Value);
+                            keyFrames.Add(1.0f, motionValue.Value);
+                        }
+
+                        if (keyFrames != null)
+                        {
+                            string animatedPropertyName = motionIndex.GetPropertyName(modelNode as ModelNode);
+                            if (!string.IsNullOrEmpty(animatedPropertyName))
+                            {
+                                ret.Value.AnimateBetween(modelNode, animatedPropertyName, keyFrames);
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    if (motionIndex is BlendShapeIndex)
+                    {
+                        var blendShapeIndex = motionIndex as BlendShapeIndex;
+                        if (blendShapeIndex.BlendShapeId?.Type == PropertyKey.KeyType.String)
+                        {
+                            // TODO : Not implement yet. (Set all blendshapes by string)
+                        }
+                    }
+                }
+            }
+
+            return ret.IsValueCreated ? ret.Value : null;
+        }
+
+        internal void InternalSetMotionData(MotionData motionData)
+        {
+            if (motionData == null || motionData.MotionValues == null)
+            {
+                Tizen.Log.Error("NUI", $"MotionData was null\n");
+                return;
+            }
+
+            foreach (var indexValuePair in motionData.MotionValues)
+            {
+                var motionIndex = indexValuePair.Item1;
+                var motionValue = indexValuePair.Item2;
+
+                if (motionIndex == null || motionValue == null || motionValue.Type == MotionValue.ValueType.Invalid)
+                {
+                    continue;
+                }
+
+                if (motionIndex.ModelNodeId != null)
+                {
+                    // TODO : Make we use ModelNode instead of Animatable. Currently, ModelNode have some problem.
+                    Animatable modelNode = null;
+                    if (motionIndex.ModelNodeId.Type == PropertyKey.KeyType.String)
+                    {
+                        modelNode = FindChildAnimatableByName(motionIndex.ModelNodeId.StringKey);
+                    }
+                    else if (motionIndex.ModelNodeId.Type == PropertyKey.KeyType.Index)
+                    {
+                        // TODO : Not implement yet.
+                    }
+
+                    if (modelNode != null)
+                    {
+                        PropertyValue value = null;
+                        if (motionValue.Type == MotionValue.ValueType.KeyFrames)
+                        {
+                            // TODO : Not implement yet.
+                        }
+                        else if (motionValue.Type == MotionValue.ValueType.Property)
+                        {
+                            value = motionValue.Value;
+                        }
+
+                        if (value != null)
+                        {
+                            string propertyName = motionIndex.GetPropertyName(modelNode as ModelNode);
+                            if (!string.IsNullOrEmpty(propertyName))
+                            {
+                                modelNode.SetProperty(propertyName, value);
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    if (motionIndex is BlendShapeIndex)
+                    {
+                        var blendShapeIndex = motionIndex as BlendShapeIndex;
+                        if (blendShapeIndex.BlendShapeId?.Type == PropertyKey.KeyType.String)
+                        {
+                            // TODO : Not implement yet. (Set all blendshapes by string)
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
index 3993585..4969483 100755 (executable)
@@ -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.
@@ -74,7 +74,7 @@ namespace Tizen.NUI.Scene3D
     /// </code>
     /// </example>
     /// <since_tizen> 10 </since_tizen>
-    public class Model : View
+    public partial class Model : View
     {
         internal Model(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
         {
@@ -467,6 +467,32 @@ namespace Tizen.NUI.Scene3D
         }
 
         /// <summary>
+        /// Prototype of animation generate by MotionData
+        /// </summary>
+        /// <param name="motionData">Inputed list of pair of MotionIndex and MotionValue.</param>
+        /// <param name="durationMilliSeconds">The duration in milliseconds.</param>
+        /// <returns>Generated animation by input motion data</returns>
+        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Animation GenerateMotionDataAnimation(MotionData motionData, int durationMilliSeconds)
+        {
+            return InternalGenerateMotionDataAnimation(motionData, durationMilliSeconds);
+        }
+
+        /// <summary>
+        /// Prototype of MotionData setter.
+        /// Note that this API didn't apply KeyFrames animation.
+        /// If you want to apply the animation, please use <see cref="GenerateMotionDataAnimation(MotionData, int)"/> and play the result.
+        /// </summary>
+        /// <param name="motionData">Inputed list of pair of MotionIndex and MotionValue.</param>
+        // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void SetMotionData(MotionData motionData)
+        {
+            InternalSetMotionData(motionData);
+        }
+
+        /// <summary>
         /// Retrieves model root Actor.
         /// </summary>
         /// <returns>Root View of the model.</returns>
diff --git a/src/Tizen.NUI.Scene3D/src/public/ModelMotion/BlendShapeIndex.cs b/src/Tizen.NUI.Scene3D/src/public/ModelMotion/BlendShapeIndex.cs
new file mode 100644 (file)
index 0000000..88c7d73
--- /dev/null
@@ -0,0 +1,78 @@
+using System.Numerics;
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using Tizen.NUI;
+
+namespace Tizen.NUI.Scene3D
+{
+    /// <summary>
+    /// Index of BlendShape feature.
+    /// MotionValue should be float type.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class BlendShapeIndex : MotionIndex
+    {
+        /// <summary>
+        /// Create an initialized motion index.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public BlendShapeIndex()
+        {
+        }
+
+        /// <summary>
+        /// The key of BlendShape.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PropertyKey BlendShapeId { get; set; } = null;
+
+        /// <summary>
+        /// Convert from index to DALi engine using blend shape uniform name.
+        /// </summary>
+        internal static string GetPropertyNameFromIndex(int index)
+        {
+            if (index >= 0)
+            {
+                return "uBlendShapeWeight[" + index.ToString() + "]";
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Get uniform name of blendshape.
+        /// </summary>
+        internal override string GetPropertyName(ModelNode node)
+        {
+            if (BlendShapeId != null)
+            {
+                if (BlendShapeId.Type == PropertyKey.KeyType.Index)
+                {
+                    return GetPropertyNameFromIndex(BlendShapeId.IndexKey);
+                }
+                if (node != null)
+                {
+                    // TODO : Not implement yet. We should make API that get the blendshape index from node by name.
+                }
+            }
+            return null;
+        }
+    }
+}
diff --git a/src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionData.cs b/src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionData.cs
new file mode 100644 (file)
index 0000000..048eace
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Scene3D
+{
+    /// <summary>
+    /// List of each motion value.
+    /// </summary>
+    /// <remark>
+    /// We don't check MotionValue type is matched with MotionIndex.
+    /// </remark>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class MotionData : IDisposable
+    {
+        /// <summary>
+        /// Owned motion value list.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public List<(MotionIndex, MotionValue)> MotionValues { get; set; } = null;
+
+        /// <summary>
+        /// Create an initialized motion data.
+        /// </summary>
+        public MotionData()
+        {
+        }
+
+        /// <summary>
+        /// IDisposable.Dipsose.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Dispose()
+        {
+            if (MotionValues != null)
+            {
+                foreach (var indexValuePair in MotionValues)
+                {
+                    indexValuePair.Item1?.Dispose();
+                    indexValuePair.Item2?.Dispose();
+                }
+            }
+        }
+    }
+}
diff --git a/src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionIndex.cs b/src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionIndex.cs
new file mode 100644 (file)
index 0000000..9bcbf5a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using Tizen.NUI;
+
+namespace Tizen.NUI.Scene3D
+{
+    /// <summary>
+    /// Index of motion value. It will be used to specify the target of motion applied.
+    ///
+    /// There are two kinds of MotionIndex : MotionTransformIndex and BlendShapeIndex.
+    /// MotionTransformIndex will be used for control the ModelNode's Position / Orientation / Scale, or each components.
+    /// BlendShapeIndex will be used for control some blendshape animation.
+    ///
+    /// We can use this class below cases
+    /// - ModelNodeId (string key) , MotionTransformIndex         : Target is ModelNode's transform property
+    /// - ModelNodeId (int key)    , MotionTransformIndex         : Target is ModelNode's transform property [not implemented yet]
+    /// - ModelNodeId (string key) , BlendShapeIndex (int key)    : Target is ModelNode's BlendShape
+    /// - ModelNodeId (string key) , BlendShapeIndex (string key) : Target is ModelNode's BlendShape [not implemented yet]
+    /// - ModelNodeId (int key)    , BlendShapeIndex (int key)    : Target is ModelNode's BlendShape [not implemented yet]
+    /// - ModelNodeId (int key)    , BlendShapeIndex (string key) : Target is ModelNode's BlendShape [not implemented yet]
+    /// - ModelNodeId (null)       , BlendShapeIndex (string key) : Target is all BlendShape [not implemented yet]
+    /// All other cases are invalid.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public abstract class MotionIndex : IDisposable
+    {
+        /// <summary>
+        /// The id of ModelNode. If you want to apply to all ModelNodes who has BlendShape string, let this value as null.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PropertyKey ModelNodeId { get; set; } = null;
+
+        /// <summary>
+        /// Abstract API to get uniform name of index, or null if invalid. Only can be used for internal API
+        /// </summary>
+        abstract internal string GetPropertyName(ModelNode node);
+
+        /// <summary>
+        /// IDisposable.Dipsose.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Dispose()
+        {
+            ModelNodeId?.Dispose();
+            ModelNodeId = null;
+        }
+    }
+}
diff --git a/src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionTransformIndex.cs b/src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionTransformIndex.cs
new file mode 100644 (file)
index 0000000..865efce
--- /dev/null
@@ -0,0 +1,157 @@
+using System.Numerics;
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using Tizen.NUI;
+
+namespace Tizen.NUI.Scene3D
+{
+    /// <summary>
+    /// Index of Transform feature.
+    /// Each TransformTypes has their own matched MotionValue type.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class MotionTransformIndex : MotionIndex
+    {
+        /// <summary>
+        /// The list of component types what this MotionIndex can control.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1717:Only FlagsAttribute enums should have plural names")]
+        public enum TransformTypes
+        {
+            /// <summary>
+            /// The position of ModelNode. MotionValue should be Vector3.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            Position,
+
+            /// <summary>
+            /// The x position of ModelNode. MotionValue should be float.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            PositionX,
+
+            /// <summary>
+            /// The y position of ModelNode. MotionValue should be float.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            PositionY,
+
+            /// <summary>
+            /// The z position of ModelNode. MotionValue should be float.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            PositionZ,
+
+            /// <summary>
+            /// The orientation of ModelNode. MotionValue should be Rotation.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            Orientation,
+
+            /// <summary>
+            /// The scale of ModelNode. MotionValue should be Vector3.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            Scale,
+
+            /// <summary>
+            /// The x scale of ModelNode. MotionValue should be float.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            ScaleX,
+
+            /// <summary>
+            /// The y scale of ModelNode. MotionValue should be float.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            ScaleY,
+
+            /// <summary>
+            /// The z scale of ModelNode. MotionValue should be float.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            ScaleZ,
+        }
+
+        /// <summary>
+        /// Create an initialized motion index.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public MotionTransformIndex()
+        {
+        }
+
+        /// <summary>
+        /// The component type what this MotionIndex want to control.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public TransformTypes TransformType { get; set; } = TransformTypes.Position;
+
+        /// <summary>
+        /// Get uniform name of TransformType.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal override string GetPropertyName(ModelNode node)
+        {
+            switch (TransformType)
+            {
+                case TransformTypes.Position:
+                {
+                    return "Position";
+                }
+                case TransformTypes.PositionX:
+                {
+                    return "PositionX";
+                }
+                case TransformTypes.PositionY:
+                {
+                    return "PositionY";
+                }
+                case TransformTypes.PositionZ:
+                {
+                    return "PositionZ";
+                }
+                case TransformTypes.Orientation:
+                {
+                    return "Orientation";
+                }
+                case TransformTypes.Scale:
+                {
+                    return "Scale";
+                }
+                case TransformTypes.ScaleX:
+                {
+                    return "ScaleX";
+                }
+                case TransformTypes.ScaleY:
+                {
+                    return "ScaleY";
+                }
+                case TransformTypes.ScaleZ:
+                {
+                    return "ScaleZ";
+                }
+            }
+            return null;
+        }
+    }
+}
diff --git a/src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionValue.cs b/src/Tizen.NUI.Scene3D/src/public/ModelMotion/MotionValue.cs
new file mode 100644 (file)
index 0000000..293ecaf
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using Tizen.NUI;
+
+namespace Tizen.NUI.Scene3D
+{
+    /// <summary>
+    /// Target value of motion. It can be define as specific PropertyValue, or KeyFrames
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class MotionValue : IDisposable
+    {
+        private IDisposable internalValue = null;
+
+        /// <summary>
+        /// Determine whether current stored value is PropertyValue, or KeyFrames.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public enum ValueType
+        {
+            /// <summary>
+            /// Value is null, or invalid class.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            Invalid,
+
+            /// <summary>
+            /// Value is PropertyValue.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            Property,
+
+            /// <summary>
+            /// Value is KeyFrames.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            KeyFrames,
+        }
+
+        /// <summary>
+        /// Create an initialized motion value with invalid.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public MotionValue()
+        {
+        }
+
+        /// <summary>
+        /// Get or set the value as PropertyValue type.
+        /// It will return null if value is not PropertyValue.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PropertyValue Value
+        {
+            get
+            {
+                return internalValue as PropertyValue;
+            }
+            set
+            {
+                internalValue = (Disposable)value;
+            }
+        }
+
+        /// <summary>
+        /// Get or set the value as KeyFrames type.
+        /// It will return null if value is not KeyFrames.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public KeyFrames KeyFramesValue
+        {
+            get
+            {
+                return internalValue as KeyFrames;
+            }
+            set
+            {
+                internalValue = (BaseHandle)value;
+            }
+        }
+
+        /// <summary>
+        /// Get the type of value what we setted.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ValueType Type
+        {
+            get
+            {
+                if (internalValue is KeyFrames)
+                {
+                    return ValueType.KeyFrames;
+                }
+                if (internalValue is PropertyValue)
+                {
+                    return ValueType.Property;
+                }
+                return ValueType.Invalid;
+            }
+        }
+
+        /// <summary>
+        /// IDisposable.Dipsose.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Dispose()
+        {
+            internalValue?.Dispose();
+        }
+    }
+}
index 78bebfd..a555160 100644 (file)
@@ -32,6 +32,15 @@ class Scene3DSample : NUIApplication
 
     SceneView mSceneView;
     Model mModel;
+    Animation mModelAnimation;
+    bool mModelLoadFinished;
+
+    // Note : This motion data works well only if model is MorthStressTest!
+    MotionData mStaticMotionData;
+    MotionData mStaticRevertMotionData;
+    MotionData mAnimateMotionData;
+    Animation mMotionAnimation;
+    const int modelMotionAnimationDurationMilliseconds = 2000; // milliseconds
 
     Animation mModelRotateAnimation;
     const int modelRotateAnimationDurationMilliseconds = 10000; // milliseconds
@@ -39,18 +48,26 @@ class Scene3DSample : NUIApplication
     private bool mMutex = false; // Lock key event during some transition / Change informations
 
     #region Model list define
+    /*
+     * Copyright 2021 Analytical Graphics, Inc.
+     * CC-BY 4.0 https://creativecommons.org/licenses/by/4.0/
+     */
     private static readonly List<string> ModelUrlList = new List<string>()
     {
         // Model reference : https://sketchfab.com/models/b81008d513954189a063ff901f7abfe4
         // Get from KhronosGroup https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/DamagedHelmet
         "DamagedHelmet/DamagedHelmet.gltf",
-        
+
+        //Get from KhronosGroup https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/MorphStressTest
+        "MorphStressTest/MorphStressTest.gltf",
+
         // Get from KhronosGroup https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/2CylinderEngine
         "2CylinderEngine/2CylinderEngine_e.gltf",
 
         // Get from KhronosGroup https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/ToyCar
         "ToyCar/ToyCar.glb",
 
+        //Get from KhronosGroup https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/BoxAnimated
         "BoxAnimated/BoxAnimated.gltf",
     };
     private int currentModelIndex = 0;
@@ -70,11 +87,11 @@ class Scene3DSample : NUIApplication
     #region Camera list define
     private class CameraInfo
     {
-        public Vector3 Position {get; set;} = Vector3.Zero;
-        public Rotation Orientation {get; set;} = null;
-        public Radian Fov {get; set;} = null;
-        public float Near {get; set;} = 0.5f;
-        public float Far {get; set;} = 50.0f;
+        public Vector3 Position { get; set; } = Vector3.Zero;
+        public Rotation Orientation { get; set; } = null;
+        public Radian Fov { get; set; } = null;
+        public float Near { get; set; } = 0.5f;
+        public float Far { get; set; } = 50.0f;
     };
     private static readonly List<CameraInfo> CameraInfoList = new List<CameraInfo>()
     {
@@ -182,6 +199,14 @@ class Scene3DSample : NUIApplication
             mModel.Dispose();
         }
 
+        // Release old animation if exist
+        if (mModelAnimation != null)
+        {
+            mModelAnimation.Stop();
+            mModelAnimation.Dispose();
+            mModelAnimation = null;
+        }
+
         // Release old camera if exist
         if (additionalCameraList != null)
         {
@@ -199,6 +224,8 @@ class Scene3DSample : NUIApplication
             additionalCameraList = null;
         }
 
+        mModelLoadFinished = false;
+
         mModel = new Model(MODEL_DIR + modelUrl)
         {
             Name = modelUrl,
@@ -210,8 +237,12 @@ class Scene3DSample : NUIApplication
             // You can play animation if the animation exists.
             if (model.GetAnimationCount() > 0u)
             {
-                model.GetAnimation(0u).Looping = true;
-                model.GetAnimation(0u).Play();
+                mModelAnimation = model.GetAnimation(0u);
+                if (mModelAnimation != null)
+                {
+                    mModelAnimation.Looping = true;
+                    mModelAnimation.Play();
+                }
             }
             // You can apply camera properties if the camera parameter exists.
             if (model.GetCameraCount() > 0u)
@@ -244,13 +275,15 @@ class Scene3DSample : NUIApplication
             }
             Tizen.Log.Error("NUI", $"{model.Name} size : {model.Size.Width}, {model.Size.Height}, {model.Size.Depth}\n");
             Tizen.Log.Error("NUI", $"Animation count {model.GetAnimationCount()} , Camera count {model.GetCameraCount()}\n");
-            
+
             // Auto rotate model only if it don't have camera.
             if (mModel.GetCameraCount() == 0u)
             {
                 mModelRotateAnimation.Play();
             }
 
+            mModelLoadFinished = true;
+
             if (mMutex)
             {
                 mMutex = false;
@@ -267,6 +300,85 @@ class Scene3DSample : NUIApplication
         mMutex = true;
     }
 
+    // Note : This motion data works well only if model is MorthStressTest!
+    private void CreateMotionData()
+    {
+        mStaticMotionData = new MotionData();
+        mStaticRevertMotionData = new MotionData();
+        mAnimateMotionData = new MotionData();
+
+        mStaticMotionData.MotionValues = new List<(MotionIndex, MotionValue)>
+        {
+            (
+                new MotionTransformIndex()
+                {
+                    ModelNodeId = new PropertyKey("Main"),
+                    TransformType = MotionTransformIndex.TransformTypes.Orientation,
+                },
+                new MotionValue()
+                {
+                    Value = new PropertyValue(new Rotation(new Radian(new Degree(-45.0f)), Vector3.ZAxis)),
+                }
+            ),
+        };
+        mStaticRevertMotionData.MotionValues = new List<(MotionIndex, MotionValue)>
+        {
+            (
+                new MotionTransformIndex()
+                {
+                    ModelNodeId = new PropertyKey("Main"),
+                    TransformType = MotionTransformIndex.TransformTypes.Orientation,
+                },
+                new MotionValue()
+                {
+                    Value = new PropertyValue(new Rotation(new Radian(new Degree(0.0f)), Vector3.ZAxis)),
+                }
+            ),
+            (
+                new MotionTransformIndex()
+                {
+                    ModelNodeId = new PropertyKey("Main"),
+                    TransformType = MotionTransformIndex.TransformTypes.Scale,
+                },
+                new MotionValue()
+                {
+                    Value = new PropertyValue(Vector3.One),
+                }
+            ),
+        };
+
+        mAnimateMotionData.MotionValues = new List<(MotionIndex, MotionValue)>()
+        {
+            (
+                new MotionTransformIndex()
+                {
+                    ModelNodeId = new PropertyKey("Main"),
+                    TransformType = MotionTransformIndex.TransformTypes.Scale,
+                },
+                new MotionValue()
+                {
+                    Value = new PropertyValue(new Vector3(0.5f, 1.5f, 1.0f)),
+                }
+            ),
+        };
+        for (int i = 0; i < 8; ++i)
+        {
+            MotionIndex index = new BlendShapeIndex()
+            {
+                ModelNodeId = new PropertyKey("Main"),
+                BlendShapeId = new PropertyKey(i),
+            };
+            MotionValue value = new MotionValue()
+            {
+                KeyFramesValue = new KeyFrames()
+            };
+            value.KeyFramesValue.Add(0.0f, 0.0f);
+            value.KeyFramesValue.Add(1.0f, 1.0f * ((float)Math.Abs(i - 3.5f) + 0.5f) / 4.0f);
+
+            mAnimateMotionData.MotionValues.Add(ValueTuple.Create(index, value));
+        }
+    }
+
     void SetupIBLimage(string specularUrl, string diffuseUrl, float iblFactor)
     {
         mSceneView.SetImageBasedLightSource(IMAGE_DIR + specularUrl, IMAGE_DIR + diffuseUrl, iblFactor);
@@ -283,8 +395,6 @@ class Scene3DSample : NUIApplication
         }
         if (e.Key.State == Key.StateType.Down)
         {
-            FullGC();
-
             switch (e.Key.KeyPressedName)
             {
                 case "Escape":
@@ -347,10 +457,51 @@ class Scene3DSample : NUIApplication
                     }
                     break;
                 }
+                case "f":
+                {
+                    if (mModelAnimation?.State == Animation.States.Playing)
+                    {
+                        if (mModel != null && mModelLoadFinished)
+                        {
+                            mMotionAnimation = mModel.GenerateMotionDataAnimation(mAnimateMotionData, modelMotionAnimationDurationMilliseconds);
+
+                            if (mMotionAnimation != null)
+                            {
+                                // Stop original model animation
+                                mModelAnimation.Stop();
+
+                                mModel.SetMotionData(mStaticMotionData);
+                                mMotionAnimation.Looping = true;
+                                mMotionAnimation.Play();
+                                Tizen.Log.Error("NUI", $"Animate pre-defined motion data!\n");
+                            }
+                        }
+                    }
+                    break;
+                }
             }
+
+            FullGC();
         }
-    }
+        else if (e.Key.State == Key.StateType.Up)
+        {
+            if (mModelAnimation?.State == Animation.States.Stopped)
+            {
+                if (mMotionAnimation != null)
+                {
+                    mMotionAnimation.Stop();
+                    mMotionAnimation.Dispose();
+                    mMotionAnimation = null;
 
+                    // Revert motion data
+                    mModel.SetMotionData(mStaticRevertMotionData);
+
+                    // Replay original model animation
+                    mModelAnimation.Play();
+                }
+            }
+        }
+    }
 
     public void Activate()
     {
@@ -366,11 +517,15 @@ class Scene3DSample : NUIApplication
 
         mWindow.KeyEvent += OnKeyEvent;
 
+        // Create motion data for MorphStressTest.gltf
+        CreateMotionData();
+
         CreateSceneView();
         SetupIBLimage(IBLUrlList[currentIBLIndex].Item1, IBLUrlList[currentIBLIndex].Item2, IBLFactor);
         CreateModel(ModelUrlList[currentModelIndex]);
     }
-    public void FullGC(){
+    public void FullGC()
+    {
         global::System.GC.Collect();
         global::System.GC.WaitForPendingFinalizers();
         global::System.GC.Collect();
diff --git a/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/Base_AO.png b/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/Base_AO.png
new file mode 100644 (file)
index 0000000..567255a
Binary files /dev/null and b/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/Base_AO.png differ
diff --git a/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/ColorSwatches.png b/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/ColorSwatches.png
new file mode 100644 (file)
index 0000000..72da1c2
Binary files /dev/null and b/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/ColorSwatches.png differ
diff --git a/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/MorphStressTest.bin b/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/MorphStressTest.bin
new file mode 100644 (file)
index 0000000..53ebd67
Binary files /dev/null and b/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/MorphStressTest.bin differ
diff --git a/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/MorphStressTest.gltf b/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/MorphStressTest.gltf
new file mode 100644 (file)
index 0000000..075d258
--- /dev/null
@@ -0,0 +1,999 @@
+{
+    "asset" : {
+        "copyright" : "CC-BY 4.0 Copyright 2021 Analytical Graphics, Inc. Model and Textures by Ed Mackey.",
+        "generator" : "Khronos glTF Blender I/O v1.5.13",
+        "version" : "2.0"
+    },
+    "scene" : 0,
+    "scenes" : [
+        {
+            "name" : "Scene",
+            "nodes" : [
+                0
+            ]
+        }
+    ],
+    "nodes" : [
+        {
+            "mesh" : 0,
+            "name" : "Main"
+        }
+    ],
+    "animations" : [
+        {
+            "channels" : [
+                {
+                    "sampler" : 0,
+                    "target" : {
+                        "node" : 0,
+                        "path" : "weights"
+                    }
+                }
+            ],
+            "name" : "Individuals",
+            "samplers" : [
+                {
+                    "input" : 42,
+                    "interpolation" : "LINEAR",
+                    "output" : 43
+                }
+            ]
+        },
+        {
+            "channels" : [
+                {
+                    "sampler" : 0,
+                    "target" : {
+                        "node" : 0,
+                        "path" : "weights"
+                    }
+                }
+            ],
+            "name" : "TheWave",
+            "samplers" : [
+                {
+                    "input" : 44,
+                    "interpolation" : "LINEAR",
+                    "output" : 45
+                }
+            ]
+        },
+        {
+            "channels" : [
+                {
+                    "sampler" : 0,
+                    "target" : {
+                        "node" : 0,
+                        "path" : "weights"
+                    }
+                }
+            ],
+            "name" : "Pulse",
+            "samplers" : [
+                {
+                    "input" : 46,
+                    "interpolation" : "LINEAR",
+                    "output" : 47
+                }
+            ]
+        }
+    ],
+    "materials" : [
+        {
+            "doubleSided" : true,
+            "name" : "Base",
+            "occlusionTexture" : {
+                "index" : 0,
+                "texCoord" : 1
+            },
+            "pbrMetallicRoughness" : {
+                "baseColorTexture" : {
+                    "index" : 1
+                },
+                "metallicFactor" : 0,
+                "roughnessFactor" : 0.4000000059604645
+            }
+        },
+        {
+            "doubleSided" : true,
+            "name" : "TestMaterial",
+            "pbrMetallicRoughness" : {
+                "baseColorTexture" : {
+                    "index" : 2
+                },
+                "metallicFactor" : 0,
+                "roughnessFactor" : 0.5
+            }
+        }
+    ],
+    "meshes" : [
+        {
+            "extras" : {
+                "targetNames" : [
+                    "Key 1",
+                    "Key 2",
+                    "Key 3",
+                    "Key 4",
+                    "Key 5",
+                    "Key 6",
+                    "Key 7",
+                    "Key 8"
+                ]
+            },
+            "name" : "Cube",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 0,
+                        "NORMAL" : 1,
+                        "TEXCOORD_0" : 2,
+                        "TEXCOORD_1" : 3
+                    },
+                    "indices" : 4,
+                    "material" : 0,
+                    "targets" : [
+                        {
+                            "POSITION" : 5,
+                            "NORMAL" : 6
+                        },
+                        {
+                            "POSITION" : 7,
+                            "NORMAL" : 8
+                        },
+                        {
+                            "POSITION" : 9,
+                            "NORMAL" : 10
+                        },
+                        {
+                            "POSITION" : 11,
+                            "NORMAL" : 12
+                        },
+                        {
+                            "POSITION" : 13,
+                            "NORMAL" : 14
+                        },
+                        {
+                            "POSITION" : 15,
+                            "NORMAL" : 16
+                        },
+                        {
+                            "POSITION" : 17,
+                            "NORMAL" : 18
+                        },
+                        {
+                            "POSITION" : 19,
+                            "NORMAL" : 20
+                        }
+                    ]
+                },
+                {
+                    "attributes" : {
+                        "POSITION" : 21,
+                        "NORMAL" : 22,
+                        "TEXCOORD_0" : 23,
+                        "TEXCOORD_1" : 24
+                    },
+                    "indices" : 25,
+                    "material" : 1,
+                    "targets" : [
+                        {
+                            "POSITION" : 26,
+                            "NORMAL" : 27
+                        },
+                        {
+                            "POSITION" : 28,
+                            "NORMAL" : 29
+                        },
+                        {
+                            "POSITION" : 30,
+                            "NORMAL" : 31
+                        },
+                        {
+                            "POSITION" : 32,
+                            "NORMAL" : 33
+                        },
+                        {
+                            "POSITION" : 34,
+                            "NORMAL" : 35
+                        },
+                        {
+                            "POSITION" : 36,
+                            "NORMAL" : 37
+                        },
+                        {
+                            "POSITION" : 38,
+                            "NORMAL" : 39
+                        },
+                        {
+                            "POSITION" : 40,
+                            "NORMAL" : 41
+                        }
+                    ]
+                }
+            ],
+            "weights" : [
+                0,
+                0,
+                0,
+                0,
+                0,
+                0,
+                0,
+                0
+            ]
+        }
+    ],
+    "textures" : [
+        {
+            "sampler" : 0,
+            "source" : 0
+        },
+        {
+            "sampler" : 0,
+            "source" : 1
+        },
+        {
+            "sampler" : 0,
+            "source" : 2
+        }
+    ],
+    "images" : [
+        {
+            "mimeType" : "image/png",
+            "name" : "Base_AO",
+            "uri" : "Base_AO.png"
+        },
+        {
+            "mimeType" : "image/png",
+            "name" : "TinyGrid",
+            "uri" : "TinyGrid.png"
+        },
+        {
+            "mimeType" : "image/png",
+            "name" : "ColorSwatches",
+            "uri" : "ColorSwatches.png"
+        }
+    ],
+    "accessors" : [
+        {
+            "bufferView" : 0,
+            "componentType" : 5126,
+            "count" : 24,
+            "max" : [
+                2,
+                0,
+                0.5
+            ],
+            "min" : [
+                -2,
+                -0.10000002384185791,
+                -0.5
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 1,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 2,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 3,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 4,
+            "componentType" : 5123,
+            "count" : 36,
+            "type" : "SCALAR"
+        },
+        {
+            "bufferView" : 5,
+            "componentType" : 5126,
+            "count" : 24,
+            "max" : [
+                0,
+                0,
+                0
+            ],
+            "min" : [
+                0,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 6,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 7,
+            "componentType" : 5126,
+            "count" : 24,
+            "max" : [
+                0,
+                0,
+                0
+            ],
+            "min" : [
+                0,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 8,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 9,
+            "componentType" : 5126,
+            "count" : 24,
+            "max" : [
+                0,
+                0,
+                0
+            ],
+            "min" : [
+                0,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 10,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 11,
+            "componentType" : 5126,
+            "count" : 24,
+            "max" : [
+                0,
+                0,
+                0
+            ],
+            "min" : [
+                0,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 12,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 13,
+            "componentType" : 5126,
+            "count" : 24,
+            "max" : [
+                0,
+                0,
+                0
+            ],
+            "min" : [
+                0,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 14,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 15,
+            "componentType" : 5126,
+            "count" : 24,
+            "max" : [
+                0,
+                0,
+                0
+            ],
+            "min" : [
+                0,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 16,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 17,
+            "componentType" : 5126,
+            "count" : 24,
+            "max" : [
+                0,
+                0,
+                0
+            ],
+            "min" : [
+                0,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 18,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 19,
+            "componentType" : 5126,
+            "count" : 24,
+            "max" : [
+                0,
+                0,
+                0
+            ],
+            "min" : [
+                0,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 20,
+            "componentType" : 5126,
+            "count" : 24,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 21,
+            "componentType" : 5126,
+            "count" : 1504,
+            "max" : [
+                1.875,
+                0.5,
+                0.25
+            ],
+            "min" : [
+                -1.875,
+                0,
+                -0.25
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 22,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 23,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 24,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 25,
+            "componentType" : 5123,
+            "count" : 7200,
+            "type" : "SCALAR"
+        },
+        {
+            "bufferView" : 26,
+            "componentType" : 5126,
+            "count" : 1504,
+            "max" : [
+                0.04999995231628418,
+                1,
+                0
+            ],
+            "min" : [
+                -0.04999995231628418,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 27,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 28,
+            "componentType" : 5126,
+            "count" : 1504,
+            "max" : [
+                0.04999995231628418,
+                1,
+                0
+            ],
+            "min" : [
+                -0.04999995231628418,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 29,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 30,
+            "componentType" : 5126,
+            "count" : 1504,
+            "max" : [
+                0.050000011920928955,
+                1,
+                0
+            ],
+            "min" : [
+                -0.050000011920928955,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 31,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 32,
+            "componentType" : 5126,
+            "count" : 1504,
+            "max" : [
+                0.050000011920928955,
+                1,
+                0
+            ],
+            "min" : [
+                -0.04999999701976776,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 33,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 34,
+            "componentType" : 5126,
+            "count" : 1504,
+            "max" : [
+                0.04999999701976776,
+                1,
+                0
+            ],
+            "min" : [
+                -0.050000011920928955,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 35,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 36,
+            "componentType" : 5126,
+            "count" : 1504,
+            "max" : [
+                0.050000011920928955,
+                1,
+                0
+            ],
+            "min" : [
+                -0.050000011920928955,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 37,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 38,
+            "componentType" : 5126,
+            "count" : 1504,
+            "max" : [
+                0.04999995231628418,
+                1,
+                0
+            ],
+            "min" : [
+                -0.04999995231628418,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 39,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 40,
+            "componentType" : 5126,
+            "count" : 1504,
+            "max" : [
+                0.04999995231628418,
+                1,
+                0
+            ],
+            "min" : [
+                -0.04999995231628418,
+                0,
+                0
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 41,
+            "componentType" : 5126,
+            "count" : 1504,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 42,
+            "componentType" : 5126,
+            "count" : 281,
+            "max" : [
+                9.366666666666667
+            ],
+            "min" : [
+                0.03333333333333333
+            ],
+            "type" : "SCALAR"
+        },
+        {
+            "bufferView" : 43,
+            "componentType" : 5126,
+            "count" : 2248,
+            "type" : "SCALAR"
+        },
+        {
+            "bufferView" : 44,
+            "componentType" : 5126,
+            "count" : 59,
+            "max" : [
+                1.9666666666666666
+            ],
+            "min" : [
+                0.03333333333333333
+            ],
+            "type" : "SCALAR"
+        },
+        {
+            "bufferView" : 45,
+            "componentType" : 5126,
+            "count" : 472,
+            "type" : "SCALAR"
+        },
+        {
+            "bufferView" : 46,
+            "componentType" : 5126,
+            "count" : 191,
+            "max" : [
+                6.366666666666666
+            ],
+            "min" : [
+                0.03333333333333333
+            ],
+            "type" : "SCALAR"
+        },
+        {
+            "bufferView" : 47,
+            "componentType" : 5126,
+            "count" : 1528,
+            "type" : "SCALAR"
+        }
+    ],
+    "bufferViews" : [
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 0
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 288
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 192,
+            "byteOffset" : 576
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 192,
+            "byteOffset" : 768
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 72,
+            "byteOffset" : 960
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 1032
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 1320
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 1608
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 1896
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 2184
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 2472
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 2760
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 3048
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 3336
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 3624
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 3912
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 4200
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 4488
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 4776
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 5064
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 288,
+            "byteOffset" : 5352
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 5640
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 23688
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 12032,
+            "byteOffset" : 41736
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 12032,
+            "byteOffset" : 53768
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 14400,
+            "byteOffset" : 65800
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 80200
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 98248
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 116296
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 134344
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 152392
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 170440
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 188488
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 206536
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 224584
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 242632
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 260680
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 278728
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 296776
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 314824
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 332872
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 18048,
+            "byteOffset" : 350920
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 1124,
+            "byteOffset" : 368968
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 8992,
+            "byteOffset" : 370092
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 236,
+            "byteOffset" : 379084
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 1888,
+            "byteOffset" : 379320
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 764,
+            "byteOffset" : 381208
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 6112,
+            "byteOffset" : 381972
+        }
+    ],
+    "samplers" : [
+        {
+            "magFilter" : 9729,
+            "minFilter" : 9987
+        }
+    ],
+    "buffers" : [
+        {
+            "byteLength" : 388084,
+            "uri" : "MorphStressTest.bin"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/TinyGrid.png b/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/TinyGrid.png
new file mode 100644 (file)
index 0000000..81d040a
Binary files /dev/null and b/test/Tizen.NUI.Scene3D.Sample/res/model/MorphStressTest/TinyGrid.png differ