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, 0.0, 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, 0.5, 0.0, 0.866]</code>. The channel overrides the rotation of the node to a different constant value of <code>[0.0, -0.5, 0.0, 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, 0.5, 0.0, 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(); }
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 }); }
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 }); }
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 }); }
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] }); }
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(); }
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 }); }
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(); }
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(); }