public Animation_NodeMisc(List <string> imageList)
        {
            Runtime.Image baseColorTextureImage = UseTexture(imageList, "BaseColor_Cube");

            // There are no common properties in this model group that are reported in the readme.

            Model CreateModel(Action <List <Property>, List <Runtime.AnimationChannel>, List <Runtime.Node>, List <Runtime.Animation> > setProperties)
            {
                var properties        = new List <Property>();
                var cubeMeshPrimitive = MeshPrimitive.CreateCube();

                // Apply the common properties to the gltf.
                cubeMeshPrimitive.Material = new Runtime.Material
                {
                    MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness
                    {
                        BaseColorTexture = new Runtime.Texture {
                            Source = baseColorTextureImage
                        },
                    },
                };
                var channels = new List <Runtime.AnimationChannel>
                {
                    new Runtime.AnimationChannel()
                };
                var nodes = new List <Runtime.Node>
                {
                    new Runtime.Node(),
                };
                var animations = new List <Runtime.Animation>
                {
                    new Runtime.Animation
                    {
                        Channels = channels
                    }
                };

                // Apply the properties that are specific to this gltf.
                setProperties(properties, channels, nodes, animations);

                // Create the gltf object.
                foreach (var node in nodes)
                {
                    node.Mesh = new Runtime.Mesh
                    {
                        MeshPrimitives = new List <Runtime.MeshPrimitive>
                        {
                            cubeMeshPrimitive
                        }
                    };
                }
                Runtime.GLTF gltf = CreateGLTF(() => new Runtime.Scene
                {
                    Nodes = nodes
                });
                gltf.Animations = animations;
                return(new Model
                {
                    Properties = properties,
                    GLTF = gltf,
                    Animated = true,
                });
            }

            void SetTranslationChannelTarget(Runtime.AnimationChannel channel, Runtime.Node node)
            {
                channel.Target = new Runtime.AnimationChannelTarget
                {
                    Node = node,
                    Path = Runtime.AnimationChannelTarget.PathEnum.TRANSLATION,
                };
            }

            void SetRotationChannelTarget(Runtime.AnimationChannel channel, Runtime.Node node)
            {
                channel.Target = new Runtime.AnimationChannelTarget
                {
                    Node = node,
                    Path = Runtime.AnimationChannelTarget.PathEnum.ROTATION,
                };
            }

            void SetLinearSamplerForTranslation(Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.LinearAnimationSampler <Vector3>
                                  (
                    new[]
                {
                    0.0f,
                    2.0f,
                    4.0f,
                },
                    new[]
                {
                    new Vector3(-0.1f, 0.0f, 0.0f),
                    new Vector3(0.1f, 0.0f, 0.0f),
                    new Vector3(-0.1f, 0.0f, 0.0f),
                }
                                  );
            }

            void SetLinearSamplerForHorizontalRotation(Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.LinearAnimationSampler <Quaternion>
                                  (
                    new[]
                {
                    0.0f,
                    1.0f,
                    2.0f,
                    3.0f,
                    4.0f,
                },
                    new[]
                {
                    Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(90.0f), 0.0f, 0.0f),
                    Quaternion.Identity,
                    Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(-90.0f), 0.0f, 0.0f),
                    Quaternion.Identity,
                    Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(90.0f), 0.0f, 0.0f),
                }
                                  );
            }

            void SetLinearSamplerForVerticalRotation(Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.LinearAnimationSampler <Quaternion>
                                  (
                    new[]
                {
                    0.0f,
                    1.0f,
                    2.0f,
                    3.0f,
                    4.0f,
                },
                    new[]
                {
                    Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(90.0f), 0.0f),
                    Quaternion.Identity,
                    Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-90.0f), 0.0f),
                    Quaternion.Identity,
                    Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(90.0f), 0.0f),
                }
                                  );
            }

            void SetLinearSamplerForConstantRotation(Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.LinearAnimationSampler <Quaternion>
                                  (
                    new[]
                {
                    0.0f,
                    6.0f,
                },
                    new[]
                {
                    Quaternion.CreateFromYawPitchRoll(-FloatMath.Pi / 3.0f, 0.0f, 0.0f),
                    Quaternion.CreateFromYawPitchRoll(-FloatMath.Pi / 3.0f, 0.0f, 0.0f),
                }
                                  );
            }

            void SetLinearSamplerForTranslationStartsAboveZero(Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.LinearAnimationSampler <Vector3>
                                  (
                    new[]
                {
                    2.0f,
                    4.0f,
                    6.0f,
                },
                    new[]
                {
                    new Vector3(0.0f, -0.1f, 0.0f),
                    new Vector3(0.0f, 0.1f, 0.0f),
                    new Vector3(0.0f, -0.1f, 0.0f),
                }
                                  );
            }

            void SetLinearSamplerWithOneKey(Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.LinearAnimationSampler <Vector3>
                                  (
                    new[]
                {
                    0.0f,
                },
                    new[]
                {
                    new Vector3(-0.1f, 0.0f, 0.0f),
                }
                                  );
            }

            void SetLinearSamplerForRotationThatStartsAboveZero(Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.LinearAnimationSampler <Quaternion>
                                  (
                    new[]
                {
                    1.0f,
                    2.0f,
                    3.0f,
                    4.0f,
                    5.0f,
                },
                    new[]
                {
                    Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(90.0f), 0.0f, 0.0f),
                    Quaternion.Identity,
                    Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(-90.0f), 0.0f, 0.0f),
                    Quaternion.Identity,
                    Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(90.0f), 0.0f, 0.0f),
                }
                                  );
            }

            void CreateMultipleChannelsWithUniqueTargets(List <Runtime.AnimationChannel> channels, Runtime.Node node)
            {
                // The first channel is already added as a common property.
                channels.Add(new Runtime.AnimationChannel());

                SetTranslationChannelTarget(channels[0], node);
                SetRotationChannelTarget(channels[1], node);

                var samplerPropertiesList = new List <Property>();

                SetLinearSamplerForTranslation(channels[0]);
                SetLinearSamplerForHorizontalRotation(channels[1]);
            }

            void CreateMultipleChannelsWithDifferentTimes(List <Runtime.AnimationChannel> channels, Runtime.Node node)
            {
                // The first channel is already added as a common property.
                channels.Add(new Runtime.AnimationChannel());

                SetTranslationChannelTarget(channels[0], node);
                SetRotationChannelTarget(channels[1], node);

                SetLinearSamplerForTranslationStartsAboveZero(channels[0]);
                SetLinearSamplerForRotationThatStartsAboveZero(channels[1]);
            }

            void CreateMultipleChannelsForDifferentNodes(List <Runtime.AnimationChannel> channels, Runtime.Node node0, Runtime.Node node1)
            {
                // The first channel is already added as a common property.
                channels.Add(new Runtime.AnimationChannel());

                SetRotationChannelTarget(channels[0], node0);
                SetRotationChannelTarget(channels[1], node1);

                SetLinearSamplerForHorizontalRotation(channels[0]);
                SetLinearSamplerForVerticalRotation(channels[1]);
            }

            Models = new List <Model>
            {
                CreateModel((properties, channels, nodes, animations) =>
                {
                    // Multiple channels
                    CreateMultipleChannelsWithUniqueTargets(channels, nodes[0]);
                    properties.Add(new Property(PropertyName.Description,
                                                "There are two channels. The first channel targets translation. The second channel targets rotation. The start and end times of both channels are `0.0` and `4.0` respectively."));
                }),
                CreateModel((properties, channels, nodes, animations) =>
                {
                    // Curve that doesn't start at zero
                    SetRotationChannelTarget(channels[0], nodes[0]);
                    SetLinearSamplerForRotationThatStartsAboveZero(channels[0]);
                    properties.Add(new Property(PropertyName.Description,
                                                "There is one channel with a non-zero start time. The channel targets rotation. The start time is `1.0`."));
                }),
                CreateModel((properties, channels, nodes, animations) =>
                {
                    // Two channels with different start/end times
                    CreateMultipleChannelsWithDifferentTimes(channels, nodes[0]);
                    properties.Add(new Property(PropertyName.Description,
                                                "There are two channels with different start and end times. The first channel targets translation with start and end times of `2.0` and `6.0` respectively. The second channel targets rotation with start and end times of `1.0` and `5.0` respectively."));
                }),
                CreateModel((properties, channels, nodes, animations) =>
                {
                    // Has only one key
                    SetTranslationChannelTarget(channels[0], nodes[0]);
                    SetLinearSamplerWithOneKey(channels[0]);
                    properties.Add(new Property(PropertyName.Description,
                                                "There is one channel with only one keyframe. The channel targets translation with a value of <code>[-0.1,&nbsp;0.0,&nbsp;0.0]</code>."));
                }),
                CreateModel((properties, channels, nodes, animations) =>
                {
                    // Creates a second node based on the existing node, and applies a transform to help differentiate them.
                    nodes.Add(DeepCopy.CloneObject(nodes[0]));
                    nodes[0].Translation = new Vector3(-0.2f, 0.0f, 0.0f);
                    nodes[1].Translation = new Vector3(0.2f, 0.0f, 0.0f);
                    nodes[0].Scale       = new Vector3(0.5f, 0.5f, 0.5f);
                    nodes[1].Scale       = new Vector3(0.5f, 0.5f, 0.5f);

                    // One animation, two channels for two nodes.
                    CreateMultipleChannelsForDifferentNodes(channels, nodes[0], nodes[1]);
                    properties.Add(new Property(PropertyName.Description,
                                                "There are two channels with different nodes. The first channel targets the left node and rotation along the X axis. The second channel targets the right node and rotation along the Y axis."));
                }),
                CreateModel((properties, channels, nodes, animations) =>
                {
                    // Rotate the model, and then apply the same target animation to it (Animation overrides)
                    nodes[0].Rotation = Quaternion.CreateFromYawPitchRoll(FloatMath.Pi / 3.0f, 0.0f, 0.0f);
                    SetRotationChannelTarget(channels[0], nodes[0]);
                    SetLinearSamplerForConstantRotation(channels[0]);
                    properties.Add(new Property(PropertyName.Description,
                                                "There is one channel that targets a node. The node has a rotation of <code>[0.0,&nbsp;0.5,&nbsp;0.0,&nbsp;0.866]</code>. The channel overrides the rotation of the node to a different constant value of <code>[0.0,&nbsp;-0.5,&nbsp;0.0,&nbsp;0.866]</code>."));
                }),
                CreateModel((properties, channels, nodes, animations) =>
                {
                    // Rotate the model, and then apply an translation animation to it (Animation doesn't override rotation)
                    nodes[0].Rotation = Quaternion.CreateFromYawPitchRoll(FloatMath.Pi / 3.0f, 0.0f, 0.0f);
                    SetTranslationChannelTarget(channels[0], nodes[0]);
                    SetLinearSamplerForTranslation(channels[0]);
                    properties.Add(new Property(PropertyName.Description,
                                                "There is one channel that targets a node. The node has a rotation of <code>[0.0,&nbsp;0.5,&nbsp;0.0,&nbsp;0.866]</code>. The channel targets the translation of the node."));
                }),
                CreateModel((properties, channels, nodes, animations) =>
                {
                    // Two animations. One rotates, the other translates. They should not interact or bleed across.
                    var channel = new Runtime.AnimationChannel();
                    SetTranslationChannelTarget(channel, nodes[0]);
                    SetLinearSamplerForTranslation(channel);
                    animations.Add(new Runtime.Animation
                    {
                        Channels = new[]
                        {
                            channel
                        }
                    });

                    // The first animation is already added as an empty common property.
                    SetRotationChannelTarget(channels[0], nodes[0]);
                    SetLinearSamplerForHorizontalRotation(channels[0]);

                    properties.Add(new Property(PropertyName.Description,
                                                "There are two animations, each with one channel. The first animation's channel targets rotation. The second animation's channel targets translation."));
                }),
                CreateModel((properties, channels, nodes, animations) =>
                {
                    // Multiple channels, but one omits node (the channel with no target node is ignored per the spec).
                    CreateMultipleChannelsForDifferentNodes(channels, null, nodes[0]);

                    properties.Add(new Property(PropertyName.Description,
                                                "There are two channels. The first channel has a rotation along the X axis but does not specify a node. The second channel does target the node and has a rotation along the Y axis."));
                }),
            };

            GenerateUsedPropertiesList();
        }
Exemplo n.º 2
0
            private static List <Runtime.Node> CreateJointsAndWeightsForCommonRoot(Runtime.Node nodePlane)
            {
                Matrix4x4 baseRotation                    = Matrix4x4.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-90.0f), 0.0f);
                Matrix4x4 jointRotation                   = Matrix4x4.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-15.0f), 0.0f);
                var       translationVectorJoint3         = new Vector3(0.1875f, 0.0f, 0.25f);
                var       translationVectorJoint2         = new Vector3(-0.1875f, 0.0f, 0.25f);
                var       translationVectorJoint1         = new Vector3(0.0f, 0.0f, 0.25f);
                var       translationVectorJoint0         = new Vector3(0.0f, -0.25f, 0.0f);
                Matrix4x4 invertedTranslationMatrixJoint3 = Matrix4x4.CreateTranslation(-translationVectorJoint3);
                Matrix4x4 invertedTranslationMatrixJoint2 = Matrix4x4.CreateTranslation(-translationVectorJoint2);

                var matrixJoint1 = jointRotation;

                Matrix4x4.Invert(matrixJoint1, out Matrix4x4 invertedJoint1);

                var matrixJoint0 = Matrix4x4.CreateTranslation(new Vector3(0, 0.0f, -0.25f));

                Matrix4x4.Invert(matrixJoint0, out Matrix4x4 invertedJoint0);

                var nodeJoint3 = new Runtime.Node
                {
                    Name        = "joint3",
                    Rotation    = Quaternion.CreateFromRotationMatrix(jointRotation),
                    Translation = translationVectorJoint3,
                };
                var nodeJoint2 = new Runtime.Node
                {
                    Name        = "joint2",
                    Rotation    = Quaternion.CreateFromRotationMatrix(jointRotation),
                    Translation = translationVectorJoint2,
                };
                var nodeJoint1 = new Runtime.Node
                {
                    Name        = "joint1",
                    Rotation    = Quaternion.CreateFromRotationMatrix(jointRotation),
                    Translation = translationVectorJoint1,
                    Children    = new[]
                    {
                        nodeJoint2,
                        nodeJoint3
                    }
                };
                var nodeJoint0 = new Runtime.Node
                {
                    Name        = "joint0",
                    Rotation    = Quaternion.CreateFromRotationMatrix(baseRotation),
                    Translation = translationVectorJoint0,
                    Children    = new[]
                    {
                        nodeJoint1
                    }
                };

                nodePlane.Skin = new Runtime.Skin
                {
                    Name   = "skinE",
                    Joints = new List <Runtime.Node>
                    {
                        nodeJoint0,
                        nodeJoint1,
                        nodeJoint2,
                        nodeJoint3
                    },
                    InverseBindMatrices = new List <Matrix4x4>
                    {
                        invertedJoint0,
                        invertedJoint1,
                        invertedTranslationMatrixJoint2,
                        invertedTranslationMatrixJoint3
                    }
                };

                // Top four vertexes of each arm have a weight for the relevant joint. Otherwise the vertex has a weight from the root.
                var jointWeights = new List <List <Runtime.JointWeight> >();

                // Base of trunk
                for (var vertexIndex = 0; vertexIndex < 2; vertexIndex++)
                {
                    jointWeights.Add(new List <Runtime.JointWeight>
                    {
                        new Runtime.JointWeight
                        {
                            JointIndex = 0,
                            Weight     = 1,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 1,
                            Weight     = 0,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 2,
                            Weight     = 0,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 3,
                            Weight     = 0,
                        }
                    });
                }
                // Top of trunk
                for (var vertexIndex = 0; vertexIndex < 3; vertexIndex++)
                {
                    jointWeights.Add(new List <Runtime.JointWeight>
                    {
                        new Runtime.JointWeight
                        {
                            JointIndex = 0,
                            Weight     = 0,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 1,
                            Weight     = 1,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 2,
                            Weight     = 0,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 3,
                            Weight     = 0,
                        }
                    });
                }
                // Left arm
                for (var vertexIndex = 0; vertexIndex < 4; vertexIndex++)
                {
                    jointWeights.Add(new List <Runtime.JointWeight>
                    {
                        new Runtime.JointWeight
                        {
                            JointIndex = 0,
                            Weight     = 0,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 1,
                            Weight     = 0,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 2,
                            Weight     = 1,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 3,
                            Weight     = 0,
                        }
                    });
                }
                // Right arm
                for (var vertexIndex = 0; vertexIndex < 4; vertexIndex++)
                {
                    jointWeights.Add(new List <Runtime.JointWeight>
                    {
                        new Runtime.JointWeight
                        {
                            JointIndex = 0,
                            Weight     = 0,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 1,
                            Weight     = 0,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 2,
                            Weight     = 0,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 3,
                            Weight     = 1,
                        }
                    });
                }
                nodePlane.Mesh.MeshPrimitives.First().VertexJointWeights = jointWeights;

                return(new List <Runtime.Node>
                {
                    nodePlane,
                    nodeJoint0
                });
            }
Exemplo n.º 3
0
            public static List <Runtime.Node> CreatePlaneWithSkinB()
            {
                var colorInner = new Vector4(0.8f, 0.8f, 0.8f, 1.0f);
                var colorOuter = new Vector4(0.0f, 0.0f, 1.0f, 1.0f);

                Matrix4x4 rotation = Matrix4x4.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(90.0f), 0.0f);
                var       translationVectorJoint1 = new Vector3(0.0f, 0.0f, -0.6f);
                var       translationVectorJoint0 = new Vector3(0.0f, 0.0f, 0.3f);
                Matrix4x4 matrixJoint1            = Matrix4x4.CreateTranslation(translationVectorJoint1);
                Matrix4x4 matrixJoint0            = Matrix4x4.CreateTranslation(translationVectorJoint0);

                matrixJoint1 = Matrix4x4.Multiply(matrixJoint0, matrixJoint1);
                Matrix4x4.Invert(matrixJoint1, out Matrix4x4 invertedJoint1);
                Matrix4x4.Invert(matrixJoint0, out Matrix4x4 invertedJoint0);

                var nodeJoint1 = new Runtime.Node
                {
                    Name        = "joint1",
                    Translation = translationVectorJoint1,
                };
                var nodeJoint0 = new Runtime.Node
                {
                    Name        = "joint0",
                    Rotation    = Quaternion.CreateFromRotationMatrix(rotation),
                    Translation = new Vector3(0.0f, -0.3f, 0.0f),
                    Children    = new[]
                    {
                        nodeJoint1
                    },
                };

                var jointsList = new List <Runtime.Node>
                {
                    nodeJoint0,
                    nodeJoint1
                };
                var inverseBindMatricesList = new List <Matrix4x4>
                {
                    invertedJoint0,
                    invertedJoint1
                };
                var innerSkin = new Runtime.Skin
                {
                    Joints = jointsList,
                    InverseBindMatrices = inverseBindMatricesList
                };
                var outerSkin = new Runtime.Skin
                {
                    Joints = jointsList,
                    InverseBindMatrices = inverseBindMatricesList
                };

                var nodeInnerPrism = new Runtime.Node
                {
                    Name = "innerPrism",
                    Skin = innerSkin,
                    Mesh = Mesh.CreatePrism(colorInner),
                };

                var nodeOuterPrism = new Runtime.Node
                {
                    Name = "outerPrism",
                    Skin = outerSkin,
                    Mesh = Mesh.CreatePrism(colorOuter, Scale: new Vector3(1.6f, 1.6f, 0.3f)),
                };

                var weightsListInnerPrism = new List <List <Runtime.JointWeight> >();
                var weightsListOuterPrism = new List <List <Runtime.JointWeight> >();

                for (var i = 0; i < 3; i++)
                {
                    var weight = new List <Runtime.JointWeight>
                    {
                        new Runtime.JointWeight
                        {
                            JointIndex = 0,
                            Weight     = 1,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 1,
                            Weight     = 0,
                        },
                    };
                    weightsListInnerPrism.Add(weight);
                    weightsListOuterPrism.Add(weight);
                }
                for (var i = 0; i < 3; i++)
                {
                    var weight = new List <Runtime.JointWeight>
                    {
                        new Runtime.JointWeight
                        {
                            JointIndex = 0,
                            Weight     = 0,
                        },
                        new Runtime.JointWeight
                        {
                            JointIndex = 1,
                            Weight     = 1,
                        },
                    };
                    weightsListInnerPrism.Add(weight);
                    weightsListOuterPrism.Add(weight);
                }
                nodeInnerPrism.Mesh.MeshPrimitives.First().VertexJointWeights = weightsListInnerPrism;
                nodeOuterPrism.Mesh.MeshPrimitives.First().VertexJointWeights = weightsListOuterPrism;

                return(new List <Runtime.Node>
                {
                    nodeInnerPrism,
                    nodeJoint0,
                    nodeOuterPrism
                });
            }
Exemplo n.º 4
0
            private static List <Runtime.Node> CreateJointsAndWeightsForMultipleRoots(Runtime.Node nodePlane)
            {
                Matrix4x4 baseRotation            = Matrix4x4.CreateFromYawPitchRoll(0.0f, FloatMath.ConvertDegreesToRadians(-90.0f), 0.0f);
                Matrix4x4 jointRotation           = Matrix4x4.CreateFromYawPitchRoll(0.0f, FloatMath.ConvertDegreesToRadians(-15.0f), 0.0f);
                var       translationVectorJoint3 = new Vector3(0.0f, 0.25f, 0.0f);
                var       translationVectorJoint2 = new Vector3(0.0f, 0.0f, 0.25f);
                var       translationVectorJoint1 = new Vector3(0.1875f, -0.25f, 0.0f);
                var       translationVectorJoint0 = new Vector3(-0.1875f, -0.25f, 0.0f);
                Matrix4x4 invertedJoint3          = Matrix4x4.CreateTranslation(-translationVectorJoint3);
                Matrix4x4 invertedJoint2          = Matrix4x4.CreateTranslation(-translationVectorJoint2);
                Matrix4x4 invertedJoint1          = Matrix4x4.CreateTranslation(new Vector3(-0.1875f, 0.0f, 0.25f));
                Matrix4x4 invertedJoint0          = Matrix4x4.CreateTranslation(new Vector3(0.1875f, 0.0f, 0.25f));

                var nodeJoint3 = new Runtime.Node
                {
                    Name        = "joint3",
                    Rotation    = Quaternion.CreateFromRotationMatrix(jointRotation),
                    Translation = translationVectorJoint3,
                };
                var nodeJoint2 = new Runtime.Node
                {
                    Name        = "joint2",
                    Rotation    = Quaternion.CreateFromRotationMatrix(jointRotation),
                    Translation = translationVectorJoint2,
                    Children    = new[]
                    {
                        nodeJoint3
                    }
                };
                var nodeJoint1 = new Runtime.Node
                {
                    Name        = "joint1",
                    Rotation    = Quaternion.CreateFromRotationMatrix(baseRotation),
                    Translation = translationVectorJoint1,
                    Children    = new[]
                    {
                        nodeJoint2
                    }
                };
                var nodeJoint0 = new Runtime.Node
                {
                    Name        = "joint0",
                    Rotation    = Quaternion.CreateFromRotationMatrix(baseRotation),
                    Translation = translationVectorJoint0,
                    Children    = new[]
                    {
                        nodeJoint2
                    }
                };

                var joint3 = new Runtime.SkinJoint
                             (
                    inverseBindMatrix: invertedJoint3,
                    node: nodeJoint3
                             );
                var joint2 = new Runtime.SkinJoint
                             (
                    inverseBindMatrix: invertedJoint2,
                    node: nodeJoint2
                             );
                var joint1 = new Runtime.SkinJoint
                             (
                    inverseBindMatrix: invertedJoint1,
                    node: nodeJoint1
                             );
                var joint0 = new Runtime.SkinJoint
                             (
                    inverseBindMatrix: invertedJoint0,
                    node: nodeJoint0
                             );

                nodePlane.Skin.SkinJoints = new[]
                {
                    joint0,
                    joint1,
                    joint2,
                    joint3
                };

                // Top four vertexes of each arm have a weight for the relevant joint. Otherwise the vertex has a weight from the root
                var jointWeights = new List <List <Runtime.JointWeight> >();

                // Base of trunk
                for (int vertexIndex = 0; vertexIndex < 2; vertexIndex++)
                {
                    jointWeights.Add(new List <Runtime.JointWeight>()
                    {
                        new Runtime.JointWeight
                        {
                            Joint  = joint0,
                            Weight = 0,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint1,
                            Weight = 0,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint2,
                            Weight = 0,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint3,
                            Weight = 1,
                        }
                    });
                }
                // Top of trunk
                for (int vertexIndex = 0; vertexIndex < 3; vertexIndex++)
                {
                    jointWeights.Add(new List <Runtime.JointWeight>()
                    {
                        new Runtime.JointWeight
                        {
                            Joint  = joint0,
                            Weight = 0,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint1,
                            Weight = 0,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint2,
                            Weight = 1,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint3,
                            Weight = 0,
                        }
                    });
                }
                // Left arm
                for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++)
                {
                    jointWeights.Add(new List <Runtime.JointWeight>()
                    {
                        new Runtime.JointWeight
                        {
                            Joint  = joint0,
                            Weight = 1,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint1,
                            Weight = 0,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint2,
                            Weight = 0,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint3,
                            Weight = 0,
                        }
                    });
                }
                // Right arm
                for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++)
                {
                    jointWeights.Add(new List <Runtime.JointWeight>()
                    {
                        new Runtime.JointWeight
                        {
                            Joint  = joint0,
                            Weight = 0,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint1,
                            Weight = 1,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint2,
                            Weight = 0,
                        },
                        new Runtime.JointWeight
                        {
                            Joint  = joint3,
                            Weight = 0,
                        }
                    });
                }
                nodePlane.Mesh.MeshPrimitives.First().VertexJointWeights = jointWeights;

                return(new List <Runtime.Node>
                {
                    nodePlane,
                    nodeJoint0,
                    nodeJoint1
                });
            }
Exemplo n.º 5
0
            public static List <Runtime.Node> CreateFoldingPlaneSkin(string skinName, int numberOfNodesInJointHierarchy, float numberOfVertexPairs, int?indexOfTransformNode = null, bool rotationJoint1 = true, float vertexVerticalSpacingMultiplier = 1.0f)
            {
                var color              = new Vector4(0.8f, 0.8f, 0.8f, 1.0f);
                var positions          = new List <Vector3>();
                var indices            = new List <int>();
                var vertexHeightOffset = 0.2f * vertexVerticalSpacingMultiplier;

                float startHeight = -((numberOfVertexPairs - 1) * vertexHeightOffset / 2);
                float positionZ   = startHeight;
                var   index1      = 0;
                var   index2      = 1;
                var   index3      = 2;

                // Create positions and indices. Pattern for indices is as follows:
                // 0, 1, 2,
                // 2, 1, 3,
                // 2, 3, 4,
                // 4, 3, 5,
                // 4, 5, 6,
                // 6, 5, 7,
                // 6, 7, 8,
                // 8, 7, 9,
                // 8, 9, 10,
                // 10, 9, 11
                for (var vertexPairIndex = 0; vertexPairIndex < numberOfVertexPairs; vertexPairIndex++)
                {
                    positions.Add(new Vector3(-0.25f, 0.0f, positionZ));
                    positions.Add(new Vector3(0.25f, 0.0f, positionZ));
                    positionZ = positionZ + vertexHeightOffset;

                    if (vertexPairIndex > 0)
                    {
                        indices.Add(index1);
                        indices.Add(index2);
                        indices.Add(index3);
                        indices.Add(index1 + 2);
                        indices.Add(index2);
                        indices.Add(index3 + 1);
                        index1 += 2;
                        index2 += 2;
                        index3 += 2;
                    }
                }

                Matrix4x4  baseRotation            = Matrix4x4.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-90.0f), 0.0f);
                Quaternion jointRotation           = Quaternion.CreateFromRotationMatrix(Matrix4x4.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-30.0f), 0.0f));
                var        translationVector       = new Vector3(0.0f, 0.0f, vertexHeightOffset);
                var        translationVectorJoint0 = new Vector3(0.0f, startHeight, 0.0f);
                var        matrixJoint0            = Matrix4x4.CreateTranslation(new Vector3(0.0f, 0.0f, startHeight));

                Matrix4x4.Invert(matrixJoint0, out Matrix4x4 invertedJoint0);
                Matrix4x4 invertedTranslationMatrix = Matrix4x4.CreateTranslation(-translationVector);

                var jointHierarchyNodes = new List <Runtime.Node>();

                // Create the root node, since it is a special case.
                jointHierarchyNodes.Add(new Runtime.Node
                {
                    Name        = "joint0",
                    Rotation    = Quaternion.CreateFromRotationMatrix(baseRotation),
                    Translation = translationVectorJoint0,
                });
                // Create the child nodes in the joint hierarchy.
                for (int nodeIndex = 1, jointIndex = 1; nodeIndex < numberOfNodesInJointHierarchy; nodeIndex++)
                {
                    string name;
                    if (nodeIndex == indexOfTransformNode)
                    {
                        name = "transformNode";
                    }
                    else
                    {
                        name = $"joint{jointIndex}";
                        jointIndex++;
                    }

                    Quaternion rotationToUse = Quaternion.Identity;
                    if (nodeIndex == 1 && rotationJoint1)
                    {
                        rotationToUse = jointRotation;
                    }

                    jointHierarchyNodes.Add(new Runtime.Node
                    {
                        Name        = name,
                        Rotation    = rotationToUse,
                        Translation = translationVector,
                    });

                    // Add as a child of the previous node.
                    jointHierarchyNodes[nodeIndex - 1].Children = new[] { jointHierarchyNodes[nodeIndex] };
                }

                // Assembles the joints and inverseBindMatrices to create the skin.
                var joints = new List <Runtime.Node>
                {
                    jointHierarchyNodes[0]
                };
                var inverseBindMatrices = new List <Matrix4x4>
                {
                    invertedJoint0
                };

                for (int nodeIndex = 1, translationMultiplier = 1; nodeIndex < numberOfNodesInJointHierarchy; nodeIndex++)
                {
                    if (nodeIndex != indexOfTransformNode)
                    {
                        joints.Add(jointHierarchyNodes[nodeIndex]);
                        inverseBindMatrices.Add(Matrix4x4.CreateTranslation(new Vector3(0.0f, 0.0f, -positions[nodeIndex * 2].Z)));
                    }
                    translationMultiplier--;
                }

                // Assign weights.
                var weights = new List <List <Runtime.JointWeight> >();

                for (int i = 0; i < numberOfVertexPairs; i++)
                {
                    // If there is a transform node, use the joint from the node before it.
                    // Else if there are more vertex pairs than joints, then the last ones use the last joint.
                    // Otherwise, use the joint with the same index as the vertex pair.
                    int jointIndexToUse = i;
                    if (i == indexOfTransformNode)
                    {
                        jointIndexToUse = jointIndexToUse - 1;
                    }
                    else if (i > joints.Count - 1)
                    {
                        jointIndexToUse = joints.Count - 1;
                    }

                    weights.Add(new List <Runtime.JointWeight>
                    {
                        new Runtime.JointWeight
                        {
                            JointIndex = jointIndexToUse,
                            Weight     = 1,
                        },
                    });
                    weights.Add(new List <Runtime.JointWeight>
                    {
                        new Runtime.JointWeight
                        {
                            JointIndex = jointIndexToUse,
                            Weight     = 1,
                        },
                    });
                }

                var nodePlane = new Runtime.Node
                {
                    Name = "plane",
                    Skin = new Runtime.Skin
                    {
                        Name   = skinName,
                        Joints = joints,
                        InverseBindMatrices = inverseBindMatrices
                    },
                    Mesh = new Runtime.Mesh
                    {
                        MeshPrimitives = new[]
                        {
                            new Runtime.MeshPrimitive
                            {
                                VertexJointWeights = weights,
                                Positions          = positions,
                                Indices            = indices,
                                Material           = new Runtime.Material
                                {
                                    DoubleSided = true,
                                    MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness
                                    {
                                        BaseColorFactor = color
                                    }
                                }
                            }
                        }
                    },
                };

                return(new List <Runtime.Node>
                {
                    nodePlane,
                    jointHierarchyNodes[0]
                });
            }
Exemplo n.º 6
0
        public Animation_Skin(List <string> imageList)
        {
            UseFigure(imageList, "skinA");
            UseFigure(imageList, "skinB");
            UseFigure(imageList, "skinC");
            UseFigure(imageList, "skinD");
            UseFigure(imageList, "skinE");
            UseFigure(imageList, "skinF");
            var closeCamera   = new Manifest.Camera(new Vector3(0.5f, 0.0f, 0.6f));
            var distantCamera = new Manifest.Camera(new Vector3(1.5f, 0.0f, 1.0f));
            var skinBCamera   = new Manifest.Camera(new Vector3(0.5f, 0.6f, 1.1f));

            // There are no common properties in this model group that are reported in the readme.

            Model CreateModel(Action <List <Property>, List <Runtime.Animation>, List <Runtime.Node> > setProperties, Action <Model> setCamera, Action <glTFLoader.Schema.Gltf> postRuntimeChanges = null)
            {
                var properties = new List <Property>();
                var nodes      = new List <Runtime.Node>();
                var animations = new List <Runtime.Animation>();
                var animated   = true;

                // There are no common properties in this model group.

                // Apply the properties that are specific to this gltf.
                setProperties(properties, animations, nodes);

                // If no animations are used, null out that property.
                if (!animations.Any())
                {
                    animations = null;
                    animated   = false;
                }

                // Create the gltf object.
                var model = new Model
                {
                    Properties = properties,
                    GLTF       = CreateGLTF(() => new Runtime.Scene
                    {
                        Nodes = nodes
                    }, animations: animations),
                    Animated = animated,
                };

                if (postRuntimeChanges != null)
                {
                    model.PostRuntimeChanges = postRuntimeChanges;
                }

                setCamera(model);

                return(model);
            }

            void AddRotationAnimationChannel(List <Runtime.AnimationChannel> channelList, Runtime.Node targetNode, Quaternion pitchValue, Quaternion restValue)
            {
                channelList.Add(
                    new Runtime.AnimationChannel
                {
                    Target = new Runtime.AnimationChannelTarget
                    {
                        Node = targetNode,
                        Path = Runtime.AnimationChannelTarget.PathEnum.ROTATION,
                    },
                    Sampler = new Runtime.LinearAnimationSampler <Quaternion>
                              (
                        new[]
                    {
                        0.0f,
                        1.0f,
                        2.0f,
                    },
                        new[]
                    {
                        restValue,
                        pitchValue,
                        restValue,
                    }
                              )
                });
            }

            Runtime.Animation CreateFoldingAnimation(Runtime.Node jointRootNode, List <Runtime.AnimationChannel> channelList = null)
            {
                if (channelList == null)
                {
                    channelList = new List <Runtime.AnimationChannel>();
                }

                Runtime.Node nodeCheck  = jointRootNode;
                float        pitchValue = FloatMath.ToRadians(-90.0f);
                var          nodeList   = new List <Runtime.Node>
                {
                    jointRootNode,
                };

                while (nodeCheck.Children != null)
                {
                    foreach (var node in nodeCheck.Children)
                    {
                        nodeList.Add(node);
                    }
                    nodeCheck = nodeCheck.Children.First();
                }

                for (var nodeIndex = 1; nodeIndex < nodeList.Count(); nodeIndex++)
                {
                    float rotateValueModifier = 1.0f;
                    if (nodeIndex == 1)
                    {
                        rotateValueModifier = 0.5f;
                    }
                    else if (nodeIndex % 2 == 0)
                    {
                        rotateValueModifier = -1.0f;
                    }
                    AddRotationAnimationChannel(channelList, nodeList[nodeIndex], Quaternion.CreateFromYawPitchRoll(0.0f, pitchValue * rotateValueModifier, 0.0f), Quaternion.Identity);
                }
                return(new Runtime.Animation
                {
                    Channels = channelList
                });
            }

            Models = new List <Model>
            {
                CreateModel((properties, animations, nodes) =>
                {
                    foreach (Runtime.Node node in Nodes.CreateFoldingPlaneSkin("skinA", 2, 3))
                    {
                        nodes.Add(node);
                    }

                    properties.Add(new Property(PropertyName.Description, "`skinA`."));
                }, (model) => { model.Camera = closeCamera; }),
                CreateModel((properties, animations, nodes) =>
                {
                    foreach (Runtime.Node node in Nodes.CreateFoldingPlaneSkin("skinA", 2, 3))
                    {
                        nodes.Add(node);
                    }
                    animations.Add(CreateFoldingAnimation(nodes[1]));

                    properties.Add(new Property(PropertyName.Description, "`skinA` where `joint1` is animating with a rotation."));
                }, (model) => { model.Camera = closeCamera; }),
                CreateModel((properties, animations, nodes) =>
                {
                    var tempNodeList = Nodes.CreateFoldingPlaneSkin("skinA", 2, 3);

                    // Give the skin node a rotation
                    tempNodeList[0].Rotation = Quaternion.CreateFromYawPitchRoll((FloatMath.Pi / 4.0f), 0.0f, 0.0f);

                    // Create a new parent node and give it a rotation
                    tempNodeList[0] = new Runtime.Node
                    {
                        Name     = "jointParent",
                        Rotation = Quaternion.CreateFromYawPitchRoll((FloatMath.Pi / 4.0f), 0.0f, 0.0f),
                        Children = new List <Runtime.Node>
                        {
                            tempNodeList[0]
                        }
                    };

                    foreach (Runtime.Node node in tempNodeList)
                    {
                        nodes.Add(node);
                    }

                    properties.Add(new Property(PropertyName.Description, "`skinA` where the skinned node has a transform and a parent node with a transform. Both transforms should be ignored."));
                }, (model) => { model.Camera = closeCamera; }),
                // Removed Animation_Skin_03 due to a change in the spec that disallows this situation.
                // Left commented out because this will likely be re-added as a negative test in the future.
                // CreateModel((properties, animations, nodes) =>
                //{
                //     foreach (Runtime.Node node in Nodes.CreateFoldingPlaneSkin("skinA", 2, 3))
                //     {
                //         nodes.Add(node);
                //     }

                //     properties.Add(new Property(PropertyName.Description, "`skinA`. The skin joints are not referenced by the scene nodes."));
                // }, (model) => { model.Camera = closeCamera; }, (gltf) => {gltf.Scenes.First().Nodes = new []{0,};}),
                CreateModel((properties, animations, nodes) =>
                {
                    foreach (Runtime.Node node in Nodes.CreateFoldingPlaneSkin("skinA", 2, 3))
                    {
                        nodes.Add(node);
                    }
                    nodes[0].Skin.InverseBindMatrices = new[]
                    {
                        Matrix4x4.Identity,
                        Matrix4x4.Identity
                    };

                    properties.Add(new Property(PropertyName.Description, "`skinA` without inverse bind matrices."));
                }, (model) => { model.Camera = closeCamera; }),
                CreateModel((properties, animations, nodes) =>
                {
                    foreach (Runtime.Node node in Nodes.CreateFoldingPlaneSkin("skinA", 2, 3))
                    {
                        nodes.Add(node);
                    }
                    animations.Add(CreateFoldingAnimation(nodes[1]));

                    // Attach a node with a mesh to the end of the joint hierarchy
                    Runtime.Node nodeCheck = nodes[1];
                    while (nodeCheck.Children != null)
                    {
                        nodeCheck = nodeCheck.Children.First();
                    }

                    nodeCheck.Children = new List <Runtime.Node>
                    {
                        new Runtime.Node
                        {
                            Mesh = Mesh.CreateTriangle()
                        }
                    };

                    properties.Add(new Property(PropertyName.Description, "`skinA` where `joint1` is animated with a rotation and `joint1` has a triangle mesh attached to it."));
                }, (model) => { model.Camera = closeCamera; }),
                CreateModel((properties, animations, nodes) =>
                {
                    foreach (Runtime.Node node in Nodes.CreateFoldingPlaneSkin("skinA", 2, 3))
                    {
                        nodes.Add(node);
                    }

                    // Create a set of positions for the second mesh that are offset from the first mesh.
                    Runtime.MeshPrimitive originalMeshPrimitive = nodes[0].Mesh.MeshPrimitives.First();
                    var offsetPositions = new List <Vector3>();
                    foreach (Vector3 position in originalMeshPrimitive.Positions)
                    {
                        var offsetPosition = position;
                        offsetPosition.X  += 0.6f;
                        offsetPositions.Add(offsetPosition);
                    }

                    // Create a second mesh
                    nodes.Add(new Runtime.Node
                    {
                        Name = "plane2",
                        Skin = nodes[0].Skin,
                        Mesh = new Runtime.Mesh
                        {
                            MeshPrimitives = new[]
                            {
                                new Runtime.MeshPrimitive
                                {
                                    VertexJointWeights = originalMeshPrimitive.VertexJointWeights,
                                    Positions          = offsetPositions,
                                    Indices            = originalMeshPrimitive.Indices,
                                    Material           = new Runtime.Material
                                    {
                                        DoubleSided = true,
                                        MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness
                                        {
                                            BaseColorFactor = new Vector4(0.0f, 0.0f, 1.0f, 1.0f)
                                        }
                                    }
                                }
                            }
                        }
                    });

                    properties.Add(new Property(PropertyName.Description, "`skinA` where there are two meshes sharing a single skin."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, animations, nodes) =>
                {
                    foreach (Runtime.Node node in Nodes.CreateFoldingPlaneSkin("skinA", 2, 3))
                    {
                        nodes.Add(node);
                    }

                    // Make joint1 a root joint
                    nodes.Add(nodes[1].Children.First());
                    nodes[1].Children = null;

                    // Compensate for no longer inheriting from joint0
                    nodes[2].Rotation    = Quaternion.Multiply((Quaternion)nodes[2].Rotation, (Quaternion)nodes[1].Rotation);
                    nodes[2].Translation = null;
                    nodes[0].Skin.InverseBindMatrices = new[]
                    {
                        nodes[0].Skin.InverseBindMatrices.First(),
                        Matrix4x4.Identity
                    };

                    properties.Add(new Property(PropertyName.Description, "`skinA` where `joint1` is a root node and not a child of `joint0`."));
                }, (model) => { model.Camera = closeCamera; }),
                CreateModel((properties, animations, nodes) =>
                {
                    foreach (Runtime.Node node in Nodes.CreatePlaneWithSkinB())
                    {
                        nodes.Add(node);
                    }

                    // Animate the joints
                    Runtime.Node nodeJoint0 = nodes[1];
                    Runtime.Node nodeJoint1 = nodeJoint0.Children.First();
                    var channelList         = new List <Runtime.AnimationChannel>();
                    float rotationValue     = FloatMath.ToRadians(-15.0f);
                    AddRotationAnimationChannel(channelList, nodeJoint1, Quaternion.CreateFromYawPitchRoll(0.0f, 0.0f, rotationValue), Quaternion.CreateFromYawPitchRoll(0.0f, 0.0f, 0.0f));
                    animations.Add(new Runtime.Animation
                    {
                        Channels = channelList
                    });

                    properties.Add(new Property(PropertyName.Description, "`skinB` which is made up of two skins. `joint1` is referenced by both skins and is animating with a rotation."));
                }, (model) => { model.Camera = skinBCamera; }),
                CreateModel((properties, animations, nodes) =>
                {
                    foreach (Runtime.Node node in Nodes.CreateFoldingPlaneSkin("skinC", 5, 5))
                    {
                        nodes.Add(node);
                    }

                    // Rotate each joint node, except the root which already has the desired rotation
                    Runtime.Node nodeCheck = nodes[1].Children.First();
                    float rotationRadian   = FloatMath.ToRadians(-10.0f);
                    Quaternion rotation    = Quaternion.CreateFromYawPitchRoll(0.0f, rotationRadian, 0.0f);
                    nodeCheck.Rotation     = rotation;
                    while (nodeCheck.Children != null)
                    {
                        foreach (var node in nodeCheck.Children)
                        {
                            node.Rotation = rotation;
                        }
                        nodeCheck = nodeCheck.Children.First();
                    }

                    // Rebuild the inverseBindMatrix for each joint (except the root) to work with the new rotation
                    List <Matrix4x4> inverseBindMatrixList = (List <Matrix4x4>)nodes[0].Skin.InverseBindMatrices;
                    for (var i = 1; i < inverseBindMatrixList.Count; i++)
                    {
                        var translationInverseBindMatrix = inverseBindMatrixList[i];
                        Matrix4x4.Invert(Matrix4x4.CreateRotationX(rotationRadian * (i + 1)), out Matrix4x4 invertedRotation);
                        inverseBindMatrixList[i] = Matrix4x4.Multiply(translationInverseBindMatrix, invertedRotation);
                    }

                    properties.Add(new Property(PropertyName.Description, "`skinC` where all of the joints have a local rotation of -10 degrees, except the root which is rotated -90 degrees."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, animations, nodes) =>
                {
                    foreach (Runtime.Node node in Nodes.CreateFoldingPlaneSkin("skinD", 5, 6, 3, false))
                    {
                        nodes.Add(node);
                    }
                    animations.Add(CreateFoldingAnimation(nodes[1]));

                    // Remove animation for the transform node
                    animations[0].Channels = new List <Runtime.AnimationChannel>
                    {
                        animations[0].Channels.First(),
                        animations[0].Channels.ElementAt(1),
                        animations[0].Channels.ElementAt(3),
                    };

                    // Add the mesh to the transform node
                    nodes[1].Children.First().Children.First().Children.First().Mesh = Mesh.CreateTriangle();

                    properties.Add(new Property(PropertyName.Description, "`skinD` where each joint is animating with a rotation. There is a transform node in the joint hierarchy that is not a joint. That node has a mesh attached to it in order to show its location."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, animations, nodes) =>
                {
                    foreach (Runtime.Node node in Nodes.CreatePlaneWithSkinE())
                    {
                        nodes.Add(node);
                    }

                    properties.Add(new Property(PropertyName.Description, "`skinE`."));
                }, (model) => { model.Camera = distantCamera; }),
                // Removing this model for now, since no viewer currently supports models that have >4 jointweights per vertex.
                //CreateModel((properties, animations, nodes) =>
                //{
                //    foreach (Runtime.Node node in Nodes.CreateFoldingPlaneSkin("skinF", 8, 9, vertexVerticalSpacingMultiplier: 0.5f))
                //    {
                //        nodes.Add(node);
                //    }

                //    // Rotate each joint node, except the root which already has the desired rotation
                //    Runtime.Node nodeCheck = nodes[1].Children.First();
                //    float rotationRadian = FloatMath.ConvertDegreesToRadians(-10.0f);
                //    Quaternion rotationQuaternion = Quaternion.CreateFromYawPitchRoll(0.0f, rotationRadian, 0.0f);
                //    nodeCheck.Rotation = rotationQuaternion;
                //    while (nodeCheck.Children != null)
                //    {
                //        foreach (Runtime.Node node in nodeCheck.Children)
                //        {
                //            node.Rotation = rotationQuaternion;
                //        }
                //        nodeCheck = nodeCheck.Children.First();
                //    }

                //    // Rebuild the inverseBindMatrix for each joint (except the root) to work with the new rotation
                //    var skinJointList = (List<Runtime.SkinJoint>)nodes[0].Skin.SkinJoints;
                //    for (var skinJointIndex = 1; skinJointIndex < skinJointList.Count(); skinJointIndex++)
                //    {
                //        Matrix4x4 translationInverseBindMatrix = skinJointList.ElementAt(skinJointIndex).InverseBindMatrix;
                //        Matrix4x4.Invert(Matrix4x4.CreateRotationX(rotationRadian * (skinJointIndex + 1)) , out Matrix4x4 invertedRotation);
                //        skinJointList.ElementAt(skinJointIndex).InverseBindMatrix = Matrix4x4.Multiply(translationInverseBindMatrix, invertedRotation);
                //    }

                //    // Rebuild weights to include every joint instead of just the ones with a weight > 0
                //    var weightList = (List<List<Runtime.JointWeight>>)nodes[0].Mesh.MeshPrimitives.First().VertexJointWeights;
                //    for (var weightIndex = 0; weightIndex < weightList.Count(); weightIndex++)
                //    {
                //        var jointWeight = new List<Runtime.JointWeight>();

                //        for (var skinJointIndex = 0; skinJointIndex < skinJointList.Count; skinJointIndex++)
                //        {
                //            int weightToUse = 0;
                //            // Set the weight to 1 if the skinJoint is at the same level as the vertex.
                //            // Or Set the weight to 1 if the vertex is further out than the last skinjoint and the last skinjoint is being set.
                //            if (skinJointIndex == (weightIndex / 2) || (((weightIndex / 2) > skinJointList.Count - 1) && (skinJointIndex == skinJointList.Count - 1)) )
                //            {
                //                weightToUse = 1;
                //            }

                //            jointWeight.Add(new Runtime.JointWeight
                //            {
                //                Joint = skinJointList[skinJointIndex],
                //                Weight = weightToUse,
                //            });
                //        }

                //        weightList[weightIndex] = jointWeight;
                //    }

                //    properties.Add(new Property(PropertyName.Description, "`skinF`. Each vertex has weights for more than four joints."));
                //}, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, animations, nodes) =>
                {
                    var skinA1 = Nodes.CreateFoldingPlaneSkin("skinA", 2, 3);
                    var skinA2 = Nodes.CreateFoldingPlaneSkin("skinA", 2, 3);

                    // Set the same mesh on both nodes.
                    skinA2[0].Mesh = skinA1[0].Mesh;

                    // Offset one of the models so they aren't overlapping.
                    Vector3 translation   = skinA2[1].Translation.Value;
                    skinA2[1].Translation = new Vector3(translation.X + 0.6f, translation.Y, translation.Z);

                    foreach (Runtime.Node node in skinA1)
                    {
                        nodes.Add(node);
                    }

                    foreach (Runtime.Node node in skinA2)
                    {
                        nodes.Add(node);
                    }

                    properties.Add(new Property(PropertyName.Description, "Two instances of `skinA` sharing a mesh but with separate skins."));
                }, (model) => { model.Camera = distantCamera; }),
            };

            GenerateUsedPropertiesList();
        }
Exemplo n.º 7
0
            private static List <Runtime.Node> CreateJointsAndWeightsForMultipleRoots(Runtime.Node nodePlane)
            {
                Matrix4x4 baseRotation            = Matrix4x4.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-90.0f), 0.0f);
                Matrix4x4 jointRotation           = Matrix4x4.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-15.0f), 0.0f);
                var       translationVectorJoint3 = new Vector3(0.0f, 0.25f, 0.0f);
                var       translationVectorJoint2 = new Vector3(0.0f, 0.0f, 0.25f);
                var       translationVectorJoint1 = new Vector3(0.1875f, -0.25f, 0.0f);
                var       translationVectorJoint0 = new Vector3(-0.1875f, -0.25f, 0.0f);
                Matrix4x4 invertedJoint3          = Matrix4x4.CreateTranslation(-translationVectorJoint3);
                Matrix4x4 invertedJoint2          = Matrix4x4.CreateTranslation(-translationVectorJoint2);
                Matrix4x4 invertedJoint1          = Matrix4x4.CreateTranslation(new Vector3(-0.1875f, 0.0f, 0.25f));
                Matrix4x4 invertedJoint0          = Matrix4x4.CreateTranslation(new Vector3(0.1875f, 0.0f, 0.25f));

                var nodeJoint3 = new Runtime.Node
                {
                    Name        = "joint3",
                    Rotation    = Quaternion.CreateFromRotationMatrix(jointRotation),
                    Translation = translationVectorJoint3,
                };
                var nodeJoint2 = new Runtime.Node
                {
                    Name        = "joint2",
                    Rotation    = Quaternion.CreateFromRotationMatrix(jointRotation),
                    Translation = translationVectorJoint2,
                    Children    = new[]
                    {
                        nodeJoint3
                    }
                };
                var nodeJoint1 = new Runtime.Node
                {
                    Name        = "joint1",
                    Rotation    = Quaternion.CreateFromRotationMatrix(baseRotation),
                    Translation = translationVectorJoint1,
                    Children    = new[]
                    {
                        nodeJoint2
                    }
                };
                var nodeJoint0 = new Runtime.Node
                {
                    Name        = "joint0",
                    Rotation    = Quaternion.CreateFromRotationMatrix(baseRotation),
                    Translation = translationVectorJoint0,
                    Children    = new[]
                    {
                        nodeJoint2
                    }
                };

                nodePlane.Skin = new Runtime.Skin
                {
                    Name   = "skinE",
                    Joints = new[]
                    {
                        nodeJoint0,
                        nodeJoint1,
                        nodeJoint2,
                        nodeJoint3
                    },
                    InverseBindMatrices = Runtime.Data.Create(new[]
                    {
                        invertedJoint0,
                        invertedJoint1,
                        invertedJoint2,
                        invertedJoint3
                    }),
                };

                // Top four vertexes of each arm have a weight for the relevant joint. Otherwise the vertex has a weight from the root.
                var joints  = new List <Runtime.JointVector>();
                var weights = new List <Runtime.WeightVector>();

                // Base of trunk
                for (var vertexIndex = 0; vertexIndex < 2; vertexIndex++)
                {
                    joints.Add(new Runtime.JointVector(0, 1, 2, 3));
                    weights.Add(new Runtime.WeightVector(0.0f, 0.0f, 0.0f, 1.0f));
                }
                // Top of trunk
                for (var vertexIndex = 0; vertexIndex < 3; vertexIndex++)
                {
                    joints.Add(new Runtime.JointVector(0, 1, 2, 3));
                    weights.Add(new Runtime.WeightVector(0.0f, 0.0f, 1.0f, 0.0f));
                }
                // Left arm
                for (var vertexIndex = 0; vertexIndex < 4; vertexIndex++)
                {
                    joints.Add(new Runtime.JointVector(0, 1, 2, 3));
                    weights.Add(new Runtime.WeightVector(1.0f, 0.0f, 0.0f, 1.0f));
                }
                // Right arm
                for (var vertexIndex = 0; vertexIndex < 4; vertexIndex++)
                {
                    joints.Add(new Runtime.JointVector(0, 1, 2, 3));
                    weights.Add(new Runtime.WeightVector(0.0f, 1.0f, 0.0f, 0.0f));
                }
                nodePlane.Mesh.MeshPrimitives.First().Joints  = Runtime.Data.Create(joints, Runtime.DataType.UnsignedShort);
                nodePlane.Mesh.MeshPrimitives.First().Weights = Runtime.Data.Create(weights);

                return(new List <Runtime.Node>
                {
                    nodePlane,
                    nodeJoint0,
                    nodeJoint1
                });
            }
            public static List <Runtime.Node> CreatePlaneWithSkinB()
            {
                var colorInner = new Vector4(0.8f, 0.8f, 0.8f, 1.0f);
                var colorOuter = new Vector4(0.0f, 0.0f, 1.0f, 1.0f);

                Matrix4x4 rotation = Matrix4x4.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(90.0f), 0.0f);
                var       translationVectorJoint1 = new Vector3(0.0f, 0.0f, -0.6f);
                var       translationVectorJoint0 = new Vector3(0.0f, 0.0f, 0.3f);
                Matrix4x4 matrixJoint1            = Matrix4x4.CreateTranslation(translationVectorJoint1);
                Matrix4x4 matrixJoint0            = Matrix4x4.CreateTranslation(translationVectorJoint0);

                matrixJoint1 = Matrix4x4.Multiply(matrixJoint0, matrixJoint1);
                Matrix4x4.Invert(matrixJoint1, out Matrix4x4 invertedJoint1);
                Matrix4x4.Invert(matrixJoint0, out Matrix4x4 invertedJoint0);

                var nodeJoint1 = new Runtime.Node
                {
                    Name        = "joint1",
                    Translation = translationVectorJoint1,
                };
                var nodeJoint0 = new Runtime.Node
                {
                    Name        = "joint0",
                    Rotation    = Quaternion.CreateFromRotationMatrix(rotation),
                    Translation = new Vector3(0.0f, -0.3f, 0.0f),
                    Children    = new[]
                    {
                        nodeJoint1
                    },
                };

                var skinJoints = new[]
                {
                    nodeJoint0,
                    nodeJoint1
                };
                var inverseBindMatrices = Runtime.Data.Create(new List <Matrix4x4>
                {
                    invertedJoint0,
                    invertedJoint1
                });
                var innerSkin = new Runtime.Skin
                {
                    Joints = skinJoints,
                    InverseBindMatrices = inverseBindMatrices
                };
                var outerSkin = new Runtime.Skin
                {
                    Joints = skinJoints,
                    InverseBindMatrices = inverseBindMatrices
                };

                var nodeInnerPrism = new Runtime.Node
                {
                    Name = "innerPrism",
                    Skin = innerSkin,
                    Mesh = Mesh.CreatePrism(colorInner),
                };

                var nodeOuterPrism = new Runtime.Node
                {
                    Name = "outerPrism",
                    Skin = outerSkin,
                    Mesh = Mesh.CreatePrism(colorOuter, scale: new Vector3(1.6f, 1.6f, 0.3f)),
                };

                var joints  = new List <Runtime.JointVector>();
                var weights = new List <Runtime.WeightVector>();

                for (var i = 0; i < 3; i++)
                {
                    joints.Add(new Runtime.JointVector(0, 1));
                    weights.Add(new Runtime.WeightVector(1.0f, 0.0f));
                }
                for (var i = 0; i < 3; i++)
                {
                    joints.Add(new Runtime.JointVector(0, 1));
                    weights.Add(new Runtime.WeightVector(0.0f, 1.0f));
                }
                nodeInnerPrism.Mesh.MeshPrimitives.First().Joints  = Runtime.Data.Create(joints, Runtime.DataType.UnsignedShort);
                nodeInnerPrism.Mesh.MeshPrimitives.First().Weights = Runtime.Data.Create(weights);
                nodeOuterPrism.Mesh.MeshPrimitives.First().Joints  = Runtime.Data.Create(joints, Runtime.DataType.UnsignedShort);
                nodeOuterPrism.Mesh.MeshPrimitives.First().Weights = Runtime.Data.Create(weights);

                return(new List <Runtime.Node>
                {
                    nodeInnerPrism,
                    nodeJoint0,
                    nodeOuterPrism
                });
            }
Exemplo n.º 9
0
        public Animation_Node(List <string> imageList)
        {
            Runtime.Image baseColorTextureImage = UseTexture(imageList, "BaseColor_Cube");

            // There are no common properties in this model group that are reported in the readme.

            Model CreateModel(Action <List <Property>, List <Runtime.AnimationChannel>, Runtime.Node> setProperties)
            {
                var properties        = new List <Property>();
                var cubeMeshPrimitive = MeshPrimitive.CreateCube();

                // Apply the common properties to the gltf.
                cubeMeshPrimitive.Material = new Runtime.Material
                {
                    MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness
                    {
                        BaseColorTexture = new Runtime.Texture {
                            Source = baseColorTextureImage
                        },
                    },
                };
                var channels = new List <Runtime.AnimationChannel>
                {
                    new Runtime.AnimationChannel()
                };
                var node = new Runtime.Node();

                // Apply the properties that are specific to this gltf.
                setProperties(properties, channels, node);

                // Create the gltf object.
                node.Mesh = new Runtime.Mesh
                {
                    MeshPrimitives = new[]
                    {
                        cubeMeshPrimitive
                    }
                };
                Runtime.GLTF gltf = CreateGLTF(() => new Runtime.Scene()
                {
                    Nodes = new[]
                    {
                        node
                    },
                });
                gltf.Animations = new[]
                {
                    new Runtime.Animation
                    {
                        Channels = channels
                    }
                };
                return(new Model
                {
                    Properties = properties,
                    GLTF = gltf,
                    Animated = true,
                });
            }

            void SetTranslationChannelTarget(List <Property> properties, Runtime.AnimationChannel channel, Runtime.Node node)
            {
                channel.Target = new Runtime.AnimationChannelTarget
                {
                    Node = node,
                    Path = Runtime.AnimationChannelTarget.PathEnum.TRANSLATION,
                };
                properties.Add(new Property(PropertyName.Target, "Translation"));
            }

            void SetRotationChannelTarget(List <Property> properties, Runtime.AnimationChannel channel, Runtime.Node node)
            {
                channel.Target = new Runtime.AnimationChannelTarget
                {
                    Node = node,
                    Path = Runtime.AnimationChannelTarget.PathEnum.ROTATION,
                };
                properties.Add(new Property(PropertyName.Target, "Rotation"));
            }

            void SetScaleChannelTarget(List <Property> properties, Runtime.AnimationChannel channel, Runtime.Node node)
            {
                channel.Target = new Runtime.AnimationChannelTarget
                {
                    Node = node,
                    Path = Runtime.AnimationChannelTarget.PathEnum.SCALE,
                };
                properties.Add(new Property(PropertyName.Target, "Scale"));
            }

            void SetLinearSamplerForTranslation(List <Property> properties, Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.LinearAnimationSampler <Vector3>
                                  (
                    new[]
                {
                    0.0f,
                    1.0f,
                    2.0f,
                },
                    new[]
                {
                    new Vector3(-0.1f, 0.0f, 0.0f),
                    new Vector3(0.1f, 0.0f, 0.0f),
                    new Vector3(-0.1f, 0.0f, 0.0f),
                }
                                  );

                properties.Add(new Property(PropertyName.Interpolation, "Linear"));
            }

            void SetLinearSamplerForScale(List <Property> properties, Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.LinearAnimationSampler <Vector3>
                                  (
                    new[]
                {
                    0.0f,
                    1.0f,
                    2.0f,
                },
                    new[]
                {
                    new Vector3(0.8f, 0.8f, 0.8f),
                    new Vector3(1.2f, 1.2f, 1.2f),
                    new Vector3(0.8f, 0.8f, 0.8f),
                }
                                  );

                properties.Add(new Property(PropertyName.Interpolation, "Linear"));
            }

            void SetLinearSamplerForRotation(List <Property> properties, Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.LinearAnimationSampler <Quaternion>
                                  (
                    new[]
                {
                    0.0f,
                    1.0f,
                    2.0f,
                    3.0f,
                    4.0f,
                },
                    new[]
                {
                    Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(90.0f), 0.0f, 0.0f),
                    Quaternion.Identity,
                    Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(-90.0f), 0.0f, 0.0f),
                    Quaternion.Identity,
                    Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(90.0f), 0.0f, 0.0f),
                }
                                  );

                properties.Add(new Property(PropertyName.Interpolation, "Linear"));
            }

            void SetStepSamplerForTranslation(List <Property> properties, Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.StepAnimationSampler <Vector3>
                                  (
                    new[]
                {
                    0.0f,
                    1.0f,
                    2.0f,
                    3.0f,
                    4.0f,
                },
                    new[]
                {
                    new Vector3(-0.1f, 0.0f, 0.0f),
                    new Vector3(0.0f, 0.0f, 0.0f),
                    new Vector3(0.1f, 0.0f, 0.0f),
                    new Vector3(0.0f, 0.0f, 0.0f),
                    new Vector3(-0.1f, 0.0f, 0.0f),
                }
                                  );

                properties.Add(new Property(PropertyName.Interpolation, "Step"));
            }

            void SetCubicSplineSamplerForTranslation(List <Property> properties, Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.CubicSplineAnimationSampler <Vector3>
                                  (
                    new[]
                {
                    0.0f,
                    1.0f,
                    2.0f,
                },
                    new[]
                {
                    new Runtime.CubicSplineAnimationSampler <Vector3> .Key
                    {
                        InTangent  = new Vector3(0.0f, 0.0f, 0.0f),
                        Value      = new Vector3(-0.1f, 0.0f, 0.0f),
                        OutTangent = new Vector3(0.0f, 0.0f, 0.0f)
                    },
                    new Runtime.CubicSplineAnimationSampler <Vector3> .Key
                    {
                        InTangent  = new Vector3(0.0f, 0.0f, 0.0f),
                        Value      = new Vector3(0.1f, 0.0f, 0.0f),
                        OutTangent = new Vector3(0.0f, -0.3f, 0.0f)
                    },
                    new Runtime.CubicSplineAnimationSampler <Vector3> .Key
                    {
                        InTangent  = new Vector3(0.0f, 0.0f, 0.0f),
                        Value      = new Vector3(-0.1f, 0.0f, 0.0f),
                        OutTangent = new Vector3(0.0f, 0.0f, 0.0f)
                    }
                }
                                  );

                properties.Add(new Property(PropertyName.Interpolation, "Cubic Spline"));
            }

            void CreateCubicSplineSamplerForRotation(List <Property> properties, Runtime.AnimationChannel channel)
            {
                channel.Sampler = new Runtime.CubicSplineAnimationSampler <Quaternion>
                                  (
                    new[]
                {
                    0.0f,
                    1.0f,
                    2.0f,
                    3.0f,
                    4.0f,
                },
                    new[]
                {
                    new Runtime.CubicSplineAnimationSampler <Quaternion> .Key
                    {
                        InTangent  = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f),
                        Value      = Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(90.0f), 0.0f, 0.0f),
                        OutTangent = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f)
                    },
                    new Runtime.CubicSplineAnimationSampler <Quaternion> .Key
                    {
                        InTangent  = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f),
                        Value      = Quaternion.Identity,
                        OutTangent = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f)
                    },
                    new Runtime.CubicSplineAnimationSampler <Quaternion> .Key
                    {
                        InTangent  = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f),
                        Value      = Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(-90.0f), 0.0f, 0.0f),
                        OutTangent = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f)
                    },
                    new Runtime.CubicSplineAnimationSampler <Quaternion> .Key
                    {
                        InTangent  = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f),
                        Value      = Quaternion.Identity,
                        OutTangent = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f)
                    },
                    new Runtime.CubicSplineAnimationSampler <Quaternion> .Key
                    {
                        InTangent  = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f),
                        Value      = Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(90.0f), 0.0f, 0.0f),
                        OutTangent = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f)
                    },
                }
                                  );
                properties.Add(new Property(PropertyName.Interpolation, "Cubic Spline"));
            }

            Models = new List <Model>
            {
                CreateModel((properties, channels, node) =>
                {
                    SetTranslationChannelTarget(properties, channels[0], node);
                    SetLinearSamplerForTranslation(properties, channels[0]);
                }),
                CreateModel((properties, channels, node) =>
                {
                    SetRotationChannelTarget(properties, channels[0], node);
                    SetLinearSamplerForRotation(properties, channels[0]);
                }),
                CreateModel((properties, channels, node) =>
                {
                    SetScaleChannelTarget(properties, channels[0], node);
                    SetLinearSamplerForScale(properties, channels[0]);
                }),
                CreateModel((properties, channels, node) =>
                {
                    SetTranslationChannelTarget(properties, channels[0], node);
                    SetStepSamplerForTranslation(properties, channels[0]);
                }),
                CreateModel((properties, channels, node) =>
                {
                    SetTranslationChannelTarget(properties, channels[0], node);
                    SetCubicSplineSamplerForTranslation(properties, channels[0]);
                }),
                CreateModel((properties, channels, node) =>
                {
                    SetRotationChannelTarget(properties, channels[0], node);
                    CreateCubicSplineSamplerForRotation(properties, channels[0]);
                }),
            };

            GenerateUsedPropertiesList();
        }
Exemplo n.º 10
0
        public Instancing(List <string> imageList)
        {
            Runtime.Image baseColorTextureImageA    = UseTexture(imageList, "BaseColor_A");
            Runtime.Image baseColorTextureImageB    = UseTexture(imageList, "BaseColor_B");
            Runtime.Image baseColorTextureImageCube = UseTexture(imageList, "BaseColor_Cube");
            var           distantCamera             = new Manifest.Camera(new Vector3(0.0f, 0.0f, 2.7f));

            // There are no common properties in this model group that are reported in the readme.

            Model CreateModel(Action <List <Property>, List <Runtime.Node>, List <Runtime.Animation> > setProperties, Action <Model> setCamera)
            {
                var properties = new List <Property>();
                var animations = new List <Runtime.Animation>();
                var animated   = true;
                var nodes      = new List <Runtime.Node>();

                // Apply the properties that are specific to this gltf.
                setProperties(properties, nodes, animations);

                // If no animations are used, null out that property.
                if (!animations.Any())
                {
                    animations = null;
                    animated   = false;
                }

                // Create the gltf object.
                var model = new Model
                {
                    Properties = properties,
                    GLTF       = CreateGLTF(() => new Runtime.Scene {
                        Nodes = nodes
                    }, animations: animations),
                    Animated = animated,
                };

                setCamera(model);

                return(model);
            }

            var SamplerInputLinear = new[]
            {
                0.0f,
                1.0f,
                2.0f,
                3.0f,
                4.0f,
            };

            var SamplerInputCurve = new[]
            {
                0.0f,
                0.5f,
                1.0f,
                2.0f,
                4.0f,
            };

            var SamplerOutput = new[]
            {
                Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(90.0f), 0.0f),
                Quaternion.Identity,
                Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-90.0f), 0.0f),
                Quaternion.Identity,
                Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(90.0f), 0.0f),
            };

            var SamplerOutputReverse = new[]
            {
                Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-90.0f), 0.0f),
                Quaternion.Identity,
                Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(90.0f), 0.0f),
                Quaternion.Identity,
                Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-90.0f), 0.0f),
            };

            Runtime.Texture CreateTexture(Runtime.Image image)
            {
                return(new Runtime.Texture {
                    Source = image
                });
            }

            Runtime.Material CreateMaterial(Runtime.Texture texture)
            {
                return(new Runtime.Material
                {
                    MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness
                    {
                        BaseColorTexture = texture
                    }
                });
            }

            void AddMeshPrimitivesToSingleNode(List <Runtime.Node> nodes, List <Runtime.MeshPrimitive> meshPrimitives)
            {
                // If there are multiple mesh primitives, offset their position so they don't overlap.
                if (meshPrimitives.Count > 1)
                {
                    meshPrimitives[0].Positions = meshPrimitives[0].Positions.Select(position => { return(new Vector3(position.X - 0.6f, position.Y, position.Z)); });
                    meshPrimitives[1].Positions = meshPrimitives[1].Positions.Select(position => { return(new Vector3(position.X + 0.6f, position.Y, position.Z)); });
                }

                nodes.Add(
                    new Runtime.Node
                {
                    Mesh = new Runtime.Mesh
                    {
                        MeshPrimitives = meshPrimitives
                    }
                }
                    );
            }

            void AddMeshPrimitivesToMultipleNodes(List <Runtime.Node> nodes, Runtime.MeshPrimitive meshPrimitives0, Runtime.MeshPrimitive meshPrimitives1)
            {
                nodes.AddRange(new[]
                {
                    new Runtime.Node
                    {
                        Translation = new Vector3(-0.6f, 0.0f, 0.0f),
                        Mesh        = new Runtime.Mesh
                        {
                            MeshPrimitives = new List <Runtime.MeshPrimitive>
                            {
                                meshPrimitives0
                            }
                        }
                    },
                    new Runtime.Node
                    {
                        Translation = new Vector3(0.6f, 0.0f, 0.0f),
                        Mesh        = new Runtime.Mesh
                        {
                            MeshPrimitives = new List <Runtime.MeshPrimitive>
                            {
                                meshPrimitives1
                            }
                        }
                    }
                }
                               );
            }

            void AddAnimation(List <Runtime.Animation> animations, List <Runtime.Node> nodes, Runtime.AnimationSampler sampler0, Runtime.AnimationSampler sampler1, bool samplerInstanced)
            {
                animations.Add(new Runtime.Animation
                {
                    Channels = new List <Runtime.AnimationChannel>
                    {
                        new Runtime.AnimationChannel
                        {
                            Target = new Runtime.AnimationChannelTarget
                            {
                                Node = nodes[0],
                                Path = ROTATION,
                            },
                            Sampler = sampler0
                        },
                        new Runtime.AnimationChannel
                        {
                            Target = new Runtime.AnimationChannelTarget
                            {
                                Node = nodes[1],
                                Path = ROTATION,
                            },
                            Sampler = sampler1
                        },
                    }
                });
            }

            Models = new List <Model>
            {
                CreateModel((properties, nodes, animations) =>
                {
                    var meshPrimitives = new List <Runtime.MeshPrimitive>
                    {
                        MeshPrimitive.CreateSinglePlane(includeTextureCoords: false),
                        MeshPrimitive.CreateSinglePlane(includeTextureCoords: false)
                    };

                    foreach (Runtime.MeshPrimitive meshPrimitive in meshPrimitives)
                    {
                        // This non-standard set of texture coordinates is larger than the texture but not an exact multiple, so it allows texture sampler settings to be visible.
                        meshPrimitive.TextureCoordSets = new List <List <Vector2> >
                        {
                            new List <Vector2>
                            {
                                new Vector2(1.3f, 1.3f),
                                new Vector2(-0.3f, 1.3f),
                                new Vector2(-0.3f, -0.3f),
                                new Vector2(1.3f, -0.3f),
                            }
                        };
                    }

                    meshPrimitives[0].Material = CreateMaterial(CreateTexture(baseColorTextureImageA));
                    meshPrimitives[1].Material = CreateMaterial(CreateTexture(baseColorTextureImageA));

                    meshPrimitives[0].Material.MetallicRoughnessMaterial.BaseColorTexture.Sampler = new Runtime.Sampler
                    {
                        WrapT = WrapTEnum.CLAMP_TO_EDGE,
                        WrapS = WrapSEnum.CLAMP_TO_EDGE
                    };
                    meshPrimitives[1].Material.MetallicRoughnessMaterial.BaseColorTexture.Sampler = new Runtime.Sampler
                    {
                        WrapT = WrapTEnum.MIRRORED_REPEAT,
                        WrapS = WrapSEnum.MIRRORED_REPEAT
                    };

                    AddMeshPrimitivesToSingleNode(nodes, meshPrimitives);

                    properties.Add(new Property(PropertyName.Description, "Two textures using the same image as their source."));
                    properties.Add(new Property(PropertyName.Difference, "The texture sampler `WrapT` and `WrapS` are set to `CLAMP_TO_EDGE` for one and `MIRRORED_REPEAT` for the other."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, nodes, animations) =>
                {
                    var meshPrimitives = new List <Runtime.MeshPrimitive>
                    {
                        MeshPrimitive.CreateSinglePlane(includeTextureCoords: false),
                        MeshPrimitive.CreateSinglePlane(includeTextureCoords: false)
                    };

                    meshPrimitives[0].Material = CreateMaterial(CreateTexture(baseColorTextureImageA));
                    meshPrimitives[1].Material = CreateMaterial(CreateTexture(baseColorTextureImageB));

                    var sampler = new Runtime.Sampler
                    {
                        WrapT = WrapTEnum.CLAMP_TO_EDGE,
                        WrapS = WrapSEnum.CLAMP_TO_EDGE
                    };
                    foreach (Runtime.MeshPrimitive meshPrimitive in meshPrimitives)
                    {
                        meshPrimitive.Material.MetallicRoughnessMaterial.BaseColorTexture.Sampler = sampler;
                        // This non-standard set of texture coordinates is larger than the texture but not an exact multiple, so it allows texture sampler settings to be visible.
                        meshPrimitive.TextureCoordSets = new List <List <Vector2> >
                        {
                            new List <Vector2>
                            {
                                new Vector2(1.3f, 1.3f),
                                new Vector2(-0.3f, 1.3f),
                                new Vector2(-0.3f, -0.3f),
                                new Vector2(1.3f, -0.3f),
                            }
                        };
                    }

                    AddMeshPrimitivesToSingleNode(nodes, meshPrimitives);

                    properties.Add(new Property(PropertyName.Description, "Two textures using the same sampler."));
                    properties.Add(new Property(PropertyName.Difference, "One texture uses image A while the other uses image B."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, nodes, animations) =>
                {
                    var meshPrimitives = new List <Runtime.MeshPrimitive>
                    {
                        MeshPrimitive.CreateSinglePlane(),
                        MeshPrimitive.CreateSinglePlane()
                    };

                    var texture = CreateTexture(baseColorTextureImageA);
                    foreach (Runtime.MeshPrimitive meshPrimitive in meshPrimitives)
                    {
                        meshPrimitive.Material = CreateMaterial(texture);
                    }
                    meshPrimitives[0].Material.MetallicRoughnessMaterial.BaseColorTexture = meshPrimitives[1].Material.MetallicRoughnessMaterial.BaseColorTexture;
                    meshPrimitives[1].Material.MetallicRoughnessMaterial.BaseColorFactor  = new Vector4(0.5f, 0.5f, 1.0f, 1.0f);

                    AddMeshPrimitivesToSingleNode(nodes, meshPrimitives);

                    properties.Add(new Property(PropertyName.Description, "Two textures using the same source image."));
                    properties.Add(new Property(PropertyName.Difference, "One material does not have a baseColorFactor and the other has a blue baseColorFactor."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, nodes, animations) =>
                {
                    var meshPrimitives = new List <Runtime.MeshPrimitive>
                    {
                        MeshPrimitive.CreateSinglePlane(),
                        MeshPrimitive.CreateSinglePlane(includeTextureCoords: false)
                    };
                    var material = CreateMaterial(CreateTexture(baseColorTextureImageA));
                    foreach (Runtime.MeshPrimitive meshPrimitive in meshPrimitives)
                    {
                        meshPrimitive.Material = material;
                    }

                    // One of the primitives has a 'zoomed in' texture coordinate set.
                    meshPrimitives[1].TextureCoordSets = new List <List <Vector2> >
                    {
                        new List <Vector2>
                        {
                            new Vector2(0.9f, 0.9f),
                            new Vector2(0.1f, 0.9f),
                            new Vector2(0.1f, 0.1f),
                            new Vector2(0.9f, 0.1f),
                        }
                    };

                    AddMeshPrimitivesToSingleNode(nodes, meshPrimitives);

                    properties.Add(new Property(PropertyName.Description, "Two primitives using the same material."));
                    properties.Add(new Property(PropertyName.Difference, "One primitive has texture coordinates that displays all of texture A, while the other primitive has textures coordinates that don't display the border."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, nodes, animations) =>
                {
                    var meshPrimitive0      = MeshPrimitive.CreateSinglePlane();
                    var meshPrimitive1      = MeshPrimitive.CreateSinglePlane();
                    meshPrimitive0.Material = CreateMaterial(CreateTexture(baseColorTextureImageA));
                    meshPrimitive1.Material = CreateMaterial(CreateTexture(baseColorTextureImageB));

                    meshPrimitive0.Positions = meshPrimitive1.Positions;

                    AddMeshPrimitivesToMultipleNodes(nodes, meshPrimitive0, meshPrimitive1);

                    properties.Add(new Property(PropertyName.Description, "Two primitives using the same accessors for the `POSITION` attribute."));
                    properties.Add(new Property(PropertyName.Difference, "One primitive uses texture A while the other primitive uses texture B."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, nodes, animations) => {
                    var meshPrimitive0      = MeshPrimitive.CreateSinglePlane(includeIndices: false);
                    var meshPrimitive1      = MeshPrimitive.CreateSinglePlane();
                    meshPrimitive0.Material = CreateMaterial(CreateTexture(baseColorTextureImageA));
                    meshPrimitive1.Material = CreateMaterial(CreateTexture(baseColorTextureImageB));

                    meshPrimitive0.Indices = meshPrimitive1.Indices;

                    AddMeshPrimitivesToMultipleNodes(nodes, meshPrimitive0, meshPrimitive1);

                    properties.Add(new Property(PropertyName.Description, "Two primitives using the same accessors for indices."));
                    properties.Add(new Property(PropertyName.Difference, "One primitive uses texture A while the other primitive uses texture B."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, nodes, animations) =>
                {
                    var meshPrimitive      = MeshPrimitive.CreateSinglePlane();
                    meshPrimitive.Material = CreateMaterial(CreateTexture(baseColorTextureImageA));

                    AddMeshPrimitivesToMultipleNodes(nodes, meshPrimitive, meshPrimitive);
                    nodes[1].Mesh = nodes[0].Mesh;

                    properties.Add(new Property(PropertyName.Description, "Two nodes using the same mesh."));
                    properties.Add(new Property(PropertyName.Difference, "The two nodes have different translations."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, nodes, animations) => {
                    nodes.AddRange(Nodes.CreateFoldingPlaneSkin("skinA", 2, 3));
                    nodes[0].Name = "plane0";
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).Material         = CreateMaterial(CreateTexture(baseColorTextureImageA));
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).TextureCoordSets = Nodes.GetSkinATextureCoordSets();

                    // Adds just the node containing the mesh, dropping the data for a second set of joints.
                    nodes.Add(Nodes.CreateFoldingPlaneSkin("skinA", 2, 3)[0]);
                    nodes[2].Name = "plane1";
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).Material         = CreateMaterial(CreateTexture(baseColorTextureImageB));
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).TextureCoordSets = Nodes.GetSkinATextureCoordSets();
                    nodes[2].Skin = nodes[0].Skin;

                    // Offsets the position of both meshes so they don't overlap.
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).Positions = nodes[0].Mesh.MeshPrimitives.ElementAt(0).Positions.Select(position => { return(new Vector3(position.X - 0.3f, position.Y, position.Z)); });
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).Positions = nodes[2].Mesh.MeshPrimitives.ElementAt(0).Positions.Select(position => { return(new Vector3(position.X + 0.3f, position.Y, position.Z)); });

                    properties.Add(new Property(PropertyName.Description, "Two nodes using the same skin."));
                    properties.Add(new Property(PropertyName.Difference, "The two mesh primitives have different `POSITION` values."));
                }, (model) => { model.Camera = null; }),
                CreateModel((properties, nodes, animations) =>
                {
                    nodes.AddRange(Nodes.CreateFoldingPlaneSkin("skinA", 2, 3));
                    nodes[0].Name = "plane0";
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).Material         = CreateMaterial(CreateTexture(baseColorTextureImageA));
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).TextureCoordSets = Nodes.GetSkinATextureCoordSets();

                    // Adds just the node containing the mesh, dropping the data for a second set of joints.
                    nodes.Add(Nodes.CreateFoldingPlaneSkin("skinA", 2, 3)[0]);
                    nodes[2].Name = "plane1";
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).Material         = CreateMaterial(CreateTexture(baseColorTextureImageB));
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).TextureCoordSets = Nodes.GetSkinATextureCoordSets();
                    nodes[2].Skin.Joints = nodes[0].Skin.Joints;

                    // Creates new inverseBindMatrices for the second skin, rotating the flap further than the default value would.
                    nodes[2].Skin.InverseBindMatrices = new[]
                    {
                        nodes[2].Skin.InverseBindMatrices.First(),
                        Matrix4x4.Multiply(nodes[2].Skin.InverseBindMatrices.ElementAt(1), Matrix4x4.CreateRotationX(FloatMath.ToRadians(-30))),
                    };

                    // Offsets the position of both meshes so they don't overlap.
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).Positions = nodes[0].Mesh.MeshPrimitives.ElementAt(0).Positions.Select(position => { return(new Vector3(position.X - 0.3f, position.Y, position.Z)); });
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).Positions = nodes[2].Mesh.MeshPrimitives.ElementAt(0).Positions.Select(position => { return(new Vector3(position.X + 0.3f, position.Y, position.Z)); });

                    properties.Add(new Property(PropertyName.Description, "Two skins using the same joints."));
                    properties.Add(new Property(PropertyName.Difference, "The skin with texture B has inverseBindMatrices that fold twice as far as the skin with texture A."));
                }, (model) => { model.Camera = null; }),
                CreateModel((properties, nodes, animations) =>
                {
                    nodes.AddRange(Nodes.CreateFoldingPlaneSkin("skinA", 2, 3));
                    nodes[0].Name = "plane0";
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).Material         = CreateMaterial(CreateTexture(baseColorTextureImageA));
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).TextureCoordSets = Nodes.GetSkinATextureCoordSets();
                    nodes[1].Translation = Vector3.Add((Vector3)nodes[1].Translation, new Vector3(-0.3f, 0.0f, 0.0f));

                    nodes.AddRange(Nodes.CreateFoldingPlaneSkin("skinA", 2, 3));
                    nodes[2].Name = "plane1";
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).Material         = CreateMaterial(CreateTexture(baseColorTextureImageB));
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).TextureCoordSets = Nodes.GetSkinATextureCoordSets();
                    nodes[3].Translation = Vector3.Add((Vector3)nodes[3].Translation, new Vector3(0.3f, 0.0f, 0.0f));

                    nodes[2].Skin.InverseBindMatrices = nodes[0].Skin.InverseBindMatrices;

                    properties.Add(new Property(PropertyName.Description, "Two skins using the same inverseBindMatrices."));
                    properties.Add(new Property(PropertyName.Difference, "The base joint for the two skins have different translations."));
                }, (model) => { model.Camera = null; }),
                CreateModel((properties, nodes, animations) =>
                {
                    var meshPrimitive0      = MeshPrimitive.CreateCube();
                    var meshPrimitive1      = MeshPrimitive.CreateCube();
                    meshPrimitive0.Material = CreateMaterial(CreateTexture(baseColorTextureImageCube));
                    meshPrimitive1.Material = CreateMaterial(CreateTexture(baseColorTextureImageCube));
                    AddMeshPrimitivesToMultipleNodes(nodes, meshPrimitive0, meshPrimitive1);

                    var sampler = new Runtime.LinearAnimationSampler <Quaternion>(SamplerInputLinear, SamplerOutput);
                    AddAnimation(animations, nodes, sampler, sampler, true);

                    properties.Add(new Property(PropertyName.Description, "Two animation channels using the same sampler."));
                    properties.Add(new Property(PropertyName.Difference, "The two animation channels target different nodes."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, nodes, animations) =>
                {
                    var meshPrimitive0      = MeshPrimitive.CreateCube();
                    var meshPrimitive1      = MeshPrimitive.CreateCube();
                    meshPrimitive0.Material = CreateMaterial(CreateTexture(baseColorTextureImageCube));
                    meshPrimitive1.Material = CreateMaterial(CreateTexture(baseColorTextureImageCube));
                    AddMeshPrimitivesToMultipleNodes(nodes, meshPrimitive0, meshPrimitive1);

                    var inputKeys = SamplerInputLinear;
                    var sampler0  = new Runtime.LinearAnimationSampler <Quaternion>(inputKeys, SamplerOutput);
                    var sampler1  = new Runtime.LinearAnimationSampler <Quaternion>(inputKeys, SamplerOutputReverse);
                    AddAnimation(animations, nodes, sampler0, sampler1, false);

                    properties.Add(new Property(PropertyName.Description, "Two animation samplers using the same input accessors."));
                    properties.Add(new Property(PropertyName.Difference, "The two animation samplers have different output values."));
                }, (model) => { model.Camera = distantCamera; }),
                CreateModel((properties, nodes, animations) =>
                {
                    var meshPrimitive0      = MeshPrimitive.CreateCube();
                    var meshPrimitive1      = MeshPrimitive.CreateCube();
                    meshPrimitive0.Material = CreateMaterial(CreateTexture(baseColorTextureImageCube));
                    meshPrimitive1.Material = CreateMaterial(CreateTexture(baseColorTextureImageCube));
                    AddMeshPrimitivesToMultipleNodes(nodes, meshPrimitive0, meshPrimitive1);

                    var output   = SamplerOutput;
                    var sampler0 = new Runtime.LinearAnimationSampler <Quaternion>(SamplerInputLinear, output);
                    var sampler1 = new Runtime.LinearAnimationSampler <Quaternion>(SamplerInputCurve, output);
                    AddAnimation(animations, nodes, sampler0, sampler1, false);

                    properties.Add(new Property(PropertyName.Description, "Two animation samplers using the same output accessors."));
                    properties.Add(new Property(PropertyName.Difference, "The two animation samplers have different input values."));
                }, (model) => { model.Camera = distantCamera; }),
                // New model

                // To be implemented later. Needs to work as a type of interleaving.
                //CreateModel((properties, nodes, animations) =>
                //{
                //    var meshPrimitives = new List<Runtime.MeshPrimitive>
                //    {
                //        MeshPrimitive.CreateSinglePlane(includeTextureCoords: false),
                //        MeshPrimitive.CreateSinglePlane(includeTextureCoords: false)
                //    };
                //    meshPrimitives[0].TextureCoordSets = meshPrimitives[1].TextureCoordSets = MeshPrimitive.GetSinglePlaneTextureCoordSets();
                //    meshPrimitives[0].Normals = meshPrimitives[1].Normals = MeshPrimitive.GetSinglePlaneNormals();

                //   foreach (Runtime.MeshPrimitive meshPrimitive in meshPrimitives)
                //    {
                //        meshPrimitive.BufferViewsInstanced = true;
                //        meshPrimitive.Material = CreateMaterial();
                //    }
                //    AddMeshPrimitivesToSingleNode(nodes, meshPrimitives);

                //    properties.Add(new Property(PropertyName.Description, "Two accessors using the same buffer view."));
                //}, (model) => { model.Camera = null; }),
            };

            GenerateUsedPropertiesList();
        }
        public Animation_SkinType(List <string> imageList)
        {
            // There are no common properties in this model group that are reported in the readme.

            Model CreateModel(Action <List <Property>, Runtime.MeshPrimitive> setProperties)
            {
                var properties            = new List <Property>();
                List <Runtime.Node> nodes = Nodes.CreateFoldingPlaneSkin("skinA", 2, 3);
                var animations            = new List <Runtime.Animation>();

                Runtime.MeshPrimitive   meshPrimitive       = nodes[0].Mesh.MeshPrimitives.First();
                JointComponentTypeEnum  jointComponentType  = meshPrimitive.JointComponentType;
                WeightComponentTypeEnum weightComponentType = meshPrimitive.WeightComponentType;
                var closeCameraTranslation = new Manifest.Camera(new Vector3(0.5f, 0.0f, 0.6f));

                // Apply the common properties to the gltf.
                AnimateWithRotation(animations, nodes);

                // Apply the properties that are specific to this gltf.
                setProperties(properties, meshPrimitive);

                // Create the gltf object.
                return(new Model
                {
                    Properties = properties,
                    GLTF = CreateGLTF(() => new Runtime.Scene
                    {
                        Nodes = nodes
                    }, animations: animations),
                    Animated = true,
                    Camera = closeCameraTranslation,
                });
            }

            void AnimateWithRotation(List <Runtime.Animation> animations, List <Runtime.Node> nodes)
            {
                animations.Add(
                    new Runtime.Animation
                {
                    Channels = new List <Runtime.AnimationChannel>
                    {
                        new Runtime.AnimationChannel
                        {
                            Target = new Runtime.AnimationChannelTarget
                            {
                                Node = nodes[1].Children.First(),
                                Path = Runtime.AnimationChannelTarget.PathEnum.ROTATION,
                            }
                        }
                    }
                }
                    );

                animations[0].Channels.First().Sampler = new Runtime.LinearAnimationSampler <Quaternion>
                                                         (
                    new[]
                {
                    0.0f,
                    1.0f,
                    2.0f,
                },
                    new[]
                {
                    Quaternion.Identity,
                    Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(90.0f), 0.0f),
                    Quaternion.Identity,
                }
                                                         );
            }

            void JointsAreByte(Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.JointComponentType = JointComponentTypeEnum.UNSIGNED_BYTE;
            }

            void JointsAreShort(Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.JointComponentType = JointComponentTypeEnum.UNSIGNED_SHORT;
            }

            void WeightsAreFloat(Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.WeightComponentType = WeightComponentTypeEnum.FLOAT;
            }

            void WeightsAreByte(Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.WeightComponentType = WeightComponentTypeEnum.NORMALIZED_UNSIGNED_BYTE;
            }

            void WeightsAreShort(Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.WeightComponentType = WeightComponentTypeEnum.NORMALIZED_UNSIGNED_SHORT;
            }

            Models = new List <Model>
            {
                CreateModel((properties, meshPrimitive) =>
                {
                    JointsAreByte(meshPrimitive);
                    WeightsAreFloat(meshPrimitive);
                    properties.Add(new Property(PropertyName.JointsComponentType, "Byte"));
                    properties.Add(new Property(PropertyName.WeightComponentType, "Float"));
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    JointsAreByte(meshPrimitive);
                    WeightsAreByte(meshPrimitive);
                    properties.Add(new Property(PropertyName.JointsComponentType, "Byte"));
                    properties.Add(new Property(PropertyName.WeightComponentType, "Byte"));
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    JointsAreByte(meshPrimitive);
                    WeightsAreShort(meshPrimitive);
                    properties.Add(new Property(PropertyName.JointsComponentType, "Byte"));
                    properties.Add(new Property(PropertyName.WeightComponentType, "Short"));
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    JointsAreShort(meshPrimitive);
                    WeightsAreFloat(meshPrimitive);
                    properties.Add(new Property(PropertyName.JointsComponentType, "Short"));
                    properties.Add(new Property(PropertyName.WeightComponentType, "Float"));
                }),
            };

            GenerateUsedPropertiesList();
        }
        public Animation_SamplerType(List <string> imageList)
        {
            Runtime.Image baseColorTextureImage = UseTexture(imageList, "BaseColor_Cube");

            CommonProperties.Add(new Property(PropertyName.Target, "Rotation"));
            CommonProperties.Add(new Property(PropertyName.Interpolation, "Linear"));

            Model CreateModel(AnimationSampler.ComponentTypeEnum samplerOutputComponentType, string samplerOutputComponentTypeDisplayValue)
            {
                var properties        = new List <Property>();
                var cubeMeshPrimitive = MeshPrimitive.CreateCube();

                // Apply the common properties to the gltf.
                cubeMeshPrimitive.Material = new Runtime.Material
                {
                    MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness
                    {
                        BaseColorTexture = new Runtime.Texture {
                            Source = baseColorTextureImage
                        },
                    },
                };
                var node = new Runtime.Node
                {
                    Mesh = new Runtime.Mesh
                    {
                        MeshPrimitives = new[]
                        {
                            cubeMeshPrimitive
                        }
                    }
                };
                var channel = new Runtime.AnimationChannel
                {
                    Target = new Runtime.AnimationChannelTarget
                    {
                        Node = node,
                        Path = Runtime.AnimationChannelTarget.PathEnum.ROTATION,
                    },
                    Sampler = new Runtime.LinearAnimationSampler <Quaternion>
                              (
                        new[]
                    {
                        0.0f,
                        1.0f,
                        2.0f,
                        3.0f,
                        4.0f,
                    },
                        new[]
                    {
                        Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(90.0f), 0.0f, 0.0f),
                        Quaternion.Identity,
                        Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(-90.0f), 0.0f, 0.0f),
                        Quaternion.Identity,
                        Quaternion.CreateFromYawPitchRoll(FloatMath.ToRadians(90.0f), 0.0f, 0.0f),
                    },
                        outputComponentType: samplerOutputComponentType
                              )
                };

                // Apply the properties that are specific to this gltf.
                properties.Add(new Property(PropertyName.SamplerOutputComponentType, samplerOutputComponentTypeDisplayValue));

                // Create the gltf object.
                Runtime.GLTF gltf = CreateGLTF(() => new Runtime.Scene
                {
                    Nodes = new[]
                    {
                        node
                    },
                });
                gltf.Animations = new[]
                {
                    new Runtime.Animation
                    {
                        Channels = new List <Runtime.AnimationChannel>
                        {
                            channel
                        }
                    }
                };
                return(new Model
                {
                    Properties = properties,
                    GLTF = gltf,
                    Animated = true,
                });
            }

            Models = new List <Model>
            {
                CreateModel(AnimationSampler.ComponentTypeEnum.FLOAT, "Float"),
                CreateModel(AnimationSampler.ComponentTypeEnum.NORMALIZED_BYTE, "Byte"),
                CreateModel(AnimationSampler.ComponentTypeEnum.NORMALIZED_SHORT, "Short"),
            };

            GenerateUsedPropertiesList();
        }