public Material_SpecularGlossiness(List <string> imageList)
        {
            Runtime.Image diffuseTextureImage            = UseTexture(imageList, "Diffuse_Plane");
            Runtime.Image specularGlossinessTextureImage = UseTexture(imageList, "SpecularGlossiness_Plane");
            Runtime.Image baseColorTextureImage          = UseTexture(imageList, "BaseColor_X");

            // Track the common properties for use in the readme.
            CommonProperties.Add(new Property(PropertyName.ExtensionUsed, "Specular Glossiness"));
            CommonProperties.Add(new Property(PropertyName.ExtensionRequired, "Specular Glossiness"));
            CommonProperties.Add(new Property(PropertyName.BaseColorTexture, baseColorTextureImage));

            Model CreateModel(Action <List <Property>, Runtime.MeshPrimitive, Runtime.Material, KHR_materials_pbrSpecularGlossiness> setProperties)
            {
                var properties    = new List <Property>();
                var meshPrimitive = MeshPrimitive.CreateSinglePlane();
                var extension     = new KHR_materials_pbrSpecularGlossiness();

                meshPrimitive.Material            = new Runtime.Material();
                meshPrimitive.Material.Extensions = new List <Extension> {
                    extension
                };
                meshPrimitive.Material.MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness();

                // Apply the common properties to the gltf.
                meshPrimitive.Material.MetallicRoughnessMaterial.BaseColorTexture = new Runtime.Texture {
                    Source = baseColorTextureImage
                };

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

                // Create the gltf object.
                return(new Model
                {
                    Properties = properties,
                    GLTF = CreateGLTF(() => new Runtime.Scene
                    {
                        Nodes = new[]
                        {
                            new Runtime.Node
                            {
                                Mesh = new Runtime.Mesh
                                {
                                    MeshPrimitives = new[]
                                    {
                                        meshPrimitive
                                    }
                                },
                            },
                        },
                    },
                                      extensionsUsed: new List <string> {
                        "KHR_materials_pbrSpecularGlossiness"
                    },
                                      extensionsRequired: new List <string> {
                        "KHR_materials_pbrSpecularGlossiness"
                    }),
                });
            }

            void SetVertexColor(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                var vertexColors = new[]
                {
                    new Vector4(0.0f, 0.0f, 1.0f, 0.8f),
                    new Vector4(1.0f, 0.0f, 0.0f, 0.8f),
                    new Vector4(0.0f, 0.0f, 1.0f, 0.8f),
                    new Vector4(1.0f, 0.0f, 0.0f, 0.8f)
                };

                meshPrimitive.ColorComponentType = ColorComponentTypeEnum.FLOAT;
                meshPrimitive.ColorType          = ColorTypeEnum.VEC3;
                meshPrimitive.Colors             = vertexColors;

                properties.Add(new Property(PropertyName.VertexColor, "Vector3 Float"));
            }

            void SetDiffuseTexture(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                extension.DiffuseTexture = new Runtime.Texture {
                    Source = diffuseTextureImage
                };
                properties.Add(new Property(PropertyName.DiffuseTexture, diffuseTextureImage));
            }

            void SetDiffuseFactor(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                var diffuseFactorValue = new Vector4(0.2f, 0.2f, 0.2f, 0.8f);

                extension.DiffuseFactor = diffuseFactorValue;
                properties.Add(new Property(PropertyName.DiffuseFactor, diffuseFactorValue));
            }

            void SetSpecularGlossinessTexture(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                extension.SpecularGlossinessTexture = new Runtime.Texture {
                    Source = specularGlossinessTextureImage
                };
                properties.Add(new Property(PropertyName.SpecularGlossinessTexture, specularGlossinessTextureImage));
            }

            void SetSpecularFactor(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                var specularFactorValue = new Vector3(0.4f, 0.4f, 0.4f);

                extension.SpecularFactor = specularFactorValue;
                properties.Add(new Property(PropertyName.SpecularFactor, specularFactorValue));
            }

            void SetSpecularFactorToZero(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                var specularFactorValue = new Vector3(0.0f, 0.0f, 0.0f);

                extension.SpecularFactor = specularFactorValue;
                properties.Add(new Property(PropertyName.SpecularFactor, specularFactorValue));
            }

            void SetGlossinessFactor(List <Property> properties, KHR_materials_pbrSpecularGlossiness extension)
            {
                extension.GlossinessFactor = 0.3f;
                properties.Add(new Property(PropertyName.GlossinessFactor, extension.GlossinessFactor));
            }

            Models = new List <Model>
            {
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    // There are no properties set on this model.
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetVertexColor(properties, meshPrimitive);
                    SetSpecularFactorToZero(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetDiffuseTexture(properties, extension);
                    SetSpecularFactorToZero(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetDiffuseFactor(properties, extension);
                    SetSpecularFactorToZero(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetSpecularGlossinessTexture(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetSpecularFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetGlossinessFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetVertexColor(properties, meshPrimitive);
                    SetDiffuseTexture(properties, extension);
                    SetSpecularFactorToZero(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetDiffuseTexture(properties, extension);
                    SetDiffuseFactor(properties, extension);
                    SetSpecularFactorToZero(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetDiffuseTexture(properties, extension);
                    SetGlossinessFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetSpecularGlossinessTexture(properties, extension);
                    SetSpecularFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetSpecularGlossinessTexture(properties, extension);
                    SetGlossinessFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetDiffuseTexture(properties, extension);
                    SetSpecularFactor(properties, extension);
                    SetGlossinessFactor(properties, extension);
                }),
                CreateModel((properties, meshPrimitive, material, extension) =>
                {
                    SetVertexColor(properties, meshPrimitive);
                    SetDiffuseTexture(properties, extension);
                    SetDiffuseFactor(properties, extension);
                    SetSpecularGlossinessTexture(properties, extension);
                    SetSpecularFactor(properties, extension);
                    SetGlossinessFactor(properties, extension);
                }),
            };

            GenerateUsedPropertiesList();
        }
        public Instancing(List <string> imageList)
        {
            var baseColorImageA    = UseTexture(imageList, "BaseColor_A");
            var baseColorImageB    = UseTexture(imageList, "BaseColor_B");
            var baseColorImageCube = 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.

            TextureInfo CreateTextureInfo(Image source)
            {
                return(new TextureInfo
                {
                    Texture = new Texture
                    {
                        Source = source,
                    }
                });
            }

            Model CreateModel(Action <List <Property>, List <Node>, List <Animation> > setProperties, Action <Model> setCamera)
            {
                var properties = new List <Property>();
                var animations = new List <Animation>();
                var animated   = true;
                var nodes      = new List <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 Scene {
                        Nodes = nodes
                    }, animations: animations),
                    Animated = animated,
                };

                setCamera(model);

                return(model);
            }

            var samplerInputLinear = Data.Create(new[]
            {
                0.0f,
                1.0f,
                2.0f,
                3.0f,
                4.0f,
            });

            var samplerInputCurve = Data.Create(new[]
            {
                0.0f,
                0.5f,
                1.0f,
                2.0f,
                4.0f,
            });

            var samplerOutput = Data.Create(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 = Data.Create(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.Material CreateMaterial(TextureInfo textureInfo)
            {
                return(new Runtime.Material
                {
                    PbrMetallicRoughness = new PbrMetallicRoughness
                    {
                        BaseColorTexture = textureInfo
                    }
                });
            }

            void AddMeshPrimitivesToSingleNode(List <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.Values = meshPrimitives[0].Positions.Values.Select(position => { return(new Vector3(position.X - 0.6f, position.Y, position.Z)); });
                    meshPrimitives[1].Positions.Values = meshPrimitives[1].Positions.Values.Select(position => { return(new Vector3(position.X + 0.6f, position.Y, position.Z)); });
                }

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

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

            void AddAnimation(List <Animation> animations, List <Node> nodes, AnimationSampler sampler0, AnimationSampler sampler1, bool samplerInstanced)
            {
                animations.Add(new Animation
                {
                    Channels = new List <AnimationChannel>
                    {
                        new AnimationChannel
                        {
                            Target = new AnimationChannelTarget
                            {
                                Node = nodes[0],
                                Path = AnimationChannelTargetPath.Rotation,
                            },
                            Sampler = sampler0
                        },
                        new AnimationChannel
                        {
                            Target = new AnimationChannelTarget
                            {
                                Node = nodes[1],
                                Path = AnimationChannelTargetPath.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.TexCoords0 = Data.Create <Vector2>
                                                   (
                            new[]
                        {
                            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(CreateTextureInfo(baseColorImageA));
                    meshPrimitives[1].Material = CreateMaterial(CreateTextureInfo(baseColorImageA));

                    meshPrimitives[0].Material.PbrMetallicRoughness.BaseColorTexture.Texture.Sampler = new Sampler
                    {
                        WrapT = SamplerWrap.ClampToEdge,
                        WrapS = SamplerWrap.ClampToEdge
                    };
                    meshPrimitives[1].Material.PbrMetallicRoughness.BaseColorTexture.Texture.Sampler = new Sampler
                    {
                        WrapT = SamplerWrap.MirroredRepeat,
                        WrapS = SamplerWrap.MirroredRepeat
                    };

                    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(CreateTextureInfo(baseColorImageA));
                    meshPrimitives[1].Material = CreateMaterial(CreateTextureInfo(baseColorImageB));

                    var sampler = new Sampler
                    {
                        WrapT = SamplerWrap.ClampToEdge,
                        WrapS = SamplerWrap.ClampToEdge
                    };
                    foreach (Runtime.MeshPrimitive meshPrimitive in meshPrimitives)
                    {
                        meshPrimitive.Material.PbrMetallicRoughness.BaseColorTexture.Texture.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.TexCoords0 = Data.Create <Vector2>
                                                   (
                            new[]
                        {
                            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 = CreateTextureInfo(baseColorImageA);
                    foreach (Runtime.MeshPrimitive meshPrimitive in meshPrimitives)
                    {
                        meshPrimitive.Material = CreateMaterial(texture);
                    }
                    meshPrimitives[0].Material.PbrMetallicRoughness.BaseColorTexture = meshPrimitives[1].Material.PbrMetallicRoughness.BaseColorTexture;
                    meshPrimitives[1].Material.PbrMetallicRoughness.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(CreateTextureInfo(baseColorImageA));
                    foreach (Runtime.MeshPrimitive meshPrimitive in meshPrimitives)
                    {
                        meshPrimitive.Material = material;
                    }

                    // One of the primitives has a 'zoomed in' texture coordinate set.
                    meshPrimitives[1].TexCoords0 = Data.Create <Vector2>
                                                   (
                        new[]
                    {
                        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(CreateTextureInfo(baseColorImageA));
                    meshPrimitive1.Material = CreateMaterial(CreateTextureInfo(baseColorImageB));

                    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(CreateTextureInfo(baseColorImageA));
                    meshPrimitive1.Material = CreateMaterial(CreateTextureInfo(baseColorImageB));

                    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(CreateTextureInfo(baseColorImageA));

                    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(CreateTextureInfo(baseColorImageA));
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).TexCoords0 = Data.Create(Nodes.GetSkinATexCoords());

                    // 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(CreateTextureInfo(baseColorImageB));
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).TexCoords0 = Data.Create(Nodes.GetSkinATexCoords());
                    nodes[2].Skin = nodes[0].Skin;

                    // Offsets the position of both meshes so they don't overlap.
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).Positions.Values = nodes[0].Mesh.MeshPrimitives.ElementAt(0).Positions.Values.Select(position => { return(new Vector3(position.X - 0.3f, position.Y, position.Z)); });
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).Positions.Values = nodes[2].Mesh.MeshPrimitives.ElementAt(0).Positions.Values.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(CreateTextureInfo(baseColorImageA));
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).TexCoords0 = Data.Create(Nodes.GetSkinATexCoords());

                    // 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(CreateTextureInfo(baseColorImageB));
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).TexCoords0 = Data.Create(Nodes.GetSkinATexCoords());
                    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 = Data.Create(new[]
                    {
                        nodes[2].Skin.InverseBindMatrices.Values.First(),
                        Matrix4x4.Multiply(nodes[2].Skin.InverseBindMatrices.Values.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.Values = nodes[0].Mesh.MeshPrimitives.ElementAt(0).Positions.Values.Select(position => new Vector3(position.X - 0.3f, position.Y, position.Z));
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).Positions.Values = nodes[2].Mesh.MeshPrimitives.ElementAt(0).Positions.Values.Select(position => 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(CreateTextureInfo(baseColorImageA));
                    nodes[0].Mesh.MeshPrimitives.ElementAt(0).TexCoords0 = Data.Create(Nodes.GetSkinATexCoords());
                    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(CreateTextureInfo(baseColorImageB));
                    nodes[2].Mesh.MeshPrimitives.ElementAt(0).TexCoords0 = Data.Create(Nodes.GetSkinATexCoords());
                    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();
                    var textureInfo         = CreateTextureInfo(baseColorImageCube);
                    meshPrimitive0.Material = CreateMaterial(textureInfo);
                    meshPrimitive1.Material = CreateMaterial(textureInfo);
                    AddMeshPrimitivesToMultipleNodes(nodes, meshPrimitive0, meshPrimitive1);

                    var sampler = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = samplerInputLinear,
                        Output        = 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();
                    var textureInfo         = CreateTextureInfo(baseColorImageCube);
                    meshPrimitive0.Material = CreateMaterial(textureInfo);
                    meshPrimitive1.Material = CreateMaterial(textureInfo);
                    AddMeshPrimitivesToMultipleNodes(nodes, meshPrimitive0, meshPrimitive1);

                    var sampler0 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = samplerInputLinear,
                        Output        = samplerOutput,
                    };

                    var sampler1 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = samplerInputLinear,
                        Output        = 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();
                    var textureInfo         = CreateTextureInfo(baseColorImageCube);
                    meshPrimitive0.Material = CreateMaterial(textureInfo);
                    meshPrimitive1.Material = CreateMaterial(textureInfo);
                    AddMeshPrimitivesToMultipleNodes(nodes, meshPrimitive0, meshPrimitive1);

                    var sampler0 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = samplerInputLinear,
                        Output        = samplerOutput,
                    };

                    var sampler1 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = samplerInputCurve,
                        Output        = samplerOutput,
                    };

                    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; }),
                // 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].TexCoords0 = meshPrimitives[1].TexCoords0 = 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();
        }
Beispiel #3
0
        internal static int AddLineLoop(this Gltf gltf, string name, List <byte> buffer, double[] vertices, ushort[] indices, double[] vMin, double[] vMax, ushort iMin, ushort iMax, int materialId, MeshPrimitive.ModeEnum mode, Transform transform = null)
        {
            var m = new glTFLoader.Schema.Mesh();

            m.Name = name;
            var vBuff = gltf.AddBufferView(0, buffer.Count, vertices.Length * sizeof(float), null, null);
            var iBuff = gltf.AddBufferView(0, buffer.Count + vertices.Length * sizeof(float), indices.Length * sizeof(ushort), null, null);

            foreach (var v in vertices)
            {
                buffer.AddRange(BitConverter.GetBytes((float)v));
            }
            foreach (var i in indices)
            {
                buffer.AddRange(BitConverter.GetBytes(i));
            }

            while (buffer.Count % 4 != 0)
            {
                // Console.WriteLine("Padding...");
                buffer.Add(0);
            }

            var vAccess = gltf.AddAccessor(vBuff, 0, Accessor.ComponentTypeEnum.FLOAT, vertices.Length / 3, new[] { (float)vMin[0], (float)vMin[1], (float)vMin[2] }, new[] { (float)vMax[0], (float)vMax[1], (float)vMax[2] }, Accessor.TypeEnum.VEC3);
            var iAccess = gltf.AddAccessor(iBuff, 0, Accessor.ComponentTypeEnum.UNSIGNED_SHORT, indices.Length, new[] { (float)iMin }, new[] { (float)iMax }, Accessor.TypeEnum.SCALAR);

            var prim = new MeshPrimitive();

            prim.Indices    = iAccess;
            prim.Material   = materialId;
            prim.Mode       = mode;
            prim.Attributes = new Dictionary <string, int> {
                { "POSITION", vAccess }
            };

            m.Primitives = new[] { prim };

            // Add mesh to gltf
            if (gltf.Meshes != null)
            {
                // TODO: Get rid of this resizing.
                var meshes = gltf.Meshes.ToList();
                meshes.Add(m);
                gltf.Meshes = meshes.ToArray();
            }
            else
            {
                gltf.Meshes = new[] { m };
            }

            var parentId = 0;

            if (transform != null)
            {
                var a = transform.XAxis;
                var b = transform.YAxis;
                var c = transform.ZAxis;

                var transNode = new Node();

                transNode.Matrix = new[] {
                    (float)a.X, (float)a.Y, (float)a.Z, 0.0f,
                    (float)b.X, (float)b.Y, (float)b.Z, 0.0f,
                    (float)c.X, (float)c.Y, (float)c.Z, 0.0f,
                    (float)transform.Origin.X, (float)transform.Origin.Y, (float)transform.Origin.Z, 1.0f
                };

                parentId = gltf.AddNode(transNode, 0);
            }

            // Add mesh node to gltf
            var node = new Node();

            node.Mesh = gltf.Meshes.Length - 1;
            gltf.AddNode(node, parentId);

            return(gltf.Meshes.Length - 1);
        }
        protected virtual GameObject CreateMeshPrimitive(MeshPrimitive primitive, int meshID, int primitiveIndex)
        {
            var primitiveObj = new GameObject("Primitive");

            var meshFilter = primitiveObj.AddComponent <MeshFilter>();

            if (_assetCache.MeshCache[meshID][primitiveIndex] == null)
            {
                _assetCache.MeshCache[meshID][primitiveIndex] = new MeshCacheData();
            }
            if (_assetCache.MeshCache[meshID][primitiveIndex].LoadedMesh == null)
            {
                if (_assetCache.MeshCache[meshID][primitiveIndex].MeshAttributes.Count == 0)
                {
                    BuildMeshAttributes(primitive, meshID, primitiveIndex);
                }
                var meshAttributes = _assetCache.MeshCache[meshID][primitiveIndex].MeshAttributes;
                var vertexCount    = primitive.Attributes[SemanticProperties.POSITION].Value.Count;

                // todo optimize: There are multiple copies being performed to turn the buffer data into mesh data. Look into reducing them
                UnityEngine.Mesh mesh = new UnityEngine.Mesh
                {
                    vertices = primitive.Attributes.ContainsKey(SemanticProperties.POSITION)
                        ? meshAttributes[SemanticProperties.POSITION].AccessorContent.AsVertices.ToUnityVector3()
                        : null,
                    normals = primitive.Attributes.ContainsKey(SemanticProperties.NORMAL)
                        ? meshAttributes[SemanticProperties.NORMAL].AccessorContent.AsNormals.ToUnityVector3()
                        : null,

                    uv = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(0))
                        ? meshAttributes[SemanticProperties.TexCoord(0)].AccessorContent.AsTexcoords.ToUnityVector2()
                        : null,

                    uv2 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(1))
                        ? meshAttributes[SemanticProperties.TexCoord(1)].AccessorContent.AsTexcoords.ToUnityVector2()
                        : null,

                    uv3 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(2))
                        ? meshAttributes[SemanticProperties.TexCoord(2)].AccessorContent.AsTexcoords.ToUnityVector2()
                        : null,

                    uv4 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(3))
                        ? meshAttributes[SemanticProperties.TexCoord(3)].AccessorContent.AsTexcoords.ToUnityVector2()
                        : null,

                    colors = primitive.Attributes.ContainsKey(SemanticProperties.Color(0))
                        ? meshAttributes[SemanticProperties.Color(0)].AccessorContent.AsColors.ToUnityColor()
                        : null,

                    triangles = primitive.Indices != null
                        ? meshAttributes[SemanticProperties.INDICES].AccessorContent.AsTriangles
                        : MeshPrimitive.GenerateTriangles(vertexCount),

                    tangents = primitive.Attributes.ContainsKey(SemanticProperties.TANGENT)
                        ? meshAttributes[SemanticProperties.TANGENT].AccessorContent.AsTangents.ToUnityVector4()
                        : null
                };

                _assetCache.MeshCache[meshID][primitiveIndex].LoadedMesh = mesh;
            }

            meshFilter.sharedMesh = _assetCache.MeshCache[meshID][primitiveIndex].LoadedMesh;

            var materialWrapper = CreateMaterial(
                primitive.Material != null ? primitive.Material.Value : DefaultMaterial,
                primitive.Material != null ? primitive.Material.Id : -1
                );

            var meshRenderer = primitiveObj.AddComponent <MeshRenderer>();

            meshRenderer.material = materialWrapper.GetContents(primitive.Attributes.ContainsKey(SemanticProperties.Color(0)));

            if (_addColliders)
            {
                var meshCollider = primitiveObj.AddComponent <MeshCollider>();
                meshCollider.sharedMesh = meshFilter.mesh;
            }

            return(primitiveObj);
        }
 private void ExportNormalMaterial(UnityEngine.Material material, MeshPrimitive primitive, ExporterEntry entry)
 {
     primitive.Material = entry.SaveNormalMaterial(material);
 }
Beispiel #6
0
        public Material_MetallicRoughness(List <string> imageList)
        {
            var baseColorTexture = new Texture {
                Source = UseTexture(imageList, "BaseColor_Plane")
            };
            var metallicRoughnessTexture = new Texture {
                Source = UseTexture(imageList, "MetallicRoughness_Plane")
            };

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

            Model CreateModel(Action <List <Property>, Runtime.MeshPrimitive, PbrMetallicRoughness> setProperties)
            {
                var properties    = new List <Property>();
                var meshPrimitive = MeshPrimitive.CreateSinglePlane(includeTextureCoords: false);

                // Apply the properties that are specific to this gltf.
                meshPrimitive.Material = new Runtime.Material
                {
                    PbrMetallicRoughness = new PbrMetallicRoughness()
                };

                setProperties(properties, meshPrimitive, meshPrimitive.Material.PbrMetallicRoughness);

                // Create the gltf object.
                return(new Model
                {
                    Properties = properties,
                    GLTF = CreateGLTF(() => new Scene
                    {
                        Nodes = new[]
                        {
                            new Node
                            {
                                Mesh = new Runtime.Mesh
                                {
                                    MeshPrimitives = new List <Runtime.MeshPrimitive>
                                    {
                                        meshPrimitive
                                    }
                                },
                            },
                        },
                    }),
                });
            }

            void SetVertexColor(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.Colors = Data.Create
                                       (
                    new[]
                {
                    new Vector3(0.0f, 0.0f, 1.0f),
                    new Vector3(1.0f, 0.0f, 0.0f),
                    new Vector3(0.0f, 0.0f, 1.0f),
                    new Vector3(1.0f, 0.0f, 0.0f),
                }
                                       );

                properties.Add(new Property(PropertyName.VertexColor, $"Vector3 Float"));
            }

            void SetBaseColorTexture(List <Property> properties, PbrMetallicRoughness metallicRoughness)
            {
                metallicRoughness.BaseColorTexture = new TextureInfo {
                    Texture = baseColorTexture
                };
                properties.Add(new Property(PropertyName.BaseColorTexture, baseColorTexture.Source.ToReadmeString()));
            }

            void SetBaseColorFactor(List <Property> properties, PbrMetallicRoughness metallicRoughness)
            {
                var baseColorFactorValue = new Vector4(0.2f, 0.2f, 0.2f, 0.8f);

                metallicRoughness.BaseColorFactor = baseColorFactorValue;
                properties.Add(new Property(PropertyName.BaseColorFactor, baseColorFactorValue.ToReadmeString()));
            }

            void SetMetallicRoughnessTexture(List <Property> properties, PbrMetallicRoughness metallicRoughness)
            {
                metallicRoughness.MetallicRoughnessTexture = new TextureInfo {
                    Texture = metallicRoughnessTexture
                };
                properties.Add(new Property(PropertyName.MetallicRoughnessTexture, metallicRoughnessTexture.Source.ToReadmeString()));
            }

            void SetMetallicFactor(List <Property> properties, PbrMetallicRoughness metallicRoughness)
            {
                metallicRoughness.MetallicFactor = 0.0f;
                properties.Add(new Property(PropertyName.MetallicFactor, metallicRoughness.MetallicFactor.ToReadmeString()));
            }

            void SetRoughnessFactor(List <Property> properties, PbrMetallicRoughness metallicRoughness)
            {
                metallicRoughness.RoughnessFactor = 0.0f;
                properties.Add(new Property(PropertyName.RoughnessFactor, metallicRoughness.RoughnessFactor.ToReadmeString()));
            }

            Models = new List <Model>
            {
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    // There are no properties set on this model.
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    SetVertexColor(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    meshPrimitive.TexCoords0 = Data.Create(MeshPrimitive.GetSinglePlaneTexCoords());
                    SetBaseColorTexture(properties, metallicRoughness);
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    SetBaseColorFactor(properties, metallicRoughness);
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    meshPrimitive.TexCoords0 = Data.Create(MeshPrimitive.GetSinglePlaneTexCoords());
                    SetMetallicRoughnessTexture(properties, metallicRoughness);
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    SetMetallicFactor(properties, metallicRoughness);
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    SetRoughnessFactor(properties, metallicRoughness);
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    meshPrimitive.TexCoords0 = Data.Create(MeshPrimitive.GetSinglePlaneTexCoords());
                    SetVertexColor(properties, meshPrimitive);
                    SetBaseColorTexture(properties, metallicRoughness);
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    meshPrimitive.TexCoords0 = Data.Create(MeshPrimitive.GetSinglePlaneTexCoords());
                    SetBaseColorTexture(properties, metallicRoughness);
                    SetBaseColorFactor(properties, metallicRoughness);
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    meshPrimitive.TexCoords0 = Data.Create(MeshPrimitive.GetSinglePlaneTexCoords());
                    SetMetallicRoughnessTexture(properties, metallicRoughness);
                    SetMetallicFactor(properties, metallicRoughness);
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    meshPrimitive.TexCoords0 = Data.Create(MeshPrimitive.GetSinglePlaneTexCoords());
                    SetMetallicRoughnessTexture(properties, metallicRoughness);
                    SetRoughnessFactor(properties, metallicRoughness);
                }),
                CreateModel((properties, meshPrimitive, metallicRoughness) =>
                {
                    meshPrimitive.TexCoords0 = Data.Create(MeshPrimitive.GetSinglePlaneTexCoords());
                    SetVertexColor(properties, meshPrimitive);
                    SetBaseColorTexture(properties, metallicRoughness);
                    SetBaseColorFactor(properties, metallicRoughness);
                    SetMetallicRoughnessTexture(properties, metallicRoughness);
                    SetMetallicFactor(properties, metallicRoughness);
                    SetRoughnessFactor(properties, metallicRoughness);
                }),
            };

            GenerateUsedPropertiesList();
        }
Beispiel #7
0
        public void MeshPrimitiveEqualTest()
        {
            var a = new MeshPrimitive {
                attributes = new Attributes {
                    POSITION = 42
                }
            };
            var b = new MeshPrimitive {
                attributes = new Attributes {
                    POSITION = 42
                }
            };

            Assert.IsTrue(a.Equals(b));

            a.targets = new[] { new MorphTarget {
                                    POSITION = 0
                                } };
            b.targets = null;
            Assert.IsFalse(a.Equals(b));

            a.targets = new[] { new MorphTarget {
                                    POSITION = 0
                                } };
            b.targets = new[] { new MorphTarget {
                                    POSITION = 0
                                } };
            Assert.IsTrue(a.Equals(b));

            a.targets = new[] { new MorphTarget {
                                    POSITION = 0
                                } };
            b.targets = new[] { new MorphTarget {
                                    POSITION = 0, NORMAL = 1
                                } };
            Assert.IsFalse(a.Equals(b));

            a.targets = null;
            b.targets = new[] { new MorphTarget {
                                    POSITION = 0
                                } };
            Assert.IsFalse(a.Equals(b));

            a.targets = new[] { new MorphTarget {
                                    POSITION = 0
                                } };
            b.targets = new[] { new MorphTarget {
                                    POSITION = 0
                                }, new MorphTarget {
                                    POSITION = 0
                                } };
            Assert.IsFalse(a.Equals(b));

            a = new MeshPrimitive {
                attributes = new Attributes {
                    POSITION = 41
                }
            };
            b = new MeshPrimitive {
                attributes = new Attributes {
                    POSITION = 42
                }
            };
            Assert.IsFalse(a.Equals(b));

            a.targets = new[] { new MorphTarget {
                                    POSITION = 0
                                } };
            b.targets = new[] { new MorphTarget {
                                    POSITION = 0
                                } };
            Assert.IsFalse(a.Equals(b));
        }
Beispiel #8
0
 public Model GenerateModel(MeshPrimitive meshPrimitive, string name, IEnumerable <Attribution> attributions = null)
 {
     return(GenerateModel(new List <MeshPrimitive> {
         meshPrimitive
     }, name, attributions));
 }
Beispiel #9
0
        public MeshPrimitive GenerateLine(IEnumerable <GeoPoint> points, Vector4 color, float width)
        {
            MeshPrimitive mesh = null;

            try
            {
                if (points == null)
                {
                    _logger?.LogWarning("Points are empty.");
                }
                else
                {
                    if (width == 0)
                    {
                        // Basic line strip  declaration
                        mesh = new MeshPrimitive()
                        {
                            Colors = points.Select(c => color)
                            ,
                            ColorComponentType = MeshPrimitive.ColorComponentTypeEnum.FLOAT
                            ,
                            ColorType = MeshPrimitive.ColorTypeEnum.VEC4
                            ,
                            Mode = MeshPrimitive.ModeEnum.LINE_STRIP
                            ,
                            Positions = points.Select(pt => pt.ToVector3())
                            ,
                            Material = new Material()
                        };
                    }
                    else
                    {
                        // https://gist.github.com/gszauer/5718441
                        // Line triangle mesh
                        List <Vector3> sections = points.Select(pt => pt.ToVector3())
                                                  .Distinct()
                                                  .ToList();

                        List <Vector3> vertices = new List <Vector3>(sections.Count * 2);

                        for (int i = 0; i < sections.Count - 1; i++)
                        {
                            Vector3 current = sections[i];
                            Vector3 next    = sections[i + 1];
                            Vector3 dir     = Vector3.Normalize(next - current);


                            // translate the vector to the left along its way
                            Vector3 side = Vector3.Cross(dir, Vector3.UnitY) * width;

                            Vector3 v0 = current - side; // 0
                            Vector3 v1 = current + side; // 1

                            vertices.Add(v0);
                            vertices.Add(v1);

                            if (i == sections.Count - 2) // add last vertices
                            {
                                v0 = next - side;        // 0
                                v1 = next + side;        // 1
                                vertices.Add(v0);
                                vertices.Add(v1);
                            }
                        }
                        // add last vertices


                        List <int> indices = new List <int>((sections.Count - 1) * 6);
                        for (int i = 0; i < sections.Count - 1; i++)
                        {
                            int i0 = i * 2;
                            indices.Add(i0);
                            indices.Add(i0 + 1);
                            indices.Add(i0 + 3);

                            indices.Add(i0 + 0);
                            indices.Add(i0 + 3);
                            indices.Add(i0 + 2);
                        }

                        IEnumerable <Vector3> normals = _meshService.ComputeNormals(vertices, indices);
                        // Basic line strip  declaration
                        mesh = new MeshPrimitive()
                        {
                            Colors = vertices.Select(v => color)
                            ,
                            ColorComponentType = MeshPrimitive.ColorComponentTypeEnum.FLOAT
                            ,
                            ColorType = MeshPrimitive.ColorTypeEnum.VEC4
                            ,
                            Mode = MeshPrimitive.ModeEnum.TRIANGLES
                            ,
                            Positions = vertices
                            ,
                            Material = new Material()
                            {
                                DoubleSided = true
                            }
                            ,
                            Indices = indices
                            ,
                            Normals = normals
                            ,
                            IndexComponentType = MeshPrimitive.IndexComponentTypeEnum.UNSIGNED_INT
                        };
                    }
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, ex.ToString());
                throw;
            }
            return(mesh);
        }
Beispiel #10
0
        public Accessor_SparseType(List <string> imageList)
        {
            var baseColorTextureA = new Texture {
                Source = UseTexture(imageList, "BaseColor_A")
            };
            var baseColorTextureB = new Texture {
                Source = UseTexture(imageList, "BaseColor_B")
            };

            UseFigure(imageList, "SparseAccessor_Input");
            UseFigure(imageList, "SparseAccessor_Output-Rotation");
            UseFigure(imageList, "SparseAccessor_NoBufferView");

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

            Model CreateModel(Action <List <Property>, Animation, List <Node> > setProperties)
            {
                var properties     = new List <Property>();
                var animated       = true;
                var meshPrimitive0 = MeshPrimitive.CreateSinglePlane(includeTextureCoords: false);
                var meshPrimitive1 = MeshPrimitive.CreateSinglePlane(includeTextureCoords: false);

                var nodes = new List <Node>
                {
                    new Node
                    {
                        Mesh = new Runtime.Mesh
                        {
                            MeshPrimitives = new List <Runtime.MeshPrimitive>
                            {
                                meshPrimitive0
                            }
                        }
                    },
                    new Node
                    {
                        Mesh = new Runtime.Mesh
                        {
                            MeshPrimitives = new List <Runtime.MeshPrimitive>
                            {
                                meshPrimitive1
                            }
                        }
                    }
                };

                var animation  = new Animation();
                var animations = new List <Animation>
                {
                    animation
                };

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

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

                // Create the gltf object.
                return(new Model
                {
                    Properties = properties,
                    GLTF = CreateGLTF
                           (
                        () => new Scene
                    {
                        Nodes = nodes
                    },
                        animations: animations
                           ),
                    Animated = animated,
                    Camera = new Manifest.Camera(new Vector3(0.0f, 0.0f, 2.75f))
                });
            }

            var samplerInputLinear = new[]
            {
                0.0f,
                1.0f,
                2.0f,
            };

            var samplerInputSparse = 1.5f;

            var samplerOutputTranslationSparse = new Vector3(0.0f, 0.2f, 0.0f);

            var samplerOutputRotation = new[]
            {
                Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-45.0f), 0.0f),
                Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(45.0f), 0.0f),
                Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-45.0f), 0.0f),
            };

            var samplerOutputRotationSparse = Quaternion.CreateFromYawPitchRoll(0.0f, FloatMath.ToRadians(-90.0f), 0.0f);

            List <AnimationChannel> CreateChannels(List <Node> nodes, AnimationSampler sampler0, AnimationSampler sampler1)
            {
                return(new List <AnimationChannel>
                {
                    new AnimationChannel
                    {
                        Target = new AnimationChannelTarget
                        {
                            Node = nodes[0],
                        },
                        Sampler = sampler0
                    },
                    new AnimationChannel
                    {
                        Target = new AnimationChannelTarget
                        {
                            Node = nodes[1],
                        },
                        Sampler = sampler1
                    },
                });
            }

            void SetAnimationPaths(List <AnimationChannel> channels, AnimationChannelTargetPath path, List <Property> properties)
            {
                foreach (var channel in channels)
                {
                    channel.Target.Path = path;
                }
            }

            void OffsetPositions(List <Node> nodes)
            {
                // Offsets the positions of the mesh primitives so they don't overlap. This is done because animation translations override node translations.
                nodes[0].Mesh.MeshPrimitives.First().Positions.Values = nodes[0].Mesh.MeshPrimitives.First().Positions.Values.Select(position => { return(new Vector3(position.X - 0.6f, position.Y, position.Z)); });
                nodes[1].Mesh.MeshPrimitives.First().Positions.Values = nodes[1].Mesh.MeshPrimitives.First().Positions.Values.Select(position => { return(new Vector3(position.X + 0.6f, position.Y, position.Z)); });
            }

            void SetTexture(List <Node> nodes)
            {
                nodes[0].Mesh.MeshPrimitives.First().Material = new Runtime.Material
                {
                    PbrMetallicRoughness = new PbrMetallicRoughness
                    {
                        BaseColorTexture = new TextureInfo {
                            Texture = baseColorTextureA
                        }
                    }
                };
                nodes[1].Mesh.MeshPrimitives.First().Material = new Runtime.Material
                {
                    PbrMetallicRoughness = new PbrMetallicRoughness
                    {
                        BaseColorTexture = new TextureInfo {
                            Texture = baseColorTextureB
                        }
                    }
                };

                nodes[0].Mesh.MeshPrimitives.First().TexCoords0 = Data.Create(MeshPrimitive.GetSinglePlaneTexCoords());
                nodes[1].Mesh.MeshPrimitives.First().TexCoords0 = Data.Create(MeshPrimitive.GetSinglePlaneTexCoords());
            }

            Models = new List <Model>
            {
                CreateModel((properties, animation, nodes) =>
                {
                    SetTexture(nodes);
                    OffsetPositions(nodes);

                    var sampler0 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear),
                        Output        = Data.Create(samplerOutputRotation),
                    };

                    var sampler1 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear, DataSparse.Create
                                                    (
                                                        DataType.UnsignedByte,
                                                        new Dictionary <int, float>
                        {
                            { 1, samplerInputSparse }
                        }
                                                    )),
                        Output = Data.Create(samplerOutputRotation),
                    };

                    var channels       = CreateChannels(nodes, sampler0, sampler1);
                    animation.Channels = channels;
                    SetAnimationPaths(channels, AnimationChannelTargetPath.Rotation, properties);

                    properties.Add(new Property(PropertyName.SparseAccessor, "Input"));
                    properties.Add(new Property(PropertyName.IndicesType, sampler1.Input.Sparse.IndicesOutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.ValueType, sampler1.Input.OutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.BufferView, ":white_check_mark:"));
                    properties.Add(new Property(PropertyName.Description, "See Figure 1"));
                }),
                CreateModel((properties, animation, nodes) =>
                {
                    SetTexture(nodes);
                    OffsetPositions(nodes);

                    var sampler0 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear),
                        Output        = Data.Create(samplerOutputRotation),
                    };

                    var sampler1 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear, DataSparse.Create
                                                    (
                                                        DataType.UnsignedShort,
                                                        new Dictionary <int, float>
                        {
                            { 1, samplerInputSparse }
                        }
                                                    )),
                        Output = Data.Create(samplerOutputRotation),
                    };

                    var channels       = CreateChannels(nodes, sampler0, sampler1);
                    animation.Channels = channels;
                    SetAnimationPaths(channels, AnimationChannelTargetPath.Rotation, properties);

                    properties.Add(new Property(PropertyName.SparseAccessor, "Input"));
                    properties.Add(new Property(PropertyName.IndicesType, sampler1.Input.Sparse.IndicesOutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.ValueType, sampler1.Input.OutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.BufferView, ":white_check_mark:"));
                    properties.Add(new Property(PropertyName.Description, "See Figure 1"));
                }),
                CreateModel((properties, animation, nodes) =>
                {
                    SetTexture(nodes);
                    OffsetPositions(nodes);

                    var sampler0 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear),
                        Output        = Data.Create(samplerOutputRotation),
                    };

                    var sampler1 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear, DataSparse.Create
                                                    (
                                                        DataType.UnsignedInt,
                                                        new Dictionary <int, float>
                        {
                            { 1, samplerInputSparse }
                        }
                                                    )),
                        Output = Data.Create(samplerOutputRotation),
                    };

                    var channels       = CreateChannels(nodes, sampler0, sampler1);
                    animation.Channels = channels;
                    SetAnimationPaths(channels, AnimationChannelTargetPath.Rotation, properties);

                    properties.Add(new Property(PropertyName.SparseAccessor, "Input"));
                    properties.Add(new Property(PropertyName.IndicesType, sampler1.Input.Sparse.IndicesOutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.ValueType, sampler1.Input.OutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.BufferView, ":white_check_mark:"));
                    properties.Add(new Property(PropertyName.Description, "See Figure 1"));
                }),
                CreateModel((properties, animation, nodes) =>
                {
                    SetTexture(nodes);
                    OffsetPositions(nodes);

                    var sampler0 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear),
                        Output        = Data.Create(samplerOutputRotation, DataType.NormalizedByte),
                    };

                    var sampler1 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear),
                        Output        = Data.Create(samplerOutputRotation, DataType.NormalizedByte, DataSparse.Create
                                                    (
                                                        DataType.UnsignedByte,
                                                        new Dictionary <int, Quaternion>
                        {
                            { 1, samplerOutputRotationSparse }
                        }
                                                    )),
                    };

                    var channels       = CreateChannels(nodes, sampler0, sampler1);
                    animation.Channels = channels;
                    SetAnimationPaths(channels, AnimationChannelTargetPath.Rotation, properties);

                    properties.Add(new Property(PropertyName.SparseAccessor, "Output"));
                    properties.Add(new Property(PropertyName.IndicesType, ((Data <Quaternion>)sampler1.Output).Sparse.IndicesOutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.ValueType, sampler1.Output.OutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.BufferView, ":white_check_mark:"));
                    properties.Add(new Property(PropertyName.Description, "See Figure 2"));
                }),
                CreateModel((properties, animation, nodes) =>
                {
                    SetTexture(nodes);
                    OffsetPositions(nodes);

                    var sampler0 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear),
                        Output        = Data.Create(samplerOutputRotation, DataType.NormalizedShort),
                    };

                    var sampler1 = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear),
                        Output        = Data.Create(samplerOutputRotation, DataType.NormalizedShort, DataSparse.Create
                                                    (
                                                        DataType.UnsignedByte,
                                                        new Dictionary <int, Quaternion>
                        {
                            { 1, samplerOutputRotationSparse }
                        }
                                                    )),
                    };

                    var channels       = CreateChannels(nodes, sampler0, sampler1);
                    animation.Channels = channels;
                    SetAnimationPaths(channels, AnimationChannelTargetPath.Rotation, properties);

                    properties.Add(new Property(PropertyName.SparseAccessor, "Output"));
                    properties.Add(new Property(PropertyName.IndicesType, ((Data <Quaternion>)sampler1.Output).Sparse.IndicesOutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.ValueType, sampler1.Output.OutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.BufferView, ":white_check_mark:"));
                    properties.Add(new Property(PropertyName.Description, "See Figure 2"));
                }),
                CreateModel((properties, animation, nodes) =>
                {
                    // Add extra vertexes that will be used by the sparse accessor.
                    SetTexture(nodes);
                    var positions = MeshPrimitive.GetSinglePlanePositions().Concat(new[]
                    {
                        new Vector3(0.25f, -0.5f, 0.0f),
                        new Vector3(-0.25f, 0.5f, 0.0f),
                    });
                    var texCoords = MeshPrimitive.GetSinglePlaneTexCoords().Concat(new[]
                    {
                        new Vector2(1.0f, 1.0f),
                        new Vector2(0.0f, 0.0f),
                    });

                    foreach (var node in nodes)
                    {
                        node.Mesh.MeshPrimitives.First().Positions.Values  = positions;
                        node.Mesh.MeshPrimitives.First().TexCoords0.Values = texCoords;
                    }
                    OffsetPositions(nodes);

                    var meshPrimitiveIndices    = nodes[1].Mesh.MeshPrimitives.First().Indices;
                    meshPrimitiveIndices.Values = nodes[0].Mesh.MeshPrimitives.First().Indices.Values;
                    meshPrimitiveIndices.Sparse = DataSparse.Create
                                                  (
                        DataType.UnsignedByte,
                        new Dictionary <int, int>
                    {
                        { 1, 4 },
                        { 5, 5 },
                    }
                                                  );

                    properties.Add(new Property(PropertyName.SparseAccessor, "Mesh Primitive Indices"));
                    properties.Add(new Property(PropertyName.IndicesType, meshPrimitiveIndices.Sparse.IndicesOutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.ValueType, meshPrimitiveIndices.OutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.BufferView, ":white_check_mark:"));
                    properties.Add(new Property(PropertyName.Description, "See the description for the Mesh Primitive Indices model in [Accessor_Sparse](../Accessor_Sparse/README.md)."));
                }),
                CreateModel((properties, animation, nodes) =>
                {
                    SetTexture(nodes);
                    nodes.RemoveAt(0);

                    var sampler = new AnimationSampler
                    {
                        Interpolation = AnimationSamplerInterpolation.Linear,
                        Input         = Data.Create(samplerInputLinear),
                        Output        = Data.Create(Enumerable.Repeat(default(Vector3), 3), DataSparse.Create
                                                    (
                                                        DataType.UnsignedByte,
                                                        new Dictionary <int, Vector3>
                        {
                            { 1, samplerOutputTranslationSparse }
                        }
                                                    )),
                    };

                    var channels = new List <AnimationChannel>
                    {
                        new AnimationChannel
                        {
                            Target = new AnimationChannelTarget
                            {
                                Node = nodes[0],
                                Path = AnimationChannelTargetPath.Translation
                            },
                            Sampler = sampler
                        },
                    };
                    animation.Channels = channels;

                    properties.Add(new Property(PropertyName.SparseAccessor, "Output"));
                    properties.Add(new Property(PropertyName.IndicesType, ((Data <Vector3>)sampler.Output).Sparse.IndicesOutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.ValueType, ((Data <Vector3>)sampler.Output).OutputType.ToReadmeString()));
                    properties.Add(new Property(PropertyName.BufferView, ""));
                    properties.Add(new Property(PropertyName.Description, "See Figure 3"));
                }),
            };

            GenerateUsedPropertiesList();
        }
        public Buffer_Interleaved(List <string> imageList)
        {
            var baseColorTextureImage = UseTexture(imageList, "BaseColor_Grey");

            // Track the common properties for use in the readme.
            CommonProperties.Add(new Property(PropertyName.BaseColorTexture, baseColorTextureImage));

            Model CreateModel(Action <List <Property>, Runtime.MeshPrimitive> setProperties)
            {
                var properties    = new List <Property>();
                var meshPrimitive = MeshPrimitive.CreateSinglePlane();

                // Apply the common properties to the gltf.
                meshPrimitive.Interleave = true;
                meshPrimitive.Colors     = new[]
                {
                    new Vector4(0.0f, 1.0f, 0.0f, 0.2f),
                    new Vector4(1.0f, 0.0f, 0.0f, 0.2f),
                    new Vector4(1.0f, 1.0f, 0.0f, 0.2f),
                    new Vector4(0.0f, 0.0f, 1.0f, 0.2f)
                };
                meshPrimitive.Material = new Runtime.Material()
                {
                    MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness()
                    {
                        BaseColorTexture = new Runtime.Texture()
                        {
                            Source  = baseColorTextureImage,
                            Sampler = new Runtime.Sampler(),
                        },
                    },
                };

                // 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 = new[]
                        {
                            new Runtime.Node
                            {
                                Mesh = new Runtime.Mesh
                                {
                                    MeshPrimitives = new[]
                                    {
                                        meshPrimitive
                                    }
                                },
                            },
                        },
                    }),
                });
            }

            void SetUvTypeFloat(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.TextureCoordsComponentType = Runtime.MeshPrimitive.TextureCoordsComponentTypeEnum.FLOAT;
                properties.Add(new Property(PropertyName.VertexUV0, "Float"));
            }

            void SetUvTypeTypeByte(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.TextureCoordsComponentType = Runtime.MeshPrimitive.TextureCoordsComponentTypeEnum.NORMALIZED_UBYTE;
                properties.Add(new Property(PropertyName.VertexUV0, "Byte"));
            }

            void SetUvTypeTypeShort(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.TextureCoordsComponentType = Runtime.MeshPrimitive.TextureCoordsComponentTypeEnum.NORMALIZED_USHORT;
                properties.Add(new Property(PropertyName.VertexUV0, "Short"));
            }

            void SetColorTypeFloat(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.ColorComponentType = Runtime.MeshPrimitive.ColorComponentTypeEnum.FLOAT;
                meshPrimitive.ColorType          = Runtime.MeshPrimitive.ColorTypeEnum.VEC3;
                properties.Add(new Property(PropertyName.VertexColor, "Vector3 Float"));
            }

            void SetColorTypeByte(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.ColorComponentType = Runtime.MeshPrimitive.ColorComponentTypeEnum.NORMALIZED_UBYTE;
                meshPrimitive.ColorType          = Runtime.MeshPrimitive.ColorTypeEnum.VEC3;
                properties.Add(new Property(PropertyName.VertexColor, "Vector3 Byte"));
            }

            void SetColorTypeShort(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.ColorComponentType = Runtime.MeshPrimitive.ColorComponentTypeEnum.NORMALIZED_USHORT;
                meshPrimitive.ColorType          = Runtime.MeshPrimitive.ColorTypeEnum.VEC3;
                properties.Add(new Property(PropertyName.VertexColor, "Vector3 Short"));
            }

            this.Models = new List <Model>
            {
                CreateModel((properties, meshPrimitive) => {
                    SetUvTypeFloat(properties, meshPrimitive);
                    SetColorTypeFloat(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) => {
                    SetUvTypeFloat(properties, meshPrimitive);
                    SetColorTypeByte(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) => {
                    SetUvTypeFloat(properties, meshPrimitive);
                    SetColorTypeShort(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) => {
                    SetUvTypeTypeByte(properties, meshPrimitive);
                    SetColorTypeFloat(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) => {
                    SetUvTypeTypeShort(properties, meshPrimitive);
                    SetColorTypeFloat(properties, meshPrimitive);
                }),
            };

            GenerateUsedPropertiesList();
        }
Beispiel #12
0
        internal static int AddLineLoop(this Gltf gltf,
                                        string name,
                                        List <byte> buffer,
                                        List <BufferView> bufferViews,
                                        List <Accessor> accessors,
                                        byte[] vertices,
                                        byte[] indices,
                                        double[] vMin,
                                        double[] vMax,
                                        ushort iMin,
                                        ushort iMax,
                                        int materialId,
                                        MeshPrimitive.ModeEnum mode,
                                        List <glTFLoader.Schema.Mesh> meshes,
                                        List <glTFLoader.Schema.Node> nodes,
                                        Transform transform = null)
        {
            var m = new glTFLoader.Schema.Mesh();

            m.Name = name;
            var vBuff = AddBufferView(bufferViews, 0, buffer.Count, vertices.Length, null, null);
            var iBuff = AddBufferView(bufferViews, 0, buffer.Count + vertices.Length, indices.Length, null, null);

            buffer.AddRange(vertices);
            buffer.AddRange(indices);

            while (buffer.Count % 4 != 0)
            {
                // Console.WriteLine("Padding...");
                buffer.Add(0);
            }

            var vAccess = AddAccessor(accessors, vBuff, 0, Accessor.ComponentTypeEnum.FLOAT, vertices.Length / sizeof(float) / 3, new[] { (float)vMin[0], (float)vMin[1], (float)vMin[2] }, new[] { (float)vMax[0], (float)vMax[1], (float)vMax[2] }, Accessor.TypeEnum.VEC3);
            var iAccess = AddAccessor(accessors, iBuff, 0, Accessor.ComponentTypeEnum.UNSIGNED_SHORT, indices.Length / sizeof(ushort), new[] { (float)iMin }, new[] { (float)iMax }, Accessor.TypeEnum.SCALAR);

            var prim = new MeshPrimitive();

            prim.Indices    = iAccess;
            prim.Material   = materialId;
            prim.Mode       = mode;
            prim.Attributes = new Dictionary <string, int> {
                { "POSITION", vAccess }
            };

            m.Primitives = new[] { prim };

            // Add mesh to gltf
            meshes.Add(m);

            var parentId = 0;

            if (transform != null)
            {
                var a = transform.XAxis;
                var b = transform.YAxis;
                var c = transform.ZAxis;

                var transNode = new Node();

                transNode.Matrix = new[] {
                    (float)a.X, (float)a.Y, (float)a.Z, 0.0f,
                    (float)b.X, (float)b.Y, (float)b.Z, 0.0f,
                    (float)c.X, (float)c.Y, (float)c.Z, 0.0f,
                    (float)transform.Origin.X, (float)transform.Origin.Y, (float)transform.Origin.Z, 1.0f
                };

                parentId = gltf.AddNode(nodes, transNode, 0);
            }

            // Add mesh node to gltf
            var node = new Node();

            node.Mesh = meshes.Count - 1;
            gltf.AddNode(nodes, node, parentId);

            return(meshes.Count - 1);
        }
Beispiel #13
0
        internal static int AddTriangleMesh(this Gltf gltf,
                                            string name,
                                            List <byte> buffer,
                                            List <BufferView> bufferViews,
                                            List <Accessor> accessors,
                                            byte[] vertices,
                                            byte[] normals,
                                            byte[] indices,
                                            byte[] colors,
                                            byte[] uvs,
                                            double[] vMin,
                                            double[] vMax,
                                            double[] nMin,
                                            double[] nMax,
                                            ushort iMin,
                                            ushort iMax,
                                            double[] uvMin,
                                            double[] uvMax,
                                            int materialId,
                                            float[] cMin,
                                            float[] cMax,
                                            int?parent_index,
                                            List <glTFLoader.Schema.Mesh> meshes)
        {
            var m = new glTFLoader.Schema.Mesh();

            m.Name = name;

            var vBuff = AddBufferView(bufferViews, 0, buffer.Count, vertices.Length, null, null);

            buffer.AddRange(vertices);

            var nBuff = AddBufferView(bufferViews, 0, buffer.Count, normals.Length, null, null);

            buffer.AddRange(normals);

            var iBuff = AddBufferView(bufferViews, 0, buffer.Count, indices.Length, null, null);

            buffer.AddRange(indices);

            while (buffer.Count % 4 != 0)
            {
                // Console.WriteLine("Padding...");
                buffer.Add(0);
            }

            var vAccess = AddAccessor(accessors, vBuff, 0, Accessor.ComponentTypeEnum.FLOAT, vertices.Length / sizeof(float) / 3, new[] { (float)vMin[0], (float)vMin[1], (float)vMin[2] }, new[] { (float)vMax[0], (float)vMax[1], (float)vMax[2] }, Accessor.TypeEnum.VEC3);
            var nAccess = AddAccessor(accessors, nBuff, 0, Accessor.ComponentTypeEnum.FLOAT, normals.Length / sizeof(float) / 3, new[] { (float)nMin[0], (float)nMin[1], (float)nMin[2] }, new[] { (float)nMax[0], (float)nMax[1], (float)nMax[2] }, Accessor.TypeEnum.VEC3);
            var iAccess = AddAccessor(accessors, iBuff, 0, Accessor.ComponentTypeEnum.UNSIGNED_SHORT, indices.Length / sizeof(ushort), new[] { (float)iMin }, new[] { (float)iMax }, Accessor.TypeEnum.SCALAR);

            var prim = new MeshPrimitive();

            prim.Indices    = iAccess;
            prim.Material   = materialId;
            prim.Mode       = MeshPrimitive.ModeEnum.TRIANGLES;
            prim.Attributes = new Dictionary <string, int> {
                { "NORMAL", nAccess },
                { "POSITION", vAccess }
            };

            if (uvs.Length > 0)
            {
                var uvBuff = AddBufferView(bufferViews, 0, buffer.Count, uvs.Length, null, null);
                buffer.AddRange(uvs);
                var uvAccess = AddAccessor(accessors, uvBuff, 0, Accessor.ComponentTypeEnum.FLOAT, uvs.Length / sizeof(float) / 2, new[] { (float)uvMin[0], (float)uvMin[1] }, new[] { (float)uvMax[0], (float)uvMax[1] }, Accessor.TypeEnum.VEC2);
                prim.Attributes.Add("TEXCOORD_0", uvAccess);
            }

            // TODO: Add to the buffer above instead of inside this block.
            // There's a chance the padding operation will put padding before
            // the color information.
            if (colors.Length > 0)
            {
                var cBuff = AddBufferView(bufferViews, 0, buffer.Count, colors.Length, null, null);
                buffer.AddRange(colors);
                var cAccess = AddAccessor(accessors, cBuff, 0, Accessor.ComponentTypeEnum.FLOAT, colors.Length / sizeof(float) / 3, cMin, cMax, Accessor.TypeEnum.VEC3);
                prim.Attributes.Add("COLOR_0", cAccess);
            }

            m.Primitives = new[] { prim };

            // Add mesh to gltf
            meshes.Add(m);

            return(meshes.Count - 1);
        }
Beispiel #14
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();
        }
Beispiel #15
0
        public Mesh_PrimitivesUV(List <string> imageList)
        {
            Runtime.Image baseColorTextureImage = UseTexture(imageList, "BaseColor_Plane");
            Runtime.Image normalImage           = UseTexture(imageList, "Normal_Plane");
            UseFigure(imageList, "Indices_Primitive0");
            UseFigure(imageList, "Indices_Primitive1");
            UseFigure(imageList, "UVSpace2");
            UseFigure(imageList, "UVSpace3");
            UseFigure(imageList, "UVSpace4");
            UseFigure(imageList, "UVSpace5");

            // Track the common properties for use in the readme.
            var vertexNormalValue = new List <Vector3>
            {
                new Vector3(0.0f, 0.0f, 1.0f),
                new Vector3(0.0f, 0.0f, 1.0f),
                new Vector3(0.0f, 0.0f, 1.0f),
            };
            var tangentValue = new List <Vector4>
            {
                new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
                new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
                new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
            };
            var vertexColorValue = new List <Vector4>
            {
                new Vector4(0.0f, 1.0f, 0.0f, 0.2f),
                new Vector4(1.0f, 0.0f, 0.0f, 0.2f),
                new Vector4(0.0f, 0.0f, 1.0f, 0.2f),
            };

            CommonProperties.Add(new Property(PropertyName.VertexNormal, vertexNormalValue.ToReadmeString()));
            CommonProperties.Add(new Property(PropertyName.VertexTangent, tangentValue.ToReadmeString()));
            CommonProperties.Add(new Property(PropertyName.VertexColor, vertexColorValue.ToReadmeString()));
            CommonProperties.Add(new Property(PropertyName.NormalTexture, normalImage.ToReadmeString()));
            CommonProperties.Add(new Property(PropertyName.BaseColorTexture, baseColorTextureImage.ToReadmeString()));

            Model CreateModel(Action <List <Property>, Runtime.MeshPrimitive, Runtime.MeshPrimitive> setProperties)
            {
                var properties = new List <Property>();
                List <Runtime.MeshPrimitive> meshPrimitives = MeshPrimitive.CreateMultiPrimitivePlane();

                // Apply the common properties to the gltf.
                foreach (var meshPrimitive in meshPrimitives)
                {
                    meshPrimitive.TextureCoordSets = new List <List <Vector2> >();
                    meshPrimitive.Material         = new Runtime.Material
                    {
                        MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness
                        {
                            MetallicFactor = 0
                        }
                    };
                }

                // Apply the properties that are specific to this gltf.
                setProperties(properties, meshPrimitives[0], meshPrimitives[1]);

                // Create the gltf object
                return(new Model
                {
                    Properties = properties,
                    GLTF = CreateGLTF(() => new Runtime.Scene
                    {
                        Nodes = new List <Runtime.Node>
                        {
                            new Runtime.Node
                            {
                                Mesh = new Runtime.Mesh
                                {
                                    MeshPrimitives = meshPrimitives
                                },
                            },
                        },
                    }),
                });
            }

            void SetCommonProperties(Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.Normals  = vertexNormalValue;
                meshPrimitive.Tangents = tangentValue;
                meshPrimitive.Colors   = vertexColorValue;
                meshPrimitive.Material.NormalTexture = new Runtime.Texture {
                    Source = normalImage
                };
                meshPrimitive.Material.MetallicRoughnessMaterial.BaseColorTexture = new Runtime.Texture()
                {
                    Source = baseColorTextureImage
                };
            }

            void SetNullUV(Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.Material         = null;
                meshPrimitive.TextureCoordSets = null;
            }

            void SetPrimitiveZeroVertexUVZero(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                SetCommonProperties(meshPrimitive);
                meshPrimitive.TextureCoordSets = meshPrimitive.TextureCoordSets.Concat(
                    new[]
                {
                    new[]
                    {
                        new Vector2(0.0f, 1.0f),
                        new Vector2(1.0f, 0.0f),
                        new Vector2(0.0f, 0.0f),
                    }
                });
                properties.Add(new Property(PropertyName.Primitive0VertexUV0, ":white_check_mark:"));
            }

            void SetPrimitiveOneVertexUVZero(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                SetCommonProperties(meshPrimitive);
                meshPrimitive.TextureCoordSets = meshPrimitive.TextureCoordSets.Concat(
                    new[]
                {
                    new[]
                    {
                        new Vector2(0.0f, 1.0f),
                        new Vector2(1.0f, 1.0f),
                        new Vector2(1.0f, 0.0f),
                    }
                });
                properties.Add(new Property(PropertyName.Primitive1VertexUV0, ":white_check_mark:"));
            }

            void SetPrimitiveZeroVertexUVOne(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                SetCommonProperties(meshPrimitive);
                meshPrimitive.Material.MetallicRoughnessMaterial.BaseColorTexture.TexCoordIndex = 1;
                meshPrimitive.Material.NormalTexture.TexCoordIndex = 1;
                meshPrimitive.TextureCoordSets = meshPrimitive.TextureCoordSets.Concat(
                    new[]
                {
                    new[]
                    {
                        new Vector2(0.5f, 0.5f),
                        new Vector2(1.0f, 0.0f),
                        new Vector2(0.5f, 0.0f),
                    }
                });
                properties.Add(new Property(PropertyName.Primitive0VertexUV1, ":white_check_mark:"));
            }

            void SetPrimitiveOneVertexUVOne(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                SetCommonProperties(meshPrimitive);
                meshPrimitive.Material.MetallicRoughnessMaterial.BaseColorTexture.TexCoordIndex = 1;
                meshPrimitive.Material.NormalTexture.TexCoordIndex = 1;
                meshPrimitive.TextureCoordSets = meshPrimitive.TextureCoordSets.Concat(
                    new[]
                {
                    new[]
                    {
                        new Vector2(0.5f, 0.5f),
                        new Vector2(1.0f, 0.5f),
                        new Vector2(1.0f, 0.0f),
                    }
                });
                properties.Add(new Property(PropertyName.Primitive1VertexUV1, ":white_check_mark:"));
            }

            Models = new List <Model>
            {
                CreateModel((properties, meshPrimitiveZero, meshPrimitiveOne) =>
                {
                    SetNullUV(meshPrimitiveZero);
                    SetNullUV(meshPrimitiveOne);
                }),
                CreateModel((properties, meshPrimitiveZero, meshPrimitiveOne) =>
                {
                    SetPrimitiveZeroVertexUVZero(properties, meshPrimitiveZero);
                    SetNullUV(meshPrimitiveOne);
                }),
                CreateModel((properties, meshPrimitiveZero, meshPrimitiveOne) =>
                {
                    SetPrimitiveOneVertexUVZero(properties, meshPrimitiveOne);
                    SetNullUV(meshPrimitiveZero);
                }),
                CreateModel((properties, meshPrimitiveZero, meshPrimitiveOne) =>
                {
                    SetPrimitiveZeroVertexUVZero(properties, meshPrimitiveZero);
                    SetPrimitiveOneVertexUVZero(properties, meshPrimitiveOne);
                }),
                CreateModel((properties, meshPrimitiveZero, meshPrimitiveOne) =>
                {
                    SetPrimitiveZeroVertexUVZero(properties, meshPrimitiveZero);
                    SetPrimitiveZeroVertexUVOne(properties, meshPrimitiveZero);
                    SetNullUV(meshPrimitiveOne);
                }),
                CreateModel((properties, meshPrimitiveZero, meshPrimitiveOne) =>
                {
                    SetPrimitiveOneVertexUVZero(properties, meshPrimitiveOne);
                    SetPrimitiveOneVertexUVOne(properties, meshPrimitiveOne);
                    SetNullUV(meshPrimitiveZero);
                }),
                CreateModel((properties, meshPrimitiveZero, meshPrimitiveOne) =>
                {
                    SetPrimitiveZeroVertexUVZero(properties, meshPrimitiveZero);
                    SetPrimitiveOneVertexUVZero(properties, meshPrimitiveOne);
                    SetPrimitiveOneVertexUVOne(properties, meshPrimitiveOne);
                }),
                CreateModel((properties, meshPrimitiveZero, meshPrimitiveOne) =>
                {
                    SetPrimitiveZeroVertexUVZero(properties, meshPrimitiveZero);
                    SetPrimitiveOneVertexUVZero(properties, meshPrimitiveOne);
                    SetPrimitiveZeroVertexUVOne(properties, meshPrimitiveZero);
                }),
                CreateModel((properties, meshPrimitiveZero, meshPrimitiveOne) =>
                {
                    SetPrimitiveZeroVertexUVZero(properties, meshPrimitiveZero);
                    SetPrimitiveOneVertexUVZero(properties, meshPrimitiveOne);
                    SetPrimitiveZeroVertexUVOne(properties, meshPrimitiveZero);
                    SetPrimitiveOneVertexUVOne(properties, meshPrimitiveOne);
                }),
            };

            GenerateUsedPropertiesList();
        }
Beispiel #16
0
        public MeshPrimitive GenerateTriangleMesh(List <Vector3> positions, List <int> indices, IEnumerable <Vector4> colors = null, PBRTexture texture = null)
        {
            MeshPrimitive mesh = null;

            try
            {
                if (positions == null || !positions.Any())
                {
                    _logger?.LogWarning("Vertex list is empty.");
                }
                else
                {
                    if (colors == null)
                    {
                        colors = positions.Select(pt => Vector4.One);
                    }

                    // Basic mesh declaration
                    mesh = new MeshPrimitive()
                    {
                        Colors = colors
                        ,
                        ColorComponentType = MeshPrimitive.ColorComponentTypeEnum.FLOAT
                        ,
                        ColorType = MeshPrimitive.ColorTypeEnum.VEC3
                        ,
                        Mode = MeshPrimitive.ModeEnum.TRIANGLES
                        ,
                        Positions = positions
                        ,
                        Material = new Material()
                        {
                            DoubleSided = true
                        }
                        ,
                        Indices = indices
                    };


                    //The number of the vertices
                    int nV = positions.Count;
                    //The number of the triangles
                    int       nT   = indices.Count / 3;
                    Vector3[] norm = new Vector3[nV]; //Array for the normals
                                                      //Scan all the triangles. For each triangle add its
                                                      //normal to norm's vectors of triangle's vertices
                    Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
                    Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
                    for (int t = 0; t < nT; t++)
                    {
                        //Get indices of the triangle t
                        int i1 = indices[3 * t];
                        int i2 = indices[3 * t + 1];
                        int i3 = indices[3 * t + 2];
                        //Get vertices of the triangle
                        Vector3 v1 = positions[i1];
                        Vector3 v2 = positions[i2];
                        Vector3 v3 = positions[i3];

                        //Compute the triangle's normal
                        Vector3 dir = Vector3.Normalize(Vector3.Cross(v2 - v1, v3 - v1));
                        //Accumulate it to norm array for i1, i2, i3
                        norm[i1] += dir;
                        norm[i2] += dir;
                        norm[i3] += dir;
                    }

                    for (int i = 0; i < nV; i++)
                    {
                        //Normalize the normal's length
                        norm[i] = Vector3.Normalize(norm[i]);

                        // Calculate bounds of UV mapping
                        Vector3 pos = positions[i];

                        // for UV coords
                        min.X = Math.Min(pos.X, min.X);
                        min.Y = Math.Min(pos.Y, min.Y);
                        min.Z = Math.Min(pos.Z, min.Z);

                        max.X = Math.Max(pos.X, max.X);
                        max.Y = Math.Max(pos.Y, max.Y);
                        max.Z = Math.Max(pos.Z, max.Z);
                    }
                    mesh.Normals = norm;

                    if (texture != null)
                    {
                        mesh.TextureCoordsComponentType = MeshPrimitive.TextureCoordsComponentTypeEnum.FLOAT;
                        if (texture.TextureCoordSets == null)
                        {
                            mesh.TextureCoordSets = Enumerable.Range(0, 1).Select(i => positions.Select(pos => new Vector2(
                                                                                                            MathHelper.Map(min.X, max.X, 0, 1, pos.X, true)
                                                                                                            , MathHelper.Map(min.Z, max.Z, 0, 1, pos.Z, true)
                                                                                                            )));
                        }
                        else
                        {
                            mesh.TextureCoordSets = Enumerable.Range(0, 1).Select(i => texture.TextureCoordSets);
                        }
                        mesh.Material.MetallicRoughnessMaterial = new PbrMetallicRoughness()
                        {
                            BaseColorFactor  = Vector4.One,
                            BaseColorTexture = GetTextureFromImage(texture.BaseColorTexture.FilePath),
                            MetallicFactor   = 0,
                            RoughnessFactor  = 1
                        };
                        if (texture.NormalTexture != null)
                        {
                            mesh.Material.NormalTexture = GetTextureFromImage(texture.NormalTexture.FilePath);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, ex.ToString());
                throw;
            }
            return(mesh);
        }
        protected virtual void CreateMeshPrimitive(MeshPrimitive primitive, string meshName, int meshID, int primitiveIndex)
        {
            var meshAttributes = BuildMeshAttributes(primitive, meshID, primitiveIndex);
            var vertexCount    = primitive.Attributes[SemanticProperties.POSITION].Value.Count;

            UnityEngine.Mesh mesh = new UnityEngine.Mesh
            {
                vertices = primitive.Attributes.ContainsKey(SemanticProperties.POSITION)
                                        ? meshAttributes[SemanticProperties.POSITION].AccessorContent.AsVertices.ToUnityVector3()
                                        : null,
                normals = primitive.Attributes.ContainsKey(SemanticProperties.NORMAL)
                                        ? meshAttributes[SemanticProperties.NORMAL].AccessorContent.AsNormals.ToUnityVector3()
                                        : null,

                uv = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(0))
                                        ? meshAttributes[SemanticProperties.TexCoord(0)].AccessorContent.AsTexcoords.ToUnityVector2()
                                        : null,

                uv2 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(1))
                                        ? meshAttributes[SemanticProperties.TexCoord(1)].AccessorContent.AsTexcoords.ToUnityVector2()
                                        : null,

                uv3 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(2))
                                        ? meshAttributes[SemanticProperties.TexCoord(2)].AccessorContent.AsTexcoords.ToUnityVector2()
                                        : null,

                uv4 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(3))
                                        ? meshAttributes[SemanticProperties.TexCoord(3)].AccessorContent.AsTexcoords.ToUnityVector2()
                                        : null,

                colors = primitive.Attributes.ContainsKey(SemanticProperties.Color(0))
                                        ? meshAttributes[SemanticProperties.Color(0)].AccessorContent.AsColors.ToUnityColor()
                                        : null,

                triangles = primitive.Indices != null
                                        ? meshAttributes[SemanticProperties.INDICES].AccessorContent.AsTriangles
                                        : MeshPrimitive.GenerateTriangles(vertexCount),

                tangents = primitive.Attributes.ContainsKey(SemanticProperties.TANGENT)
                                        ? meshAttributes[SemanticProperties.TANGENT].AccessorContent.AsTangents.ToUnityVector4(true)
                                        : null
            };

            if (primitive.Attributes.ContainsKey(SemanticProperties.JOINT) && primitive.Attributes.ContainsKey(SemanticProperties.WEIGHT))
            {
                Vector4[] bones   = new Vector4[1];
                Vector4[] weights = new Vector4[1];

                LoadSkinnedMeshAttributes(meshID, primitiveIndex, ref bones, ref weights);
                if (bones.Length != mesh.vertices.Length || weights.Length != mesh.vertices.Length)
                {
                    Debug.LogError("Not enough skinning data (bones:" + bones.Length + " weights:" + weights.Length + "  verts:" + mesh.vertices.Length + ")");
                    return;
                }

                BoneWeight[] bws           = new BoneWeight[mesh.vertices.Length];
                int          maxBonesIndex = 0;
                for (int i = 0; i < bws.Length; ++i)
                {
                    // Unity seems expects the the sum of weights to be 1.
                    float[] normalizedWeights = GLTFUtils.normalizeBoneWeights(weights[i]);

                    bws[i].boneIndex0 = (int)bones[i].x;
                    bws[i].weight0    = normalizedWeights[0];

                    bws[i].boneIndex1 = (int)bones[i].y;
                    bws[i].weight1    = normalizedWeights[1];

                    bws[i].boneIndex2 = (int)bones[i].z;
                    bws[i].weight2    = normalizedWeights[2];

                    bws[i].boneIndex3 = (int)bones[i].w;
                    bws[i].weight3    = normalizedWeights[3];

                    maxBonesIndex = (int)Mathf.Max(maxBonesIndex, bones[i].x, bones[i].y, bones[i].z, bones[i].w);
                }

                mesh.boneWeights = bws;

                // initialize inverseBindMatrix array with identity matrix in order to output a valid mesh object
                Matrix4x4[] bindposes = new Matrix4x4[maxBonesIndex + 1];
                for (int j = 0; j <= maxBonesIndex; ++j)
                {
                    bindposes[j] = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one);
                }
                mesh.bindposes = bindposes;
            }

            if (primitive.Targets != null && primitive.Targets.Count > 0)
            {
                for (int b = 0; b < primitive.Targets.Count; ++b)
                {
                    Vector3[] deltaVertices = new Vector3[primitive.Targets[b]["POSITION"].Value.Count];
                    Vector3[] deltaNormals  = new Vector3[primitive.Targets[b]["POSITION"].Value.Count];
                    Vector3[] deltaTangents = new Vector3[primitive.Targets[b]["POSITION"].Value.Count];

                    if (primitive.Targets[b].ContainsKey("POSITION"))
                    {
                        NumericArray num = new NumericArray();
                        deltaVertices = primitive.Targets[b]["POSITION"].Value.AsVector3Array(ref num, _assetCache.BufferCache[0], false).ToUnityVector3(true);
                    }
                    if (primitive.Targets[b].ContainsKey("NORMAL"))
                    {
                        NumericArray num = new NumericArray();
                        deltaNormals = primitive.Targets[b]["NORMAL"].Value.AsVector3Array(ref num, _assetCache.BufferCache[0], true).ToUnityVector3(true);
                    }
                    //if (primitive.Targets[b].ContainsKey("TANGENT"))
                    //{
                    //	deltaTangents = primitive.Targets[b]["TANGENT"].Value.AsVector3Array(ref num, _assetCache.BufferCache[0], true).ToUnityVector3(true);
                    //}

                    mesh.AddBlendShapeFrame(GLTFUtils.buildBlendShapeName(meshID, b), 1.0f, deltaVertices, deltaNormals, deltaTangents);
                }
            }

            mesh.RecalculateBounds();
            mesh.RecalculateTangents();
            mesh = _assetManager.saveMesh(mesh, meshName + "_" + meshID + "_" + primitiveIndex);
            UnityEngine.Material material = primitive.Material != null && primitive.Material.Id >= 0 ? getMaterial(primitive.Material.Id) : defaultMaterial;

            _assetManager.addPrimitiveMeshData(meshID, primitiveIndex, mesh, material);
        }
Beispiel #18
0
        public Buffer_Misc(List <string> imageList)
        {
            Model CreateModel(Action <List <Property>, AnimationChannel, Node> setProperties)
            {
                var properties = new List <Property>();

                // Apply the common properties to the glTF.
                var node = new Node
                {
                    Mesh = new Runtime.Mesh
                    {
                        MeshPrimitives = new[]
                        {
                            MeshPrimitive.CreateSinglePlane(includeTextureCoords: false)
                        }
                    },
                    Scale = new Vector3(0.8f)
                };

                var channel = new AnimationChannel();

                // Apply the proerties that are specific to this glTF
                setProperties(properties, channel, node);

                // Create the glTF object
                GLTF gltf = CreateGLTF(() => new Scene
                {
                    Nodes = new[]
                    {
                        node
                    },
                });

                gltf.Animations = new[]
                {
                    new Animation
                    {
                        Channels = new List <AnimationChannel>
                        {
                            channel
                        }
                    }
                };

                return(new Model
                {
                    Properties = properties,
                    GLTF = gltf,
                    Animated = true,
                    SeparateBuffers = true,
                });
            }

            void setTranslationChanneltarget(AnimationChannel channel, Node node)
            {
                channel.Target = new AnimationChannelTarget
                {
                    Node = node,
                    Path = AnimationChannelTargetPath.Translation,
                };
            }

            void SetLinearSamplerForTranslation(AnimationChannel channel)
            {
                channel.Sampler = new AnimationSampler
                {
                    Interpolation = AnimationSamplerInterpolation.Linear,
                    Input         = Data.Create(new[]
                    {
                        0.0f,
                        2.0f,
                        4.0f,
                    }),
                    Output = Data.Create(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),
                    }),
                };
            }

            Models = new List <Model>
            {
                CreateModel((properties, channel, node) =>
                {
                    setTranslationChanneltarget(channel, node);
                    SetLinearSamplerForTranslation(channel);
                    properties.Add(new Property(PropertyName.Description, "The mesh primitive and animation data are stored in separate buffers."));
                })
            };

            GenerateUsedPropertiesList();
        }
Beispiel #19
0
        public Mesh_PrimitiveAttribute(List <string> imageList)
        {
            var baseColorTexture = new Texture {
                Source = UseTexture(imageList, "BaseColor_Plane")
            };
            var normalTexture = new Texture {
                Source = UseTexture(imageList, "Normal_Plane")
            };

            // Track the common properties for use in the readme.
            CommonProperties.Add(new Property(PropertyName.BaseColorTexture, baseColorTexture.Source.ToReadmeString()));

            Model CreateModel(Action <List <Property>, Runtime.MeshPrimitive> setProperties)
            {
                var properties    = new List <Property>();
                var meshPrimitive = MeshPrimitive.CreateSinglePlane();

                meshPrimitive.Material = new Runtime.Material();

                // Apply the common properties to the gltf.
                meshPrimitive.Material.PbrMetallicRoughness = new PbrMetallicRoughness
                {
                    BaseColorTexture = new TextureInfo {
                        Texture = baseColorTexture
                    },
                };

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

                // Create the gltf object.
                return(new Model
                {
                    Properties = properties,
                    GLTF = CreateGLTF(() => new Scene
                    {
                        Nodes = new List <Node>
                        {
                            new Node
                            {
                                Mesh = new Runtime.Mesh
                                {
                                    MeshPrimitives = new List <Runtime.MeshPrimitive>
                                    {
                                        meshPrimitive
                                    }
                                },
                            },
                        },
                    }),
                });
            }

            void SetVertexUVFloat(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.TexCoords0.OutputType = DataType.Float;
                properties.Add(new Property(PropertyName.VertexUV0, meshPrimitive.TexCoords0.OutputType.ToReadmeString()));
            }

            void SetVertexUVByte(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.TexCoords0.OutputType = DataType.NormalizedUnsignedByte;
                properties.Add(new Property(PropertyName.VertexUV0, meshPrimitive.TexCoords0.OutputType.ToReadmeString()));
            }

            void SetVertexUVShort(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.TexCoords0.OutputType = DataType.NormalizedUnsignedShort;
                properties.Add(new Property(PropertyName.VertexUV0, meshPrimitive.TexCoords0.OutputType.ToReadmeString()));
            }

            void SetVertexNormal(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                var normals = MeshPrimitive.GetSinglePlaneNormals();

                meshPrimitive.Normals = Data.Create(normals);
                properties.Add(new Property(PropertyName.VertexNormal, normals.ToReadmeString()));
            }

            void SetVertexTangent(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                var tangents = new[]
                {
                    new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
                    new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
                    new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
                    new Vector4(1.0f, 0.0f, 0.0f, 1.0f)
                };

                meshPrimitive.Tangents = Data.Create(tangents);
                properties.Add(new Property(PropertyName.VertexTangent, tangents.ToReadmeString()));
            }

            void SetNormalTexture(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.Material.NormalTexture = new NormalTextureInfo {
                    Texture = normalTexture
                };
                properties.Add(new Property(PropertyName.NormalTexture, normalTexture.Source.ToReadmeString()));
            }

            Models = new List <Model>
            {
                CreateModel((properties, meshPrimitive) =>
                {
                    SetVertexUVFloat(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    SetVertexUVByte(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    SetVertexUVShort(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    SetVertexUVFloat(properties, meshPrimitive);
                    SetVertexNormal(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    SetVertexUVFloat(properties, meshPrimitive);
                    SetNormalTexture(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    SetVertexUVFloat(properties, meshPrimitive);
                    SetVertexNormal(properties, meshPrimitive);
                    SetNormalTexture(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    SetVertexUVFloat(properties, meshPrimitive);
                    SetVertexNormal(properties, meshPrimitive);
                    SetVertexTangent(properties, meshPrimitive);
                    SetNormalTexture(properties, meshPrimitive);
                }),
            };

            GenerateUsedPropertiesList();
        }
        /// <inheritdoc/>
        public override Material CreateMaterialForPrimitive(ContentManager contentManager, MeshPrimitive primitive)
        {
            Contract.Require(contentManager, nameof(contentManager));
            Contract.Require(primitive, nameof(primitive));

            return(new SkinnedMaterial
            {
                Alpha = GetMaterialAlpha(primitive.Material),
                DiffuseColor = GetMaterialDiffuseColor(primitive.Material),
                SpecularPower = GetMaterialSpecularPower(primitive.Material),
                SpecularColor = GetMaterialSpecularColor(primitive.Material),
                EmissiveColor = GetMaterialEmissiveColor(primitive.Material),
                Texture = GetMaterialTexture(contentManager, primitive.Material) ?? GetBlankTexture(),
            });
        }
        protected virtual void BuildMeshAttributes(MeshPrimitive primitive, int meshID, int primitiveIndex)
        {
            if (_assetCache.MeshCache[meshID][primitiveIndex].MeshAttributes.Count == 0)
            {
                Dictionary <string, AttributeAccessor> attributeAccessors = new Dictionary <string, AttributeAccessor>(primitive.Attributes.Count + 1);
                foreach (var attributePair in primitive.Attributes)
                {
                    AttributeAccessor AttributeAccessor = new AttributeAccessor()
                    {
                        AccessorId = attributePair.Value,
                        Buffer     = _assetCache.BufferCache[attributePair.Value.Value.BufferView.Value.Buffer.Id]
                    };

                    attributeAccessors[attributePair.Key] = AttributeAccessor;
                }

                if (primitive.Indices != null)
                {
                    AttributeAccessor indexBuilder = new AttributeAccessor()
                    {
                        AccessorId = primitive.Indices,
                        Buffer     = _assetCache.BufferCache[primitive.Indices.Value.BufferView.Value.Buffer.Id]
                    };

                    attributeAccessors[SemanticProperties.INDICES] = indexBuilder;
                }

                GLTFHelpers.BuildMeshAttributes(ref attributeAccessors);

                // Flip vectors and triangles to the Unity coordinate system.
                if (attributeAccessors.ContainsKey(SemanticProperties.POSITION))
                {
                    NumericArray resultArray = attributeAccessors[SemanticProperties.POSITION].AccessorContent;
                    resultArray.AsVertices = GLTFUnityHelpers.FlipVectorArrayHandedness(resultArray.AsVertices);
                    attributeAccessors[SemanticProperties.POSITION].AccessorContent = resultArray;
                }
                if (attributeAccessors.ContainsKey(SemanticProperties.INDICES))
                {
                    NumericArray resultArray = attributeAccessors[SemanticProperties.INDICES].AccessorContent;
                    resultArray.AsTriangles = GLTFUnityHelpers.FlipFaces(resultArray.AsTriangles);
                    attributeAccessors[SemanticProperties.INDICES].AccessorContent = resultArray;
                }
                if (attributeAccessors.ContainsKey(SemanticProperties.NORMAL))
                {
                    NumericArray resultArray = attributeAccessors[SemanticProperties.NORMAL].AccessorContent;
                    resultArray.AsNormals = GLTFUnityHelpers.FlipVectorArrayHandedness(resultArray.AsNormals);
                    attributeAccessors[SemanticProperties.NORMAL].AccessorContent = resultArray;
                }
                // TexCoord goes from 0 to 3 to match GLTFHelpers.BuildMeshAttributes
                for (int i = 0; i < 4; i++)
                {
                    if (attributeAccessors.ContainsKey(SemanticProperties.TexCoord(i)))
                    {
                        NumericArray resultArray = attributeAccessors[SemanticProperties.TexCoord(i)].AccessorContent;
                        resultArray.AsTexcoords = GLTFUnityHelpers.FlipTexCoordArrayV(resultArray.AsTexcoords);
                        attributeAccessors[SemanticProperties.TexCoord(i)].AccessorContent = resultArray;
                    }
                }
                if (attributeAccessors.ContainsKey(SemanticProperties.TANGENT))
                {
                    NumericArray resultArray = attributeAccessors[SemanticProperties.TANGENT].AccessorContent;
                    resultArray.AsTangents = GLTFUnityHelpers.FlipVectorArrayHandedness(resultArray.AsTangents);
                    attributeAccessors[SemanticProperties.TANGENT].AccessorContent = resultArray;
                }

                _assetCache.MeshCache[meshID][primitiveIndex].MeshAttributes = attributeAccessors;
            }
        }
Beispiel #22
0
        public Compatibility(List <string> imageList)
        {
            NoSampleImages = true;

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

            Model CreateModel(Action <List <Property>, Asset, List <string>, List <string>, Runtime.MeshPrimitive> setProperties,
                              Action <Schema.Gltf> postRuntimeChanges = null, Dictionary <Type, Type> schemaTypeMapping = null, bool?setLoadableTag = true)
            {
                var properties = new List <Property>();

                var gltf = CreateGLTF(() => new Scene());

                Runtime.MeshPrimitive meshPrimitive = MeshPrimitive.CreateSinglePlane(includeTextureCoords: false);
                var extensionsUsed     = new List <string>();
                var extensionsRequired = new List <string>();

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

                // Create the gltf object.
                if (extensionsUsed.Any())
                {
                    gltf.ExtensionsUsed = extensionsUsed;
                }
                if (extensionsRequired.Any())
                {
                    gltf.ExtensionsRequired = extensionsRequired;
                }

                gltf.Scenes.First().Nodes = new List <Node>
                {
                    new Node
                    {
                        Mesh = new Runtime.Mesh
                        {
                            MeshPrimitives = new List <Runtime.MeshPrimitive>
                            {
                                meshPrimitive
                            }
                        },
                    },
                };

                var model = new Model
                {
                    Properties = properties,
                    GLTF       = gltf
                };

                model.Loadable           = setLoadableTag;
                model.PostRuntimeChanges = postRuntimeChanges;

                if (schemaTypeMapping != null)
                {
                    model.CreateSchemaInstance = type =>
                    {
                        if (schemaTypeMapping.TryGetValue(type, out Type mappedType))
                        {
                            type = mappedType;
                        }

                        return(Activator.CreateInstance(type));
                    };
                }

                return(model);
            }

            Property SetMinVersion(Asset asset)
            {
                return(new Property(PropertyName.MinVersion, asset.MinVersion = "2.1"));
            }

            Property SetVersionCurrent(Asset asset)
            {
                return(new Property(PropertyName.Version, asset.Version = "2.0"));
            }

            Property SetVersionFuture(Asset asset)
            {
                return(new Property(PropertyName.Version, asset.Version = "2.1"));
            }

            void SetPostRuntimeAtRoot(Schema.Gltf gltf)
            {
                // Add an simulated feature at the root level.
                var experimentalGltf = (ExperimentalGltf)gltf;

                experimentalGltf.Lights = new[]
                {
                    new ExperimentalLight
                    {
                        Color = new[] { 0.3f, 0.4f, 0.5f }
                    }
                };
            }

            void SetPostRuntimeInProperty(Schema.Gltf gltf)
            {
                // Add an simulated feature into an existing property.
                var experimentalNode = (ExperimentalNode)gltf.Nodes[0];

                experimentalNode.Light = 0;
            }

            void SetPostRuntimeWithFallback(Schema.Gltf gltf)
            {
                // Add an simulated feature with a fallback option.
                gltf.Materials = new Schema.Material[]
                {
                    new ExperimentalMaterial
                    {
                        AlphaMode  = Schema.Material.AlphaModeEnum.BLEND,
                        AlphaMode2 = ExperimentalAlphaMode2.QUANTUM,
                    }
                };
            }

            var experimentalSchemaTypeMapping = new Dictionary <Type, Type>
            {
                { typeof(Schema.Gltf), typeof(ExperimentalGltf) },
                { typeof(Schema.Node), typeof(ExperimentalNode) },
                { typeof(Schema.Material), typeof(ExperimentalMaterial) },
            };

            var shouldLoad = ":white_check_mark:";

            Models = new List <Model>
            {
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionCurrent(asset));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, shouldLoad));
                }),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionFuture(asset));
                    properties.Add(new Property(PropertyName.Description, "Light object added at root"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, shouldLoad));
                }, SetPostRuntimeAtRoot, experimentalSchemaTypeMapping),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionFuture(asset));
                    properties.Add(new Property(PropertyName.Description, "Light property added to node object"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, shouldLoad));
                }, SetPostRuntimeInProperty, experimentalSchemaTypeMapping),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionFuture(asset));
                    properties.Add(new Property(PropertyName.Description, "Alpha mode updated with a new enum value, and a fallback value"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, shouldLoad));
                }, SetPostRuntimeWithFallback, experimentalSchemaTypeMapping),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetMinVersion(asset));
                    properties.Add(SetVersionFuture(asset));
                    properties.Add(new Property(PropertyName.Description, "Requires a specific version or higher"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, "Only in version 2.1 or higher"));
                }, null, null, setLoadableTag: false),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionCurrent(asset));

                    var emptyTexture = new Texture();
                    var extension    = new FAKE_materials_quantumRendering
                    {
                        PlanckFactor      = new Vector4(0.2f, 0.2f, 0.2f, 0.8f),
                        CopenhagenTexture = new TextureInfo
                        {
                            Texture = emptyTexture
                        },
                        EntanglementFactor           = new Vector3(0.4f, 0.4f, 0.4f),
                        ProbabilisticFactor          = 0.3f,
                        SuperpositionCollapseTexture = new TextureInfo
                        {
                            Texture = emptyTexture
                        },
                    };

                    meshPrimitive.Material = new Runtime.Material
                    {
                        Extensions = new List <Extension>
                        {
                            extension
                        }
                    };

                    extensionsUsed.Add(extension.Name);
                    extensionsRequired.Add(extension.Name);

                    properties.Add(new Property(PropertyName.Description, "Extension required"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, ":x:"));
                }, null, null, setLoadableTag: false),
                CreateModel((properties, asset, extensionsUsed, extensionsRequired, meshPrimitive) =>
                {
                    properties.Add(SetVersionCurrent(asset));

                    var extension = new KHR_materials_pbrSpecularGlossiness
                    {
                        SpecularFactor   = new Vector3(0.04f, 0.04f, 0.04f),
                        GlossinessFactor = 0.0f,
                    };

                    meshPrimitive.Material = new Runtime.Material
                    {
                        // Metallic-Roughness
                        PbrMetallicRoughness = new PbrMetallicRoughness
                        {
                            MetallicFactor = 0.0f
                        },
                        // Specular-Glossiness
                        Extensions = new[] { extension },
                    };

                    extensionsUsed.Add(extension.Name);

                    properties.Add(new Property(PropertyName.Description, "Specular Glossiness extension used but not required"));
                    properties.Add(new Property(PropertyName.ModelShouldLoad, shouldLoad));
                }),
            };

            GenerateUsedPropertiesList();
        }
Beispiel #23
0
        // a mesh *might* decode to multiple prims if there are submeshes
        private MeshPrimitive[] ExportPrimitive(GameObject gameObject)
        {
            var filter  = gameObject.GetComponent <MeshFilter>();
            var meshObj = filter.sharedMesh;

            var renderer     = gameObject.GetComponent <MeshRenderer>();
            var materialsObj = renderer.sharedMaterials;

            var prims = new MeshPrimitive[meshObj.subMeshCount];

            // don't export any more accessors if this mesh is already exported
            MeshPrimitive[] primVariations;
            if (_meshToPrims.TryGetValue(meshObj, out primVariations) &&
                meshObj.subMeshCount == primVariations.Length)
            {
                for (var i = 0; i < primVariations.Length; i++)
                {
                    prims[i]          = primVariations[i].Clone();
                    prims[i].Material = ExportMaterial(materialsObj[i]);
                }

                return(prims);
            }

            AccessorId aPosition = null, aNormal = null, aTangent = null,
                       aTexcoord0 = null, aTexcoord1 = null, aColor0 = null;

            aPosition = ExportAccessor(InvertZ(meshObj.vertices));

            if (meshObj.normals.Length != 0)
            {
                aNormal = ExportAccessor(InvertZ(meshObj.normals));
            }

            if (meshObj.tangents.Length != 0)
            {
                aTangent = ExportAccessor(InvertW(meshObj.tangents));
            }

            if (meshObj.uv.Length != 0)
            {
                aTexcoord0 = ExportAccessor(InvertY(meshObj.uv));
            }

            if (meshObj.uv2.Length != 0)
            {
                aTexcoord1 = ExportAccessor(InvertY(meshObj.uv2));
            }

            if (meshObj.colors.Length != 0)
            {
                aColor0 = ExportAccessor(meshObj.colors);
            }

            MaterialId lastMaterialId = null;

            for (var submesh = 0; submesh < meshObj.subMeshCount; submesh++)
            {
                var primitive = new MeshPrimitive();

                var triangles = meshObj.GetTriangles(submesh);
                primitive.Indices = ExportAccessor(FlipFaces(triangles), true);

                primitive.Attributes = new Dictionary <string, AccessorId>();
                primitive.Attributes.Add(SemanticProperties.POSITION, aPosition);

                if (aNormal != null)
                {
                    primitive.Attributes.Add(SemanticProperties.NORMAL, aNormal);
                }
                if (aTangent != null)
                {
                    primitive.Attributes.Add(SemanticProperties.TANGENT, aTangent);
                }
                if (aTexcoord0 != null)
                {
                    primitive.Attributes.Add(SemanticProperties.TexCoord(0), aTexcoord0);
                }
                if (aTexcoord1 != null)
                {
                    primitive.Attributes.Add(SemanticProperties.TexCoord(1), aTexcoord1);
                }
                if (aColor0 != null)
                {
                    primitive.Attributes.Add(SemanticProperties.Color(0), aColor0);
                }

                if (submesh < materialsObj.Length)
                {
                    primitive.Material = ExportMaterial(materialsObj[submesh]);
                    lastMaterialId     = primitive.Material;
                }
                else
                {
                    primitive.Material = lastMaterialId;
                }

                prims[submesh] = primitive;
            }

            _meshToPrims[meshObj] = prims;

            return(prims);
        }
Beispiel #24
0
        public PrimitiveDemo(Layer layer) : base(layer)
        {
            // Primitives can only be drawn from instances. There are no static methods.
            _trianglefan          = new TriangleFanPrimitive();
            _trianglefan.Vertices = new List <Vertex>
            {
                new Vertex(new Vector2(0, 0)),
                new Vertex(new Vector2(16, 0)),
                new Vertex(new Vector2(40, 10)),
                new Vertex(new Vector2(64, 64)),
                new Vertex(new Vector2(0, 32)),
            };


            _trianglestrip          = new TriangleStripPrimitive();
            _trianglestrip.Vertices = new List <Vertex>
            {
                new Vertex(new Vector2(0, 0), _mainColor),
                new Vertex(new Vector2(32, 32), _secondaryColor),
                new Vertex(new Vector2(64, 0), _secondaryColor2),
                new Vertex(new Vector2(96, 32), _secondaryColor),
                new Vertex(new Vector2(64 + 32, 0), _secondaryColor2),
                new Vertex(new Vector2(96 + 32, 32), _secondaryColor),
                new Vertex(new Vector2(64 + 64, 0), _secondaryColor2),
                new Vertex(new Vector2(96 + 64, 32), _mainColor),
            };

            _mesh          = new MeshPrimitive(16, 16);
            _mesh.Position = new Vector2(0, 100);

            // You can set the texture for a primitive. Preferrably it shouldn't be in texture atlas.
            // If in atlas, textures wouldn't be able to repeat.
            _mesh.SetTextureFromFrame(Default.AutismCat[0]);
            _mesh.Vertices = new List <Vertex>(8 * 8);

            for (var k = 0; k < _mesh.Height; k += 1)
            {
                for (var i = 0; i < _mesh.Width; i += 1)
                {
                    _mesh.Vertices.Add(
                        new Vertex(
                            Vector2.Zero,                             // Positions will be set later.
                            Color.White,
                            new Vector2(i / (float)(_mesh.Width - 1), k / (float)(_mesh.Height - 1)) * _meshRepeat
                            )
                        );
                }
            }


            _linestrip = new LineStripPrimitive();

            _linestrip.Vertices = new List <Vertex>();

            for (var i = 0; i < 16; i += 1)
            {
                _linestrip.Vertices.Add(new Vertex(Vector2.Zero, new Color(16 * i, 8 * i, 4 * i)));
            }


            // You can make your own custom primitives.
            // CustomTrianglePrimitive and CustomLinePrimitive give you
            // access to the index array. Index array tells inwhat order vertices should be drawn.
            // One vertex can be used multiple times in an index array.
            _custom          = new CustomTrianglePrimitive();
            _custom.Vertices = new List <Vertex>()
            {
                new Vertex(new Vector2(0, 0), Color.Green),
                new Vertex(new Vector2(32, 0)),
                new Vertex(new Vector2(32, 32)),
                new Vertex(new Vector2(64, 32), Color.Blue),
            };
            _custom.Indices = new short[] { 0, 1, 2, 1, 3, 2 };
        }
 private void ExportComponentMaterial(SeinCustomMaterial material, MeshPrimitive primitive, ExporterEntry entry)
 {
     primitive.Material = entry.SaveComponentMaterial(material);
 }
Beispiel #26
0
 /// <summary>
 /// Creates a new <see cref="Material"/> instance for the specified primitve.
 /// </summary>
 /// <param name="contentManager">The content manager with which the model is being loaded.</param>
 /// <param name="primitive">The <see cref="MeshPrimitive"/> for which to create a material.</param>
 /// <returns>The <see cref="Material"/> instance which was created.</returns>
 public abstract Material CreateMaterialForPrimitive(ContentManager contentManager, MeshPrimitive primitive);
Beispiel #27
0
        internal static int AddTriangleMesh(this Gltf gltf, string name, List <byte> buffer, double[] vertices, double[] normals, ushort[] indices, float[] colors,
                                            double[] vMin, double[] vMax, double[] nMin, double[] nMax, ushort iMin, ushort iMax, int materialId, float[] cMin, float[] cMax, int?parent_index, Transform transform = null)
        {
            var m = new glTFLoader.Schema.Mesh();

            m.Name = name;

            var vBuff = gltf.AddBufferView(0, buffer.Count, vertices.Length * sizeof(float), null, null);
            var nBuff = gltf.AddBufferView(0, buffer.Count + vertices.Length * sizeof(float), normals.Length * sizeof(float), null, null);
            var iBuff = gltf.AddBufferView(0, buffer.Count + vertices.Length * sizeof(float) + normals.Length * sizeof(float), indices.Length * sizeof(ushort), null, null);

            foreach (var v in vertices)
            {
                buffer.AddRange(BitConverter.GetBytes((float)v));
            }
            foreach (var n in normals)
            {
                buffer.AddRange(BitConverter.GetBytes((float)n));
            }
            foreach (var i in indices)
            {
                buffer.AddRange(BitConverter.GetBytes(i));
            }

            while (buffer.Count % 4 != 0)
            {
                // Console.WriteLine("Padding...");
                buffer.Add(0);
            }

            var vAccess = gltf.AddAccessor(vBuff, 0, Accessor.ComponentTypeEnum.FLOAT, vertices.Length / 3, new[] { (float)vMin[0], (float)vMin[1], (float)vMin[2] }, new[] { (float)vMax[0], (float)vMax[1], (float)vMax[2] }, Accessor.TypeEnum.VEC3);
            var nAccess = gltf.AddAccessor(nBuff, 0, Accessor.ComponentTypeEnum.FLOAT, normals.Length / 3, new[] { (float)nMin[0], (float)nMin[1], (float)nMin[2] }, new[] { (float)nMax[0], (float)nMax[1], (float)nMax[2] }, Accessor.TypeEnum.VEC3);
            var iAccess = gltf.AddAccessor(iBuff, 0, Accessor.ComponentTypeEnum.UNSIGNED_SHORT, indices.Length, new[] { (float)iMin }, new[] { (float)iMax }, Accessor.TypeEnum.SCALAR);

            var prim = new MeshPrimitive();

            prim.Indices    = iAccess;
            prim.Material   = materialId;
            prim.Mode       = MeshPrimitive.ModeEnum.TRIANGLES;
            prim.Attributes = new Dictionary <string, int> {
                { "NORMAL", nAccess },
                { "POSITION", vAccess }
            };

            // TODO: Add to the buffer above instead of inside this block.
            // There's a chance the padding operation will put padding before
            // the color information.
            if (colors.Length > 0)
            {
                var cBuff = gltf.AddBufferView(0, buffer.Count, colors.Length * sizeof(float), null, null);

                foreach (var c in colors)
                {
                    buffer.AddRange(BitConverter.GetBytes((float)c));
                }

                var cAccess = gltf.AddAccessor(cBuff, 0, Accessor.ComponentTypeEnum.FLOAT, colors.Length / 3, cMin, cMax, Accessor.TypeEnum.VEC3);
                prim.Attributes.Add("COLOR_0", cAccess);
            }

            m.Primitives = new[] { prim };

            // Add mesh to gltf
            if (gltf.Meshes != null)
            {
                // TODO: Get rid of this resizing.
                var meshes = gltf.Meshes.ToList();
                meshes.Add(m);
                gltf.Meshes = meshes.ToArray();
            }
            else
            {
                gltf.Meshes = new[] { m };
            }

            var parentId = 0;

            if (transform != null)
            {
                var a = transform.XAxis;
                var b = transform.YAxis;
                var c = transform.ZAxis;

                var transNode = new Node();

                transNode.Matrix = new[] {
                    (float)a.X, (float)a.Y, (float)a.Z, 0.0f,
                    (float)b.X, (float)b.Y, (float)b.Z, 0.0f,
                    (float)c.X, (float)c.Y, (float)c.Z, 0.0f,
                    (float)transform.Origin.X, (float)transform.Origin.Y, (float)transform.Origin.Z, 1.0f
                };

                parentId = gltf.AddNode(transNode, 0);
            }
            // Add mesh node to gltf
            var node = new Node();

            node.Mesh = gltf.Meshes.Length - 1;
            gltf.AddNode(node, parentId);

            return(gltf.Meshes.Length - 1);
        }
Beispiel #28
0
        public Material_DoubleSided(List <string> imageList)
        {
            Runtime.Image baseColorTextureImage = UseTexture(imageList, "BaseColor_Plane");
            Runtime.Image normalImage           = UseTexture(imageList, "Normal_Plane");

            // Track the common properties for use in the readme.
            var doubleSidedValue = true;

            CommonProperties.Add(new Property(PropertyName.DoubleSided, doubleSidedValue.ToString()));
            CommonProperties.Add(new Property(PropertyName.BaseColorTexture, baseColorTextureImage.ToReadmeString()));

            Model CreateModel(Action <List <Property>, Runtime.MeshPrimitive> setProperties)
            {
                var properties    = new List <Property>();
                var meshPrimitive = MeshPrimitive.CreateSinglePlane();

                meshPrimitive.Material = new Runtime.Material();
                meshPrimitive.Material.MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness();

                // Apply the common properties to the gltf.
                meshPrimitive.Material.DoubleSided = doubleSidedValue;
                meshPrimitive.Material.MetallicRoughnessMaterial.BaseColorTexture = new Runtime.Texture {
                    Source = baseColorTextureImage
                };

                // 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 = new List <Runtime.Node>
                        {
                            new Runtime.Node
                            {
                                Mesh = new Runtime.Mesh
                                {
                                    MeshPrimitives = new List <Runtime.MeshPrimitive>
                                    {
                                        meshPrimitive
                                    }
                                },
                            },
                        },
                    }),
                });
            }

            void SetVertexNormal(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                var planeNormalsValue = MeshPrimitive.GetSinglePlaneNormals();

                meshPrimitive.Normals = planeNormalsValue;
                properties.Add(new Property(PropertyName.VertexNormal, planeNormalsValue.ToReadmeString()));
            }

            void SetVertexTangent(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                var planeTangentValue = MeshPrimitive.GetSinglePlaneTangents();

                meshPrimitive.Tangents = planeTangentValue;
                properties.Add(new Property(PropertyName.VertexTangent, planeTangentValue.ToReadmeString()));
            }

            void SetNormalTexture(List <Property> properties, Runtime.MeshPrimitive meshPrimitive)
            {
                meshPrimitive.Material.NormalTexture = new Runtime.Texture {
                    Source = normalImage
                };
                properties.Add(new Property(PropertyName.NormalTexture, normalImage.ToReadmeString()));
            }

            Models = new List <Model>
            {
                CreateModel((properties, meshPrimitive) =>
                {
                    // There are no properties set on this model.
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    SetVertexNormal(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    SetVertexNormal(properties, meshPrimitive);
                    SetNormalTexture(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    SetVertexNormal(properties, meshPrimitive);
                    SetVertexTangent(properties, meshPrimitive);
                    SetNormalTexture(properties, meshPrimitive);
                }),
                CreateModel((properties, meshPrimitive) =>
                {
                    SetNormalTexture(properties, meshPrimitive);
                }),
            };

            GenerateUsedPropertiesList();
        }
        public Material_Mixed(List <string> imageList)
        {
            Runtime.Image baseColorTextureImage = UseTexture(imageList, "BaseColor_X");
            UseFigure(imageList, "UVSpace2");
            UseFigure(imageList, "UVSpace3");

            // Track the common properties for use in the readme.
            CommonProperties.Add(new Property(PropertyName.ExtensionUsed, "Specular Glossiness"));
            CommonProperties.Add(new Property(PropertyName.BaseColorTexture, baseColorTextureImage));

            Model CreateModel(Action <List <Property>, Runtime.Material, Runtime.Material> setProperties)
            {
                var properties       = new List <Property>();
                var meshPrimitives   = MeshPrimitive.CreateMultiPrimitivePlane();
                var baseColorTexture = new Runtime.Texture {
                    Source = baseColorTextureImage
                };

                meshPrimitives[0].Material = new Runtime.Material();
                meshPrimitives[0].Material.MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness();
                meshPrimitives[1].Material = new Runtime.Material();
                meshPrimitives[1].Material.MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness();

                // Apply the common properties to the gltf.
                meshPrimitives[0].Material.MetallicRoughnessMaterial.BaseColorTexture = baseColorTexture;
                meshPrimitives[1].Material.MetallicRoughnessMaterial.BaseColorTexture = baseColorTexture;

                // Apply the properties that are specific to this gltf.
                setProperties(properties, meshPrimitives[0].Material, meshPrimitives[1].Material);

                // Create the gltf object.
                return(new Model
                {
                    Properties = properties,
                    GLTF = CreateGLTF(() => new Runtime.Scene()
                    {
                        Nodes = new[]
                        {
                            new Runtime.Node
                            {
                                Mesh = new Runtime.Mesh
                                {
                                    MeshPrimitives = meshPrimitives
                                },
                            },
                        },
                    }, extensionsUsed: new List <string>()
                    {
                        "KHR_materials_pbrSpecularGlossiness"
                    }),
                });
            }

            void SetSpecularGlossiness0(List <Property> properties, Runtime.Material material0)
            {
                material0.Extensions = new List <Runtime.Extensions.Extension>()
                {
                    new Runtime.Extensions.KHR_materials_pbrSpecularGlossiness()
                };
                properties.Add(new Property(PropertyName.SpecularGlossinessOnMaterial0, ":white_check_mark:"));
            }

            void SetSpecularGlossiness1(List <Property> properties, Runtime.Material material1)
            {
                material1.Extensions = new List <Runtime.Extensions.Extension>()
                {
                    new Runtime.Extensions.KHR_materials_pbrSpecularGlossiness()
                };
                properties.Add(new Property(PropertyName.SpecularGlossinessOnMaterial1, ":white_check_mark:"));
            }

            void NoSpecularGlossiness0(List <Property> properties)
            {
                properties.Add(new Property(PropertyName.SpecularGlossinessOnMaterial0, ":x:"));
            }

            void NoSpecularGlossiness1(List <Property> properties)
            {
                properties.Add(new Property(PropertyName.SpecularGlossinessOnMaterial1, ":x:"));
            }

            Models = new List <Model>
            {
                CreateModel((properties, material0, material1) => {
                    SetSpecularGlossiness0(properties, material0);
                    SetSpecularGlossiness1(properties, material1);
                }),
                CreateModel((properties, material0, material1) => {
                    NoSpecularGlossiness0(properties);
                    NoSpecularGlossiness1(properties);
                }),
                CreateModel((properties, material0, material1) => {
                    SetSpecularGlossiness0(properties, material0);
                    NoSpecularGlossiness1(properties);
                }),
            };

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

            // Track the common properties for use in the readme.
            var alphaModeValue = AlphaModeEnum.MASK;

            CommonProperties.Add(new Property(PropertyName.AlphaMode, alphaModeValue));
            CommonProperties.Add(new Property(PropertyName.BaseColorTexture, baseColorTextureImage));

            Model CreateModel(Action <List <Property>, Runtime.Material, Runtime.PbrMetallicRoughness> setProperties)
            {
                var properties    = new List <Property>();
                var meshPrimitive = MeshPrimitive.CreateSinglePlane();

                meshPrimitive.Material = new Runtime.Material();
                meshPrimitive.Material.MetallicRoughnessMaterial = new Runtime.PbrMetallicRoughness();

                // Apply the common properties to the gltf.
                meshPrimitive.Material.AlphaMode = alphaModeValue;
                meshPrimitive.Material.MetallicRoughnessMaterial.BaseColorTexture = new Runtime.Texture {
                    Source = baseColorTextureImage
                };

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

                // Create the gltf object.
                return(new Model
                {
                    Properties = properties,
                    GLTF = CreateGLTF(() => new Runtime.Scene()
                    {
                        Nodes = new[]
                        {
                            new Runtime.Node
                            {
                                Mesh = new Runtime.Mesh
                                {
                                    MeshPrimitives = new List <Runtime.MeshPrimitive>
                                    {
                                        meshPrimitive
                                    }
                                },
                            },
                        },
                    }),
                });
            }

            void SetAlphaCutoff_Low(List <Property> properties, Runtime.Material material)
            {
                material.AlphaCutoff = 0.4f;
                properties.Add(new Property(PropertyName.AlphaCutoff, material.AlphaCutoff));
            }

            void SetAlphaCutoff_High(List <Property> properties, Runtime.Material material)
            {
                material.AlphaCutoff = 0.7f;
                properties.Add(new Property(PropertyName.AlphaCutoff, material.AlphaCutoff));
            }

            void SetAlphaCutoff_Multiplied(List <Property> properties, Runtime.Material material)
            {
                material.AlphaCutoff = 0.6f;
                properties.Add(new Property(PropertyName.AlphaCutoff, material.AlphaCutoff));
            }

            void SetAlphaCutoff_All(List <Property> properties, Runtime.Material material)
            {
                material.AlphaCutoff = 1.1f;
                properties.Add(new Property(PropertyName.AlphaCutoff, material.AlphaCutoff));
            }

            void SetAlphaCutoff_None(List <Property> properties, Runtime.Material material)
            {
                material.AlphaCutoff = 0.0f;
                properties.Add(new Property(PropertyName.AlphaCutoff, material.AlphaCutoff));
            }

            void SetBaseColorFactor(List <Property> properties, Runtime.PbrMetallicRoughness metallicRoughness)
            {
                var baseColorFactorValue = new Vector4(1.0f, 1.0f, 1.0f, 0.7f);

                metallicRoughness.BaseColorFactor = baseColorFactorValue;
                properties.Add(new Property(PropertyName.BaseColorFactor, baseColorFactorValue));
            }

            Models = new List <Model>
            {
                CreateModel((properties, material, metallicRoughness) => {
                    // There are no properties set on this model.
                }),
                CreateModel((properties, material, metallicRoughness) => {
                    SetAlphaCutoff_Low(properties, material);
                }),
                CreateModel((properties, material, metallicRoughness) => {
                    SetAlphaCutoff_High(properties, material);
                }),
                CreateModel((properties, material, metallicRoughness) => {
                    SetAlphaCutoff_All(properties, material);
                }),
                CreateModel((properties, material, metallicRoughness) => {
                    SetAlphaCutoff_None(properties, material);
                }),
                CreateModel((properties, material, metallicRoughness) => {
                    SetAlphaCutoff_Low(properties, material);
                    SetBaseColorFactor(properties, metallicRoughness);
                }),
                CreateModel((properties, material, metallicRoughness) => {
                    SetAlphaCutoff_Multiplied(properties, material);
                    SetBaseColorFactor(properties, metallicRoughness);
                }),
            };

            GenerateUsedPropertiesList();
        }