--- /dev/null
+/*
+ * 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)
+ }
+ }
+ }
+ }
+ }
+ }
+}
/*
- * 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.
/// </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)
{
}
/// <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>
--- /dev/null
+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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+ }
+}
--- /dev/null
+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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+}
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
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;
#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>()
{
mModel.Dispose();
}
+ // Release old animation if exist
+ if (mModelAnimation != null)
+ {
+ mModelAnimation.Stop();
+ mModelAnimation.Dispose();
+ mModelAnimation = null;
+ }
+
// Release old camera if exist
if (additionalCameraList != null)
{
additionalCameraList = null;
}
+ mModelLoadFinished = false;
+
mModel = new Model(MODEL_DIR + modelUrl)
{
Name = modelUrl,
// 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)
}
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;
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);
}
if (e.Key.State == Key.StateType.Down)
{
- FullGC();
-
switch (e.Key.KeyPressedName)
{
case "Escape":
}
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()
{
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();
--- /dev/null
+{
+ "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