Exemple #1
0
        public static void AttachToCurrentTest <TvG, TvM, TvS>(this Geometry.MeshBuilder <TvG, TvM, TvS> mesh, string fileName)
            where TvG : struct, Geometry.VertexTypes.IVertexGeometry
            where TvM : struct, Geometry.VertexTypes.IVertexMaterial
            where TvS : struct, Geometry.VertexTypes.IVertexSkinning
        {
            var gl2model = ModelRoot.CreateModel();

            var gl2mesh = gl2model.CreateMeshes(mesh).First();

            var node = gl2model.UseScene(0).CreateNode();

            node.Mesh = gl2mesh;

            gl2model.AttachToCurrentTest(fileName);
        }
Exemple #2
0
        public void CreateTextureTriangleScene()
        {
            TestContext.CurrentContext.AttachShowDirLink();
            TestContext.CurrentContext.AttachGltfValidatorLink();

            // we'll use our icon as the source texture
            var imagePath = System.IO.Path.Combine(TestContext.CurrentContext.WorkDirectory, "..\\..\\..\\..\\..\\build\\Icons\\glTF2Sharp.png");

            // create a basic scene
            var model = ModelRoot.CreateModel();
            var scene = model.UseScene("Default");
            var rnode = scene.CreateNode("Triangle Node");
            var rmesh = rnode.Mesh = model.CreateMesh("Triangle Mesh");

            var material = model.CreateMaterial("Default")
                           .WithPBRMetallicRoughness(Vector4.One, imagePath)
                           .WithDoubleSide(true);

            // define the triangle positions
            var positions = new[]
            {
                new Vector3(0, 10, 0),
                new Vector3(-10, -10, 0),
                new Vector3(10, -10, 0)
            };

            // define the triangle UV coordinates
            var texCoords = new[]
            {
                new Vector2(0.5f, -0.8f),
                new Vector2(-0.5f, 1.2f),
                new Vector2(1.5f, 1.2f)
            };

            // create a mesh primitive and assgin the accessors and other properties
            var primitive = rmesh.CreatePrimitive()
                            .WithVertexAccessor("POSITION", positions)
                            .WithVertexAccessor("TEXCOORD_0", texCoords)
                            .WithIndicesAutomatic(PrimitiveType.TRIANGLES)
                            .WithMaterial(material);

            model.AttachToCurrentTest("result.glb");
            model.AttachToCurrentTest("result.obj");
            model.AttachToCurrentTest("result.gltf");

            material.FindChannel("BaseColor").SetTransform(0, Vector2.Zero, Vector2.One, 1.5f);
            model.AttachToCurrentTest("result_withTransform.glb");
        }
        public void CreateSceneWithAnimatedVisibility()
        {
            TestContext.CurrentContext.AttachShowDirLink();
            TestContext.CurrentContext.AttachGltfValidatorLinks();

            // create a mesh
            var cube = new MeshBuilder <VPOSNRM>("cube");

            cube.VertexPreprocessor.SetDebugPreprocessors();
            cube.AddCube(MaterialBuilder.CreateDefault(), Matrix4x4.Identity);
            cube.Validate();

            // create a new gltf model
            var model = ModelRoot.CreateModel();

            // add all meshes (just one in this case) to the model
            model.CreateMeshes(cube);

            var flatx = new Vector3(0, 1, 1);
            var flaty = new Vector3(1, 0, 1);
            var flatz = new Vector3(1, 1, 0);

            // create a scene, a node, and assign the first mesh (the terrain)
            model.UseScene("Default")
            .CreateNode()
            .WithMesh(model.LogicalMeshes[0])
            .WithScaleAnimation("SimulatedVisibility"
                                , (0, Vector3.One)
                                , (1 - 0.0001f, Vector3.One)
                                , (1, Vector3.Zero)
                                , (2 - 0.0001f, Vector3.Zero)
                                , (2, Vector3.One)
                                , (3, Vector3.One)
                                , (4, -Vector3.One)
                                , (5, -Vector3.One)
                                , (6, Vector3.One)
                                , (7, flatx)
                                , (8, flatx)
                                , (9, flaty)
                                , (10, flaty)
                                , (11, flatz)
                                , (12, flatz)
                                , (13, Vector3.One)
                                );

            // save the model as GLB
            model.AttachToCurrentTest("animatedvisibility.glb");
        }
        /// <summary>
        /// Converts this <see cref="SceneBuilder"/> instance into a <see cref="ModelRoot"/> instance.
        /// </summary>
        /// <param name="useStridedBuffers">True to generate strided vertex buffers whenever possible.</param>
        /// <returns>A new <see cref="ModelRoot"/> instance.</returns>
        public ModelRoot ToSchema2(bool useStridedBuffers = true)
        {
            var context = new Schema2SceneBuilder();

            var dstModel = ModelRoot.CreateModel();

            context.AddGeometryResources(dstModel, new[] { this }, useStridedBuffers);

            var dstScene = dstModel.UseScene(0);

            dstScene.Name = this.Name;

            context.AddScene(dstScene, this);

            return(dstModel);
        }
Exemple #5
0
        public bool Start()
        {
            Debug.Print("Start");

            _material = new MaterialBuilder()
                        .WithDoubleSide(true)
                        .WithMetallicRoughnessShader()
                        .WithChannelParam("BaseColor", new Vector4(0.5f, 0.5f, 0.5f, 1));
            _material.UseChannel("MetallicRoughness");

            _materials.Add("Default", _material);

            _model = ModelRoot.CreateModel();
            _scene = _model.UseScene("Default");

            return(true);
        }
        /// <summary>
        /// Export a Valve VMESH to Gltf.
        /// </summary>
        /// <param name="resourceName">The name of the resource being exported.</param>
        /// <param name="fileName">Target file name.</param>
        /// <param name="mesh">The mesh resource to export.</param>
        public void ExportToFile(string resourceName, string fileName, VMesh mesh)
        {
            var exportedModel = ModelRoot.CreateModel();

            exportedModel.Asset.Generator = GENERATOR;
            var name  = Path.GetFileName(resourceName);
            var scene = exportedModel.UseScene(name);

            var exportedMesh = CreateGltfMesh(name, mesh, exportedModel, false);
            var meshNode     = scene.CreateNode(name)
                               .WithMesh(exportedMesh);

            // Swap Rotate upright, scale inches to meters.
            meshNode.WorldMatrix = TRANSFORMSOURCETOGLTF;

            exportedModel.Save(fileName);
        }
Exemple #7
0
        public static ModelRoot ToGLTF(this Papa papa)
        {
            ModelRoot root     = ModelRoot.CreateModel();
            Scene     scene    = root.UseScene("default");
            Node      rootNode = scene
                                 .CreateNode()
                                 .WithLocalRotation(Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), (float)(-90 * (Math.PI / 180))));

            foreach (PapaModel papaModel in papa.Models)
            {
                Node modelNode = rootNode
                                 .CreateNode();

                // Skinned model
                if (papaModel.Skeleton != null)
                {
                    List <(Node, Matrix4x4)> skeleton = CreateSkeleton(modelNode, papaModel.Skeleton);

                    foreach (PapaMeshBinding meshBinding in papaModel.MeshBindings)
                    {
                        modelNode
                        .CreateNode(papaModel.Name)
                        .WithSkinnedMesh(root.CreateMesh(BuildSkinnedMesh(meshBinding)), skeleton.ToArray());
                    }

                    if (papa.Animations.Count != 0)
                    {
                        CreateAnimations(root, skeleton, papa.Animations);
                    }
                }
                else
                {
                    foreach (PapaMeshBinding meshBinding in papaModel.MeshBindings)
                    {
                        var meshBuilder = BuildMesh(meshBinding);

                        modelNode
                        .CreateNode(meshBinding.Name)
                        .WithMesh(root.CreateMesh(meshBuilder));
                    }
                }
            }

            return(root);
        }
        public void CreateSceneWithTerrain()
        {
            TestContext.CurrentContext.AttachShowDirLink();
            TestContext.CurrentContext.AttachGltfValidatorLinks();

            // texture path
            var imagePath = System.IO.Path.Combine(TestContext.CurrentContext.WorkDirectory, "Assets", "Texture1.jpg");

            // fancy height function; can be easily replaced with a bitmap sampler.
            float heightFunction(int xx, int yy)
            {
                float x = xx;
                float y = yy;

                double h = 0;

                h += Math.Sin(x / 45);
                h += Math.Sin(3 + x / 13) * 0.5f;

                h += Math.Sin(2 + y / 31);
                h += Math.Sin(y / 13) * 0.5f;

                h += Math.Sin((x + y * 2) / 19);

                h *= 5;

                return((float)h);
            }

            var terrain = SolidMeshUtils.CreateTerrainMesh(128, 128, heightFunction, imagePath);

            // create a new gltf model
            var model = ModelRoot.CreateModel();

            // add all meshes (just one in this case) to the model
            model.CreateMeshes(terrain);

            // create a scene, a node, and assign the first mesh (the terrain)
            model.UseScene("Default")
            .CreateNode().WithMesh(model.LogicalMeshes[0]);

            // save the model as GLB
            model.AttachToCurrentTest("terrain.glb");
            model.AttachToCurrentTest("result.plotly");
        }
        /// <summary>
        /// Converts this <see cref="SceneBuilder"/> instance into a <see cref="ModelRoot"/> instance.
        /// </summary>
        /// <param name="useStridedBuffers">True to generate strided vertex buffers whenever possible.</param>
        /// <returns>A new <see cref="ModelRoot"/> instance.</returns>
        public ModelRoot ToGltf2(SceneBuilderSchema2Settings settings)
        {
            var context = new Schema2SceneBuilder();

            var dstModel = ModelRoot.CreateModel();

            context.AddGeometryResources(dstModel, new[] { this }, settings);

            var dstScene = dstModel.UseScene(0);

            dstScene.Name = this.Name;

            context.AddScene(dstScene, this);

            dstModel.DefaultScene = dstScene;

            return(dstModel);
        }
Exemple #10
0
        static void Main(string[] args)
        {
            var material = new MaterialBuilder("material1").WithUnlitShader();

            var mesh = VERTEX.CreateCompatibleMesh("points");

            // create a point cloud primitive
            var pointCloud = mesh.UsePrimitive(material, 1);

            var galaxy = new Galaxy();

            galaxy.scaleOverPlane = 0.05f;
            galaxy.randomJitter   = 0.01f;
            foreach (var startPoint in galaxy.CreateStarts(50000))
            {
                pointCloud.AddPoint((startPoint, Vector4.One));
            }

            galaxy.scaleOverPlane = 0.15f;
            galaxy.randomJitter   = 0.02f;
            foreach (var startPoint in galaxy.CreateStarts(50000))
            {
                pointCloud.AddPoint((startPoint, new Vector4(0.4f, 0.8f, 0.7f, 1)));
            }

            galaxy.randomJitter = 0.07f;
            foreach (var startPoint in galaxy.CreateStarts(10000))
            {
                pointCloud.AddPoint((startPoint, new Vector4(0.2f, 0.6f, 0.5f, 1)));
            }

            // create a new gltf model
            var model = ModelRoot.CreateModel();

            // add all meshes (just one in this case) to the model
            model.CreateMeshes(mesh);

            // create a scene, a node, and assign the first mesh (the terrain)
            model.UseScene("Default")
            .CreateNode().WithMesh(model.LogicalMeshes[0]);

            // save the model as GLB
            model.SaveGLB("Galaxy.glb");
        }
Exemple #11
0
        public void CreateSceneWithWithLightsExtension()
        {
            TestContext.CurrentContext.AttachGltfValidatorLinks();

            var root  = ModelRoot.CreateModel();
            var scene = root.UseScene("Empty Scene");

            scene.CreateNode()
            .PunctualLight = root.CreatePunctualLight(PunctualLightType.Directional)
                             .WithColor(Vector3.UnitX, 2);

            scene.CreateNode()
            .PunctualLight = root.CreatePunctualLight(PunctualLightType.Spot)
                             .WithColor(Vector3.UnitY, 3, 10)
                             .WithSpotCone(0.2f, 0.3f);

            root.AttachToCurrentTest("sceneWithLight.gltf");
            root.AttachToCurrentTest("sceneWithLight.glb");
        }
Exemple #12
0
        public void CreateSolidTriangleScene()
        {
            TestContext.CurrentContext.AttachShowDirLink();
            TestContext.CurrentContext.AttachGltfValidatorLink();

            // create model
            var model = ModelRoot.CreateModel();

            // create scene
            var scene = model.DefaultScene = model.UseScene("Default");

            // create node
            var rnode = scene.CreateNode("Triangle Node");

            // create material
            var material = model.CreateMaterial("Default")
                           .WithDefault(new Vector4(0, 1, 0, 1))
                           .WithDoubleSide(true);

            // create mesh
            var rmesh = rnode.Mesh = model.CreateMesh("Triangle Mesh");

            // create the vertex positions
            var positions = new[]
            {
                new Vector3(0, 10, 0),
                new Vector3(-10, -10, 0),
                new Vector3(10, -10, 0),
            };

            // create an index buffer and fill it
            var indices = new[] { 0, 1, 2 };

            // create mesh primitive
            var primitive = rmesh.CreatePrimitive()
                            .WithVertexAccessor("POSITION", positions)
                            .WithIndicesAccessor(PrimitiveType.TRIANGLES, indices)
                            .WithMaterial(material);

            model.AttachToCurrentTest("result.glb");
            model.AttachToCurrentTest("result.gltf");
        }
Exemple #13
0
        public void CreateFallbackMaterialScene()
        {
            TestContext.CurrentContext.AttachShowDirLink();
            TestContext.CurrentContext.AttachGltfValidatorLink();

            var basePath = System.IO.Path.Combine(TestContext.CurrentContext.WorkDirectory, "glTF-Sample-Models", "2.0", "SpecGlossVsMetalRough", "glTF");

            // first, create a default material
            var material = new Materials.MaterialBuilder("material1 fallback")
                           .WithMetallicRoughnessShader()
                           .WithChannelImage(Materials.KnownChannels.Normal, System.IO.Path.Combine(basePath, "WaterBottle_normal.png"))
                           .WithChannelImage(Materials.KnownChannels.Emissive, System.IO.Path.Combine(basePath, "WaterBottle_emissive.png"))
                           .WithChannelImage(Materials.KnownChannels.Occlusion, System.IO.Path.Combine(basePath, "WaterBottle_occlusion.png"))
                           .WithChannelImage(Materials.KnownChannels.BaseColor, System.IO.Path.Combine(basePath, "WaterBottle_baseColor.png"))
                           .WithChannelImage(Materials.KnownChannels.MetallicRoughness, System.IO.Path.Combine(basePath, "WaterBottle_roughnessMetallic.png"));

            // wrap the fallback material with a PBR Specular Glossiness material.
            material = new Materials.MaterialBuilder("material1")
                       .WithFallback(material)
                       .WithSpecularGlossinessShader()
                       .WithChannelImage(Materials.KnownChannels.Normal, System.IO.Path.Combine(basePath, "WaterBottle_normal.png"))
                       .WithChannelImage(Materials.KnownChannels.Emissive, System.IO.Path.Combine(basePath, "WaterBottle_emissive.png"))
                       .WithChannelImage(Materials.KnownChannels.Occlusion, System.IO.Path.Combine(basePath, "WaterBottle_occlusion.png"))
                       .WithChannelImage(Materials.KnownChannels.Diffuse, System.IO.Path.Combine(basePath, "WaterBottle_diffuse.png"))
                       .WithChannelImage(Materials.KnownChannels.SpecularGlossiness, System.IO.Path.Combine(basePath, "WaterBottle_specularGlossiness.png"));

            var mesh = new Geometry.MeshBuilder <VPOS, VTEX>("mesh1");

            mesh.UsePrimitive(material).AddPolygon
                ((new Vector3(-10, 10, 0), new Vector2(1, 0))
                , (new Vector3(10, 10, 0), new Vector2(0, 0))
                , (new Vector3(10, -10, 0), new Vector2(0, 1))
                , (new Vector3(-10, -10, 0), new Vector2(1, 1))
                );

            var model = ModelRoot.CreateModel();
            var scene = model.UseScene("Default");
            var rnode = scene.CreateNode("RootNode").WithMesh(model.CreateMesh(mesh));

            model.AttachToCurrentTest("result.glb");
            model.AttachToCurrentTest("result.gltf");
        }
        public void CreateSceneWithRandomCubes()
        {
            TestContext.CurrentContext.AttachShowDirLink();
            TestContext.CurrentContext.AttachGltfValidatorLinks();

            var rnd = new Random();

            var materials = Enumerable
                            .Range(0, 10)
                            .Select(idx => MaterialBuilder.CreateDefault()
                                    .WithChannelParam("BaseColor", new Vector4(rnd.NextVector3(), 1)))
                            .ToList();

            // create a mesh
            var cubes = new MeshBuilder <VPOSNRM>("cube");

            cubes.VertexPreprocessor.SetDebugPreprocessors();

            for (int i = 0; i < 100; ++i)
            {
                var r     = rnd.NextVector3() * 5;
                var m     = materials[rnd.Next(0, 10)];
                var xform = Matrix4x4.CreateFromYawPitchRoll(r.X, r.Y, r.Z) * Matrix4x4.CreateTranslation(rnd.NextVector3() * 25);
                cubes.AddCube(m, xform);
            }

            cubes.Validate();

            // create a new gltf model
            var model = ModelRoot.CreateModel();

            // add all meshes (just one in this case) to the model
            model.CreateMeshes(cubes);

            // create a scene, a node, and assign the first mesh (the terrain)
            model.UseScene("Default")
            .CreateNode().WithMesh(model.LogicalMeshes[0]);

            // save the model as GLB
            model.AttachToCurrentTest("cubes.glb");
        }
        /// <summary>
        /// Convertes a collection of <see cref="SceneBuilder"/> instances to a single <see cref="ModelRoot"/> instance.
        /// </summary>
        /// <param name="srcScenes">A collection of scenes</param>
        /// <param name="useStridedBuffers">True to generate strided vertex buffers whenever possible.</param>
        /// <returns>A new <see cref="ModelRoot"/> instance.</returns>
        public static ModelRoot ToSchema2(IEnumerable <SceneBuilder> srcScenes, SceneBuilderSchema2Settings settings)
        {
            Guard.NotNull(srcScenes, nameof(srcScenes));

            var context = new Schema2SceneBuilder();

            var dstModel = ModelRoot.CreateModel();

            context.AddGeometryResources(dstModel, srcScenes, settings);

            foreach (var srcScene in srcScenes)
            {
                var dstScene = dstModel.UseScene(dstModel.LogicalScenes.Count);

                dstScene.Name = srcScene.Name;

                context.AddScene(dstScene, srcScene);
            }

            return(dstModel);
        }
Exemple #16
0
        public void CreateSceneWithExtras()
        {
            var root  = ModelRoot.CreateModel();
            var scene = root.UseScene("Empty Scene");

            /*
             *
             * root.Extras["author"] = "me";
             *
             * root.Extras["value1"] = 17;
             * root.Extras["array1"] = new Single[] { 1, 2, 3 };
             * root.Extras["dict1"] = new Dictionary<String, Object>
             * {
             *  ["A"] = 16,
             *  ["B"] = "delta",
             *  ["C"] = new Single[] { 4, 6, 7 },
             *  ["D"] = new Dictionary<String, Object> { ["S"]= 1, ["T"] = 2 }
             * };
             *
             * var json = root.GetJSON(Newtonsoft.Json.Formatting.Indented);
             * var bytes = root.WriteGLB();
             *
             * var rootBis = ModelRoot.ParseGLB(bytes);
             *
             * CollectionAssert.AreEqual(root.Extras, rootBis.Extras);
             *
             * Assert.AreEqual(root.Extras["author"], rootBis.Extras["author"]);
             * Assert.AreEqual(root.Extras["value1"], rootBis.Extras["value1"]);
             * CollectionAssert.AreEqual
             *  (
             *  root.Extras["array1"] as Array,
             *  rootBis.Extras["array1"] as Array
             *  );
             *
             * CollectionAssert.AreEqual
             *  (
             *  root.Extras["dict1"] as Dictionary<string, Object>,
             *  rootBis.Extras["dict1"] as Dictionary<string, Object>
             *  );*/
        }
        public void CreateSceneWithTextureImageExtension(string textureFileName)
        {
            TestContext.CurrentContext.AttachShowDirLink();
            TestContext.CurrentContext.AttachGltfValidatorLinks();

            var basePath = System.IO.Path.Combine(TestContext.CurrentContext.WorkDirectory, "Assets");

            // first, create a default material
            var material = new Materials.MaterialBuilder("material1")
                           .WithDoubleSide(true)
                           .WithMetallicRoughnessShader()
                           .WithChannelImage
                           (
                Materials.KnownChannel.BaseColor,
                System.IO.Path.Combine(basePath, textureFileName)
                           );

            var mesh = new Geometry.MeshBuilder <VPOS, VTEX>("mesh1");

            mesh
            .UsePrimitive(material)
            .AddQuadrangle
                ((new Vector3(-10, 10, 0), new Vector2(1, 0))
                , (new Vector3(10, 10, 0), new Vector2(0, 0))
                , (new Vector3(10, -10, 0), new Vector2(0, 1))
                , (new Vector3(-10, -10, 0), new Vector2(1, 1))
                );

            var model = ModelRoot.CreateModel();

            model.CreateMeshes(mesh);

            model.UseScene("Default")
            .CreateNode("RootNode")
            .WithMesh(model.LogicalMeshes[0]);

            model.AttachToCurrentTest("result_wf.obj");
            model.AttachToCurrentTest("result_glb.glb");
            model.AttachToCurrentTest("result_gltf.gltf");
        }
Exemple #18
0
        public static ModelRoot ToGLTF(this MapGeometry mgeo)
        {
            ModelRoot root     = ModelRoot.CreateModel();
            Scene     scene    = root.UseScene("Map");
            Node      rootNode = scene.CreateNode("Map");

            // Find all layer combinations used in the Map
            // so we can group the meshes
            var layerModelMap = new Dictionary <MapGeometryLayer, List <MapGeometryModel> >();

            foreach (MapGeometryModel model in mgeo.Models)
            {
                if (!layerModelMap.ContainsKey(model.Layer))
                {
                    layerModelMap.Add(model.Layer, new List <MapGeometryModel>());
                }

                layerModelMap[model.Layer].Add(model);
            }

            // Create node for each layer combination
            var layerNodeMap = new Dictionary <MapGeometryLayer, Node>();

            foreach (var layerModelPair in layerModelMap)
            {
                layerNodeMap.Add(layerModelPair.Key, rootNode.CreateNode(DeriveLayerCombinationName(layerModelPair.Key)));
            }

            foreach (MapGeometryModel model in mgeo.Models)
            {
                IMeshBuilder <MaterialBuilder> meshBuilder = BuildMapGeometryMeshStatic(model);

                layerNodeMap[model.Layer]
                .CreateNode()
                .WithMesh(root.CreateMesh(meshBuilder))
                .WithLocalTransform(new AffineTransform(model.Transformation));
            }

            return(root);
        }
Exemple #19
0
        /// <summary>
        /// Converts a collection of <see cref="SceneBuilder"/> instances to a single <see cref="ModelRoot"/> instance.
        /// </summary>
        /// <param name="srcScenes">A collection of scenes</param>
        /// <param name="settings">Conversion settings.</param>
        /// <returns>A new <see cref="ModelRoot"/> instance.</returns>
        public static ModelRoot ToGltf2(IEnumerable <SceneBuilder> srcScenes, SceneBuilderSchema2Settings settings)
        {
            Guard.NotNull(srcScenes, nameof(srcScenes));

            var context = new Schema2SceneBuilder();

            var dstModel = ModelRoot.CreateModel();

            context.AddGeometryResources(dstModel, srcScenes, settings);

            foreach (var srcScene in srcScenes)
            {
                var dstScene = dstModel.UseScene(dstModel.LogicalScenes.Count);
                srcScene.TryCopyNameAndExtrasTo(dstScene);

                context.AddScene(dstScene, srcScene);
            }

            dstModel.DefaultScene = dstModel.LogicalScenes[0];

            return(dstModel);
        }
Exemple #20
0
        // Skinning use cases and examples: https://github.com/KhronosGroup/glTF/issues/1403

        // hierarchy created:

        // Mesh1
        // Skin1─> Armature1
        // Skin2─> Armature2
        // Skin3─> Armature3
        // Scene
        // ├── Armature1
        // │   ├── Bone1
        // │   ├── Bone2
        // │   └── Bone3
        // ├── SkinnedMesh1─> Mesh1, Skin1
        // ├── Armature2
        // │   ├── Bone1
        // │   ├── Bone2
        // │   └── Bone3
        // ├── SkinnedMesh2─> Mesh1, Skin2
        // ├── Armature3
        // │   ├── Bone1
        // │   ├── Bone2
        // │   └── Bone3
        // └── SkinnedMesh3─> Mesh1, Skin3
        // ...

        static void Main(string[] args)
        {
            var model = ModelRoot.CreateModel();
            var scene = model.UseScene("default");

            var mesh = model
                       .CreateMeshes(CreateMesh(10))
                       .First();

            RecusiveTentacle(scene, scene, Matrix4x4.CreateTranslation(+25, 0, +25), mesh, Quaternion.CreateFromYawPitchRoll(0f, 0.2f, 0f), 2);
            RecusiveTentacle(scene, scene, Matrix4x4.CreateTranslation(-25, 0, +25), mesh, Quaternion.CreateFromYawPitchRoll(0.2f, 0f, 0f), 2);
            RecusiveTentacle(scene, scene, Matrix4x4.CreateTranslation(-25, 0, -25), mesh, Quaternion.CreateFromYawPitchRoll(0f, 0f, 0.2f), 2);
            RecusiveTentacle(scene, scene, Matrix4x4.CreateTranslation(+25, 0, -25), mesh, Quaternion.CreateFromYawPitchRoll(0.2f, 0f, 0f), 2);

            model.SaveGLB("recursive tentacles.glb");
            model.SaveGLTF("recursive tentacles.gltf");

            model.SaveAsWavefront("recursive_tentacles_at_000.obj", model.LogicalAnimations[0], 0);
            model.SaveAsWavefront("recursive_tentacles_at_025.obj", model.LogicalAnimations[0], 0.25f);
            model.SaveAsWavefront("recursive_tentacles_at_050.obj", model.LogicalAnimations[0], 0.50f);
            model.SaveAsWavefront("recursive_tentacles_at_075.obj", model.LogicalAnimations[0], 0.75f);
            model.SaveAsWavefront("recursive_tentacles_at_100.obj", model.LogicalAnimations[0], 1);
        }
        public void CreateSceneWithAnimatedMeshBuilder()
        {
            TestContext.CurrentContext.AttachShowDirLink();
            TestContext.CurrentContext.AttachGltfValidatorLinks();

            // create animation sequence with 4 frames
            var keyframes = new Dictionary <Single, Vector3>()
            {
                [1] = new Vector3(0, 0, 0),
                [2] = new Vector3(50, 0, 0),
                [3] = new Vector3(0, 50, 0),
                [4] = new Vector3(0, 0, 0),
            };

            // create a material
            var material1 = new MaterialBuilder("material1").WithChannelParam(KnownChannel.BaseColor, Vector4.One);

            // create a mesh
            var meshBuilder = new MeshBuilder <VPOSNRM>("mesh1");

            meshBuilder.VertexPreprocessor.SetDebugPreprocessors();

            meshBuilder.AddCube(material1, Matrix4x4.Identity);
            meshBuilder.Validate();

            // create the gltf model
            var model = ModelRoot.CreateModel();

            model.UseScene("Default")
            .CreateNode("RootNode")
            .WithTranslationAnimation("track1", keyframes)
            .WithMesh(model.CreateMesh(meshBuilder));

            model.AttachToCurrentTest("result.glb");
            model.AttachToCurrentTest("result.gltf");
        }
Exemple #22
0
        public static ModelRoot ToGltf(this StaticObject staticObject)
        {
            ModelRoot root  = ModelRoot.CreateModel();
            Scene     scene = root.UseScene("default");

            var mesh = VERTEX.CreateCompatibleMesh();

            foreach (StaticObjectSubmesh submesh in staticObject.Submeshes)
            {
                MaterialBuilder material  = new MaterialBuilder(submesh.Name);
                var             primitive = mesh.UsePrimitive(material);

                List <VERTEX> vertices = new List <VERTEX>();
                foreach (StaticObjectVertex vertex in submesh.Vertices)
                {
                    vertices.Add(new VERTEX()
                                 .WithGeometry(vertex.Position)
                                 .WithMaterial(vertex.UV));
                }

                for (int i = 0; i < submesh.Indices.Count; i += 3)
                {
                    VERTEX v1 = vertices[(int)submesh.Indices[i + 0]];
                    VERTEX v2 = vertices[(int)submesh.Indices[i + 1]];
                    VERTEX v3 = vertices[(int)submesh.Indices[i + 2]];

                    primitive.AddTriangle(v1, v2, v3);
                }
            }

            scene
            .CreateNode()
            .WithMesh(root.CreateMesh(mesh));

            return(root);
        }
Exemple #23
0
        public bool ExportAnim(Stream animStream, List <Archive> archives, FileInfo outfile, bool isGLBinary = true)
        {
            var cr2w = _wolvenkitFileService.TryReadRED4File(animStream);

            if (!cr2w.Chunks.Select(_ => _.Data).OfType <animAnimSet>().Any())
            {
                return(false);
            }
            var blob = cr2w.Chunks.Select(_ => _.Data).OfType <animAnimSet>().First();

            List <MemoryStream> animDataBuffers = new List <MemoryStream>();

            foreach (var chk in blob.AnimationDataChunks)
            {
                UInt16 bufferIdx = chk.Buffer.Buffer.Value;
                var    b         = cr2w.Buffers[bufferIdx - 1];
                animStream.Seek(b.Offset, SeekOrigin.Begin);
                var ms = new MemoryStream();
                animStream.DecompressAndCopySegment(ms, b.DiskSize, b.MemSize);
                animDataBuffers.Add(ms);
            }
            RawArmature Rig = null;

            {
                ulong hash = FNV1A64HashAlgorithm.HashString(blob.Rig.DepotPath);
                foreach (Archive ar in archives)
                {
                    if (ar.Files.ContainsKey(hash))
                    {
                        var ms = new MemoryStream();
                        ModTools.ExtractSingleToStream(ar, hash, ms);
                        Rig = new RIG(_wolvenkitFileService).ProcessRig(ms);
                        break;
                    }
                }
            }
            if (Rig.BoneCount < 1)
            {
                return(false);
            }
            var model = ModelRoot.CreateModel();
            var skin  = model.CreateSkin();

            skin.BindJoints(RIG.ExportNodes(ref model, Rig).Values.ToArray());

            for (int i = 0; i < blob.Animations.Count; i++)
            {
                var setEntry    = (blob.Animations[i].GetReference().Data as animAnimSetEntry);
                var animAnimDes = (setEntry.Animation.GetReference().Data as animAnimation);
                if (animAnimDes.AnimationType.Value != Enums.animAnimationType.Normal)
                {
                    continue;
                }
                switch (animAnimDes.AnimBuffer.GetReference().REDType)
                {
                case "animAnimationBufferSimd":
                {
                    var animBuff  = (animAnimDes.AnimBuffer.GetReference().Data as animAnimationBufferSimd);
                    var bufferIdx = animBuff.DefferedBuffer.Buffer.Value;
                    var b         = cr2w.Buffers[bufferIdx - 1];
                    animStream.Seek(b.Offset, SeekOrigin.Begin);
                    var defferedBuffer = new MemoryStream();
                    animStream.DecompressAndCopySegment(defferedBuffer, b.DiskSize, b.MemSize);
                    SIMD.AddAnimationSIMD(ref model, animBuff, animAnimDes.Name.Value, defferedBuffer);
                }
                break;

                case "animAnimationBufferCompressed":
                {
                    var    animBuff = (animAnimDes.AnimBuffer.GetReference().Data as animAnimationBufferCompressed);
                    var    dataAddr = animBuff.DataAddress;
                    Byte[] bytes    = new Byte[dataAddr.ZeInBytes.Value];
                    animDataBuffers[(int)dataAddr.UnkIndex.Value].Seek(dataAddr.FsetInBytes.Value, SeekOrigin.Begin);
                    animDataBuffers[(int)dataAddr.UnkIndex.Value].Read(bytes, 0, (int)dataAddr.ZeInBytes.Value);
                    var defferedBuffer = new MemoryStream(bytes);
                    SPLINE.AddAnimationSpline(ref model, animBuff, animAnimDes.Name.Value, defferedBuffer);
                }
                break;

                default:
                    break;
                }
            }
            if (isGLBinary)
            {
                model.SaveGLB(outfile.FullName);
            }
            else
            {
                model.SaveGLTF(outfile.FullName);
            }

            return(true);
        }
        /// <summary>
        /// Export a Valve VMDL to GLTF.
        /// </summary>
        /// <param name="resourceName">The name of the resource being exported.</param>
        /// <param name="fileName">Target file name.</param>
        /// <param name="model">The model resource to export.</param>
        public void ExportToFile(string resourceName, string fileName, VModel model)
        {
            if (FileLoader == null)
            {
                throw new InvalidOperationException(nameof(FileLoader) + " must be set first.");
            }

            var exportedModel = ModelRoot.CreateModel();

            exportedModel.Asset.Generator = GENERATOR;
            var scene = exportedModel.UseScene(Path.GetFileName(resourceName));

            void AddMeshNode(string name, VMesh mesh, Skeleton skeleton)
            {
                if (mesh.GetData().GetArray("m_sceneObjects").Length == 0)
                {
                    return;
                }

                var hasJoints       = skeleton.AnimationTextureSize > 0;
                var exportedMesh    = CreateGltfMesh(name, mesh, exportedModel, hasJoints);
                var hasVertexJoints = exportedMesh.Primitives.All(primitive => primitive.GetVertexAccessor("JOINTS_0") != null);

                if (hasJoints && hasVertexJoints)
                {
                    var skeletonNode = scene.CreateNode(name);
                    var joints       = CreateGltfSkeleton(skeleton, skeletonNode);

                    scene.CreateNode(name)
                    .WithSkinnedMesh(exportedMesh, Matrix4x4.Identity, joints);

                    // Rotate upright, scale inches to meters.
                    skeletonNode.WorldMatrix = TRANSFORMSOURCETOGLTF;

                    // Add animations
                    var animations = GetAllAnimations(model);
                    foreach (var animation in animations)
                    {
                        var exportedAnimation = exportedModel.CreateAnimation(animation.Name);
                        var rotationDict      = new Dictionary <string, Dictionary <float, Quaternion> >();
                        var translationDict   = new Dictionary <string, Dictionary <float, Vector3> >();

                        var time = 0f;
                        foreach (var frame in animation.Frames)
                        {
                            foreach (var boneFrame in frame.Bones)
                            {
                                var bone = boneFrame.Key;
                                if (!rotationDict.ContainsKey(bone))
                                {
                                    rotationDict[bone]    = new Dictionary <float, Quaternion>();
                                    translationDict[bone] = new Dictionary <float, Vector3>();
                                }
                                rotationDict[bone].Add(time, boneFrame.Value.Angle);
                                translationDict[bone].Add(time, boneFrame.Value.Position);
                            }
                            time += 1 / animation.Fps;
                        }

                        foreach (var bone in rotationDict.Keys)
                        {
                            var node = joints.FirstOrDefault(n => n.Name == bone);
                            if (node != null)
                            {
                                exportedAnimation.CreateRotationChannel(node, rotationDict[bone], true);
                                exportedAnimation.CreateTranslationChannel(node, translationDict[bone], true);
                            }
                        }
                    }
                }
                else
                {
                    var meshNode = scene.CreateNode(name)
                                   .WithMesh(exportedMesh);

                    // Rotate upright, scale inches to meters.
                    meshNode.WorldMatrix = TRANSFORMSOURCETOGLTF;
                }
            }

            // Add meshes and their skeletons
            var meshes = LoadModelMeshes(model);

            for (var i = 0; i < meshes.Length; i++)
            {
                AddMeshNode(meshes[i].Name, meshes[i].Mesh, model.GetSkeleton(i));
            }

            exportedModel.Save(fileName);
        }
Exemple #25
0
        private static ModelRoot RawTargetsToGLTF(List <RawMeshContainer> meshes, List <RawTargetContainer[]> expTargets, string[] names, RawArmature rig)
        {
            var model = ModelRoot.CreateModel();
            var mat   = model.CreateMaterial("Default");

            mat.WithPBRMetallicRoughness().WithDefault();
            mat.DoubleSided = true;
            var skins = new List <Skin>();

            if (rig != null)
            {
                var skin = model.CreateSkin();
                skin.BindJoints(RIG.ExportNodes(ref model, rig).Values.ToArray());
                skins.Add(skin);
            }

            var ms     = new MemoryStream();
            var bw     = new BinaryWriter(ms);
            var mIndex = -1;

            foreach (var mesh in meshes)
            {
                ++mIndex;
                for (var i = 0; i < mesh.positions.Length; i++)
                {
                    bw.Write(mesh.positions[i].X);
                    bw.Write(mesh.positions[i].Y);
                    bw.Write(mesh.positions[i].Z);
                }
                for (var i = 0; i < mesh.normals.Length; i++)
                {
                    bw.Write(mesh.normals[i].X);
                    bw.Write(mesh.normals[i].Y);
                    bw.Write(mesh.normals[i].Z);
                }
                for (var i = 0; i < mesh.tangents.Length; i++)
                {
                    bw.Write(mesh.tangents[i].X);
                    bw.Write(mesh.tangents[i].Y);
                    bw.Write(mesh.tangents[i].Z);
                    bw.Write(mesh.tangents[i].W);
                }
                for (var i = 0; i < mesh.colors0.Length; i++)
                {
                    bw.Write(mesh.colors0[i].X);
                    bw.Write(mesh.colors0[i].Y);
                    bw.Write(mesh.colors0[i].Z);
                    bw.Write(mesh.colors0[i].W);
                }
                for (var i = 0; i < mesh.colors1.Length; i++)
                {
                    bw.Write(mesh.colors1[i].X);
                    bw.Write(mesh.colors1[i].Y);
                    bw.Write(mesh.colors1[i].Z);
                    bw.Write(mesh.colors1[i].W);
                }
                for (var i = 0; i < mesh.texCoords0.Length; i++)
                {
                    bw.Write(mesh.texCoords0[i].X);
                    bw.Write(mesh.texCoords0[i].Y);
                }
                for (var i = 0; i < mesh.texCoords1.Length; i++)
                {
                    bw.Write(mesh.texCoords1[i].X);
                    bw.Write(mesh.texCoords1[i].Y);
                }

                if (mesh.weightCount > 0)
                {
                    if (rig != null)
                    {
                        for (var i = 0; i < mesh.positions.Length; i++)
                        {
                            bw.Write(mesh.boneindices[i, 0]);
                            bw.Write(mesh.boneindices[i, 1]);
                            bw.Write(mesh.boneindices[i, 2]);
                            bw.Write(mesh.boneindices[i, 3]);
                        }
                        for (var i = 0; i < mesh.positions.Length; i++)
                        {
                            bw.Write(mesh.weights[i, 0]);
                            bw.Write(mesh.weights[i, 1]);
                            bw.Write(mesh.weights[i, 2]);
                            bw.Write(mesh.weights[i, 3]);
                        }
                        if (mesh.weightCount > 4)
                        {
                            for (var i = 0; i < mesh.positions.Length; i++)
                            {
                                bw.Write(mesh.boneindices[i, 4]);
                                bw.Write(mesh.boneindices[i, 5]);
                                bw.Write(mesh.boneindices[i, 6]);
                                bw.Write(mesh.boneindices[i, 7]);
                            }
                            for (var i = 0; i < mesh.positions.Length; i++)
                            {
                                bw.Write(mesh.weights[i, 4]);
                                bw.Write(mesh.weights[i, 5]);
                                bw.Write(mesh.weights[i, 6]);
                                bw.Write(mesh.weights[i, 7]);
                            }
                        }
                    }
                }
                for (var i = 0; i < mesh.indices.Length; i += 3)
                {
                    bw.Write(Convert.ToUInt16(mesh.indices[i + 1]));
                    bw.Write(Convert.ToUInt16(mesh.indices[i + 0]));
                    bw.Write(Convert.ToUInt16(mesh.indices[i + 2]));
                }
                for (var i = 0; i < expTargets.Count; i++)
                {
                    var mappings = expTargets[i][mIndex].vertexMapping.ToList();
                    for (ushort e = 0; e < mesh.positions.Length; e++)
                    {
                        if (mappings.Contains(e))
                        {
                            var idx = mappings.IndexOf(e);
                            bw.Write(expTargets[i][mIndex].vertexDelta[idx].X);
                            bw.Write(expTargets[i][mIndex].vertexDelta[idx].Y);
                            bw.Write(expTargets[i][mIndex].vertexDelta[idx].Z);
                        }
                        else
                        {
                            bw.Write(0f);
                            bw.Write(0f);
                            bw.Write(0f);
                        }
                    }
                    for (ushort e = 0; e < mesh.normals.Length; e++)
                    {
                        if (mappings.Contains(e))
                        {
                            var idx = mappings.IndexOf(e);
                            bw.Write(expTargets[i][mIndex].normalDelta[idx].X);
                            bw.Write(expTargets[i][mIndex].normalDelta[idx].Y);
                            bw.Write(expTargets[i][mIndex].normalDelta[idx].Z);
                        }
                        else
                        {
                            bw.Write(0f);
                            bw.Write(0f);
                            bw.Write(0f);
                        }
                    }
                    for (ushort e = 0; e < mesh.tangents.Length; e++)
                    {
                        if (mappings.Contains(e))
                        {
                            var idx = mappings.IndexOf(e);
                            bw.Write(expTargets[i][mIndex].tangentDelta[idx].X);
                            bw.Write(expTargets[i][mIndex].tangentDelta[idx].Y);
                            bw.Write(expTargets[i][mIndex].tangentDelta[idx].Z);
                        }
                        else
                        {
                            bw.Write(0f);
                            bw.Write(0f);
                            bw.Write(0f);
                        }
                    }
                }
            }
            var buffer         = model.UseBuffer(ms.ToArray());
            var BuffViewoffset = 0;

            foreach (var mesh in meshes)
            {
                var mes  = model.CreateMesh(mesh.name);
                var prim = mes.CreatePrimitive();
                prim.Material = mat;
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.positions.Length * 12);
                    acc.SetData(buff, 0, mesh.positions.Length, DimensionType.VEC3, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("POSITION", acc);
                    BuffViewoffset += mesh.positions.Length * 12;
                }
                if (mesh.normals.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.normals.Length * 12);
                    acc.SetData(buff, 0, mesh.normals.Length, DimensionType.VEC3, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("NORMAL", acc);
                    BuffViewoffset += mesh.normals.Length * 12;
                }
                if (mesh.tangents.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.tangents.Length * 16);
                    acc.SetData(buff, 0, mesh.tangents.Length, DimensionType.VEC4, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("TANGENT", acc);
                    BuffViewoffset += mesh.tangents.Length * 16;
                }
                if (mesh.colors0.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.colors0.Length * 16);
                    acc.SetData(buff, 0, mesh.colors0.Length, DimensionType.VEC4, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("COLOR_0", acc);
                    BuffViewoffset += mesh.colors0.Length * 16;
                }
                if (mesh.colors1.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.colors1.Length * 16);
                    acc.SetData(buff, 0, mesh.colors1.Length, DimensionType.VEC4, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("COLOR_1", acc);
                    BuffViewoffset += mesh.colors1.Length * 16;
                }
                if (mesh.texCoords0.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.texCoords0.Length * 8);
                    acc.SetData(buff, 0, mesh.texCoords0.Length, DimensionType.VEC2, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("TEXCOORD_0", acc);
                    BuffViewoffset += mesh.texCoords0.Length * 8;
                }
                if (mesh.texCoords1.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.texCoords1.Length * 8);
                    acc.SetData(buff, 0, mesh.texCoords1.Length, DimensionType.VEC2, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("TEXCOORD_1", acc);
                    BuffViewoffset += mesh.texCoords1.Length * 8;
                }
                if (mesh.weightCount > 0)
                {
                    if (rig != null)
                    {
                        {
                            var acc  = model.CreateAccessor();
                            var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.positions.Length * 8);
                            acc.SetData(buff, 0, mesh.positions.Length, DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, false);
                            prim.SetVertexAccessor("JOINTS_0", acc);
                            BuffViewoffset += mesh.positions.Length * 8;
                        }
                        {
                            var acc  = model.CreateAccessor();
                            var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.positions.Length * 16);
                            acc.SetData(buff, 0, mesh.positions.Length, DimensionType.VEC4, EncodingType.FLOAT, false);
                            prim.SetVertexAccessor("WEIGHTS_0", acc);
                            BuffViewoffset += mesh.positions.Length * 16;
                        }
                        if (mesh.weightCount > 4)
                        {
                            {
                                var acc  = model.CreateAccessor();
                                var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.positions.Length * 8);
                                acc.SetData(buff, 0, mesh.positions.Length, DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, false);
                                prim.SetVertexAccessor("JOINTS_1", acc);
                                BuffViewoffset += mesh.positions.Length * 8;
                            }
                            {
                                var acc  = model.CreateAccessor();
                                var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.positions.Length * 16);
                                acc.SetData(buff, 0, mesh.positions.Length, DimensionType.VEC4, EncodingType.FLOAT, false);
                                prim.SetVertexAccessor("WEIGHTS_1", acc);
                                BuffViewoffset += mesh.positions.Length * 16;
                            }
                        }
                    }
                }
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.indices.Length * 2);
                    acc.SetData(buff, 0, mesh.indices.Length, DimensionType.SCALAR, EncodingType.UNSIGNED_SHORT, false);
                    prim.SetIndexAccessor(acc);
                    BuffViewoffset += mesh.indices.Length * 2;
                }
                var nod = model.UseScene(0).CreateNode(mesh.name);
                nod.Mesh = mes;
                if (rig != null && mesh.weightCount > 0)
                {
                    nod.Skin = skins[0];
                }

                var obj = new { targetNames = names }; // anonymous variable/obj
                mes.Extras = SharpGLTF.IO.JsonContent.Serialize(obj);

                for (var i = 0; i < expTargets.Count; i++)
                {
                    var dict = new Dictionary <string, Accessor>();
                    {
                        var acc  = model.CreateAccessor();
                        var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.positions.Length * 12);
                        acc.SetData(buff, 0, mesh.positions.Length, DimensionType.VEC3, EncodingType.FLOAT, false);
                        dict.Add("POSITION", acc);
                        BuffViewoffset += mesh.positions.Length * 12;
                    }
                    if (mesh.normals.Length > 0)
                    {
                        var acc  = model.CreateAccessor();
                        var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.normals.Length * 12);
                        acc.SetData(buff, 0, mesh.normals.Length, DimensionType.VEC3, EncodingType.FLOAT, false);
                        dict.Add("NORMAL", acc);
                        BuffViewoffset += mesh.normals.Length * 12;
                    }
                    if (mesh.tangents.Length > 0)
                    {
                        var acc  = model.CreateAccessor();
                        var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.tangents.Length * 12);
                        acc.SetData(buff, 0, mesh.tangents.Length, DimensionType.VEC3, EncodingType.FLOAT, false);
                        dict.Add("TANGENT", acc);
                        BuffViewoffset += mesh.tangents.Length * 12;
                    }
                    prim.SetMorphTargetAccessors(i, dict);
                }
            }
            model.UseScene(0).Name = "Scene";
            model.DefaultScene     = model.UseScene(0);
            model.MergeBuffers();
            return(model);
        }
Exemple #26
0
        public void CreateSceneWithSkinnedAnimatedMeshBuilder()
        {
            TestContext.CurrentContext.AttachShowDirLink();
            TestContext.CurrentContext.AttachGltfValidatorLinks();

            // create animation sequence with 4 frames
            var keyframes = new Dictionary <Single, Quaternion>
            {
                [1] = Quaternion.Identity,
                [2] = Quaternion.CreateFromYawPitchRoll(0, 1, 0),
                [3] = Quaternion.CreateFromYawPitchRoll(0, 0, 1),
                [4] = Quaternion.Identity,
            };

            // create two materials
            var pink = new MaterialBuilder("material1")
                       .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 0, 1, 1))
                       .WithDoubleSide(true);

            var yellow = new MaterialBuilder("material2")
                         .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 1, 0, 1))
                         .WithDoubleSide(true);

            // create the mesh
            var meshBuilder = new MeshBuilder <VPOS, VEMPTY, VSKIN4>("mesh1");

            #if DEBUG
            meshBuilder.VertexPreprocessor.SetDebugPreprocessors();
            #else
            meshBuilder.VertexPreprocessor.SetSanitizerPreprocessors();
            #endif

            const int jointIdx0 = 0;
            const int jointIdx1 = 1;
            const int jointIdx2 = 2;

            var v1 = (new VPOS(-10, 0, +10), new VSKIN4(jointIdx0));
            var v2 = (new VPOS(+10, 0, +10), new VSKIN4(jointIdx0));
            var v3 = (new VPOS(+10, 0, -10), new VSKIN4(jointIdx0));
            var v4 = (new VPOS(-10, 0, -10), new VSKIN4(jointIdx0));

            var v5 = (new VPOS(-10, 40, +10), new VSKIN4((jointIdx0, 0.5f), (jointIdx1, 0.5f)));
            var v6 = (new VPOS(+10, 40, +10), new VSKIN4((jointIdx0, 0.5f), (jointIdx1, 0.5f)));
            var v7 = (new VPOS(+10, 40, -10), new VSKIN4((jointIdx0, 0.5f), (jointIdx1, 0.5f)));
            var v8 = (new VPOS(-10, 40, -10), new VSKIN4((jointIdx0, 0.5f), (jointIdx1, 0.5f)));

            var v9  = (new VPOS(-5, 80, +5), new VSKIN4(jointIdx2));
            var v10 = (new VPOS(+5, 80, +5), new VSKIN4(jointIdx2));
            var v11 = (new VPOS(+5, 80, -5), new VSKIN4(jointIdx2));
            var v12 = (new VPOS(-5, 80, -5), new VSKIN4(jointIdx2));

            meshBuilder.UsePrimitive(pink).AddQuadrangle(v1, v2, v6, v5);
            meshBuilder.UsePrimitive(pink).AddQuadrangle(v2, v3, v7, v6);
            meshBuilder.UsePrimitive(pink).AddQuadrangle(v3, v4, v8, v7);
            meshBuilder.UsePrimitive(pink).AddQuadrangle(v4, v1, v5, v8);

            meshBuilder.UsePrimitive(yellow).AddQuadrangle(v5, v6, v10, v9);
            meshBuilder.UsePrimitive(yellow).AddQuadrangle(v6, v7, v11, v10);
            meshBuilder.UsePrimitive(yellow).AddQuadrangle(v7, v8, v12, v11);
            meshBuilder.UsePrimitive(yellow).AddQuadrangle(v8, v5, v9, v12);

            meshBuilder.Validate();

            // create base model
            var model = ModelRoot.CreateModel();
            var scene = model.UseScene("Default");

            // create the three joints that will affect the mesh
            var skelet = scene.CreateNode("Skeleton");
            var joint0 = skelet.CreateNode("Joint 0").WithLocalTranslation(new Vector3(0, 0, 0));
            var joint1 = joint0.CreateNode("Joint 1").WithLocalTranslation(new Vector3(0, 40, 0)).WithRotationAnimation("Base Track", keyframes);
            var joint2 = joint1.CreateNode("Joint 2").WithLocalTranslation(new Vector3(0, 40, 0));

            // setup skin
            var snode = scene.CreateNode("Skeleton Node");
            snode.Skin = model.CreateSkin();
            snode.Skin.BindJoints(joint0, joint1, joint2);

            snode.WithMesh(model.CreateMesh(meshBuilder));

            model.AttachToCurrentTest("result.glb");
            model.AttachToCurrentTest("result.gltf");
        }
        public static void DoIt()
        {
            // todo: do something with laz file...
            var material = new MaterialBuilder("material1").WithUnlitShader();

            var mesh = VERTEX.CreateCompatibleMesh("points");

            // create a point cloud primitive
            var pointCloud = mesh.UsePrimitive(material, 1);


            var points = LasReader.Readlas("utrecht.laz");

            foreach (var p in points)
            {
                pointCloud.AddPoint((p, new Vector4(0.4f, 0.8f, 0.7f, 1)));
            }

            // create a new gltf model
            var model = ModelRoot.CreateModel();

            // add all meshes (just one in this case) to the model
            model.CreateMeshes(mesh);

            // create a scene, a node, and assign the first mesh (the terrain)
            model.UseScene("Default")
            .CreateNode().WithMesh(model.LogicalMeshes[0]);

            // save the model as GLB
            model.SaveGLB("Galaxy.glb");

            MessageBox.Show("Galaxy.glb is created");

            /**
             *
             * var galaxy = new Galaxy();
             *
             * galaxy.scaleOverPlane = 0.05f;
             * galaxy.randomJitter = 0.01f;
             * foreach (var startPoint in galaxy.CreateStarts(50000))
             * {
             *  pointCloud.AddPoint((startPoint, Vector4.One));
             * }
             *
             * galaxy.scaleOverPlane = 0.15f;
             * galaxy.randomJitter = 0.02f;
             * foreach (var startPoint in galaxy.CreateStarts(50000))
             * {
             *  pointCloud.AddPoint((startPoint, new Vector4(0.4f, 0.8f, 0.7f, 1)));
             * }
             *
             * galaxy.randomJitter = 0.07f;
             * foreach (var startPoint in galaxy.CreateStarts(10000))
             * {
             *  pointCloud.AddPoint((startPoint, new Vector4(0.2f, 0.6f, 0.5f, 1)));
             * }
             *
             * // create a new gltf model
             * var model = ModelRoot.CreateModel();
             *
             * // add all meshes (just one in this case) to the model
             * model.CreateMeshes(mesh);
             *
             * // create a scene, a node, and assign the first mesh (the terrain)
             * model.UseScene("Default")
             *  .CreateNode().WithMesh(model.LogicalMeshes[0]);
             *
             * // save the model as GLB
             * model.SaveGLB("Galaxy.glb");
             *
             * MessageBox.Show("Galaxy.glb is created");
             */
        }
        public void CreateSceneWithSharedBuffers()
        {
            TestContext.CurrentContext.AttachShowDirLink();
            TestContext.CurrentContext.AttachGltfValidatorLinks();

            // create materials
            var material1 = new MaterialBuilder("material1")
                            .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 1, 0, 1));

            var material2 = new MaterialBuilder("material1")
                            .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 0, 1, 1));

            // create several meshes
            var meshBuilder1 = new MeshBuilder <VPOSNRM>("mesh1");

            meshBuilder1.VertexPreprocessor.SetDebugPreprocessors();
            var meshBuilder2 = new MeshBuilder <VPOSNRM>("mesh2");

            meshBuilder2.VertexPreprocessor.SetDebugPreprocessors();
            var meshBuilder3 = new MeshBuilder <VPOSNRM>("mesh3");

            meshBuilder3.VertexPreprocessor.SetDebugPreprocessors();
            var meshBuilder4 = new MeshBuilder <VPOSNRM>("mesh4");

            meshBuilder4.VertexPreprocessor.SetDebugPreprocessors();

            meshBuilder1.AddCube(material1, Matrix4x4.Identity);
            meshBuilder2.AddCube(material2, Matrix4x4.Identity);
            meshBuilder3.AddSphere(material1, 0.5f, Matrix4x4.Identity);
            meshBuilder4.AddSphere(material2, 0.5f, Matrix4x4.Identity);

            meshBuilder1.Validate();
            meshBuilder2.Validate();
            meshBuilder3.Validate();
            meshBuilder4.Validate();

            // create the gltf model
            var model = ModelRoot.CreateModel();

            // create gltf meshes, by doing so in a single call, we ensure a single, shared vertex and index buffer will be used.
            var meshes = model.CreateMeshes(meshBuilder1, meshBuilder2, meshBuilder3, meshBuilder4);

            // create scene nodes
            model.UseScene("Default").CreateNode("Cube1").WithMesh(meshes[0]).WithLocalTranslation(new Vector3(-5, 0, 0));
            model.UseScene("Default").CreateNode("Cube2").WithMesh(meshes[1]).WithLocalTranslation(new Vector3(0, 5, 0));
            model.UseScene("Default").CreateNode("Sphere1").WithMesh(meshes[2]).WithLocalTranslation(new Vector3(+5, 0, 0));
            model.UseScene("Default").CreateNode("Sphere2").WithMesh(meshes[3]).WithLocalTranslation(new Vector3(0, -5, 0));

            // manuall merge all the buffers
            model.MergeBuffers();

            // checks
            Assert.AreEqual(1, model.LogicalBuffers.Count);
            Assert.AreEqual(2, model.LogicalBufferViews.Count);
            Assert.IsTrue(model.LogicalBufferViews[0].IsVertexBuffer);
            Assert.IsTrue(model.LogicalBufferViews[1].IsIndexBuffer);
            Assert.AreEqual(2, model.LogicalMaterials.Count);

            model.AttachToCurrentTest("result.glb");
            model.AttachToCurrentTest("result.gltf");
        }
        public static ModelRoot RawMeshesToGLTF(List <RawMeshContainer> meshes, RawArmature Rig)
        {
            var model = ModelRoot.CreateModel();
            var mat   = model.CreateMaterial("Default");

            mat.WithPBRMetallicRoughness().WithDefault();
            mat.DoubleSided = true;
            List <Skin> skins = new List <Skin>();

            if (Rig != null)
            {
                var skin = model.CreateSkin();
                skin.BindJoints(RIG.ExportNodes(ref model, Rig).Values.ToArray());
                skins.Add(skin);
            }

            var ms = new MemoryStream();
            var bw = new BinaryWriter(ms);

            foreach (var mesh in meshes)
            {
                for (int i = 0; i < mesh.vertices.Length; i++)
                {
                    bw.Write(mesh.vertices[i].X);
                    bw.Write(mesh.vertices[i].Y);
                    bw.Write(mesh.vertices[i].Z);
                }
                for (int i = 0; i < mesh.normals.Length; i++)
                {
                    bw.Write(mesh.normals[i].X);
                    bw.Write(mesh.normals[i].Y);
                    bw.Write(mesh.normals[i].Z);
                }
                for (int i = 0; i < mesh.tangents.Length; i++)
                {
                    bw.Write(mesh.tangents[i].X);
                    bw.Write(mesh.tangents[i].Y);
                    bw.Write(mesh.tangents[i].Z);
                    bw.Write(mesh.tangents[i].W);
                }
                for (int i = 0; i < mesh.colors.Length; i++)
                {
                    bw.Write(mesh.colors[i].X);
                    bw.Write(mesh.colors[i].Y);
                    bw.Write(mesh.colors[i].Z);
                    bw.Write(mesh.colors[i].W);
                }
                for (int i = 0; i < mesh.tx0coords.Length; i++)
                {
                    bw.Write(mesh.tx0coords[i].X);
                    bw.Write(mesh.tx0coords[i].Y);
                }
                for (int i = 0; i < mesh.tx1coords.Length; i++)
                {
                    bw.Write(mesh.tx1coords[i].X);
                    bw.Write(mesh.tx1coords[i].Y);
                }

                if (mesh.weightcount > 0)
                {
                    if (Rig != null)
                    {
                        for (int i = 0; i < mesh.vertices.Length; i++)
                        {
                            bw.Write(mesh.boneindices[i, 0]);
                            bw.Write(mesh.boneindices[i, 1]);
                            bw.Write(mesh.boneindices[i, 2]);
                            bw.Write(mesh.boneindices[i, 3]);
                        }
                        for (int i = 0; i < mesh.vertices.Length; i++)
                        {
                            bw.Write(mesh.weights[i, 0]);
                            bw.Write(mesh.weights[i, 1]);
                            bw.Write(mesh.weights[i, 2]);
                            bw.Write(mesh.weights[i, 3]);
                        }
                        if (mesh.weightcount > 4)
                        {
                            for (int i = 0; i < mesh.vertices.Length; i++)
                            {
                                bw.Write(mesh.boneindices[i, 4]);
                                bw.Write(mesh.boneindices[i, 5]);
                                bw.Write(mesh.boneindices[i, 6]);
                                bw.Write(mesh.boneindices[i, 7]);
                            }
                            for (int i = 0; i < mesh.vertices.Length; i++)
                            {
                                bw.Write(mesh.weights[i, 4]);
                                bw.Write(mesh.weights[i, 5]);
                                bw.Write(mesh.weights[i, 6]);
                                bw.Write(mesh.weights[i, 7]);
                            }
                        }
                    }
                }
                for (int i = 0; i < mesh.indices.Length; i += 3)
                {
                    bw.Write(Convert.ToUInt16(mesh.indices[i + 1]));
                    bw.Write(Convert.ToUInt16(mesh.indices[i + 0]));
                    bw.Write(Convert.ToUInt16(mesh.indices[i + 2]));
                }
                if (mesh.extraExist)
                {
                    for (int i = 0; i < mesh.vertices.Length; i++)
                    {
                        bw.Write(mesh.extradata[i].X);
                        bw.Write(mesh.extradata[i].Y);
                        bw.Write(mesh.extradata[i].Z);
                    }
                }
            }
            var buffer         = model.UseBuffer(ms.ToArray());
            int BuffViewoffset = 0;

            foreach (var mesh in meshes)
            {
                var mes  = model.CreateMesh(mesh.name);
                var prim = mes.CreatePrimitive();
                prim.Material = mat;
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.vertices.Length * 12);
                    acc.SetData(buff, 0, mesh.vertices.Length, DimensionType.VEC3, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("POSITION", acc);
                    BuffViewoffset += mesh.vertices.Length * 12;
                }
                if (mesh.normals.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.normals.Length * 12);
                    acc.SetData(buff, 0, mesh.normals.Length, DimensionType.VEC3, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("NORMAL", acc);
                    BuffViewoffset += mesh.normals.Length * 12;
                }
                if (mesh.tangents.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.tangents.Length * 16);
                    acc.SetData(buff, 0, mesh.tangents.Length, DimensionType.VEC4, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("TANGENT", acc);
                    BuffViewoffset += mesh.tangents.Length * 16;
                }
                if (mesh.colors.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.colors.Length * 16);
                    acc.SetData(buff, 0, mesh.colors.Length, DimensionType.VEC4, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("COLOR_0", acc);
                    BuffViewoffset += mesh.colors.Length * 16;
                }
                if (mesh.tx0coords.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.tx0coords.Length * 8);
                    acc.SetData(buff, 0, mesh.tx0coords.Length, DimensionType.VEC2, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("TEXCOORD_0", acc);
                    BuffViewoffset += mesh.tx0coords.Length * 8;
                }
                if (mesh.tx1coords.Length > 0)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.tx1coords.Length * 8);
                    acc.SetData(buff, 0, mesh.tx1coords.Length, DimensionType.VEC2, EncodingType.FLOAT, false);
                    prim.SetVertexAccessor("TEXCOORD_1", acc);
                    BuffViewoffset += mesh.tx1coords.Length * 8;
                }
                if (mesh.weightcount > 0)
                {
                    if (Rig != null)
                    {
                        {
                            var acc  = model.CreateAccessor();
                            var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.vertices.Length * 8);
                            acc.SetData(buff, 0, mesh.vertices.Length, DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, false);
                            prim.SetVertexAccessor("JOINTS_0", acc);
                            BuffViewoffset += mesh.vertices.Length * 8;
                        }
                        {
                            var acc  = model.CreateAccessor();
                            var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.vertices.Length * 16);
                            acc.SetData(buff, 0, mesh.vertices.Length, DimensionType.VEC4, EncodingType.FLOAT, false);
                            prim.SetVertexAccessor("WEIGHTS_0", acc);
                            BuffViewoffset += mesh.vertices.Length * 16;
                        }
                        if (mesh.weightcount > 4)
                        {
                            {
                                var acc  = model.CreateAccessor();
                                var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.vertices.Length * 8);
                                acc.SetData(buff, 0, mesh.vertices.Length, DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, false);
                                prim.SetVertexAccessor("JOINTS_1", acc);
                                BuffViewoffset += mesh.vertices.Length * 8;
                            }
                            {
                                var acc  = model.CreateAccessor();
                                var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.vertices.Length * 16);
                                acc.SetData(buff, 0, mesh.vertices.Length, DimensionType.VEC4, EncodingType.FLOAT, false);
                                prim.SetVertexAccessor("WEIGHTS_1", acc);
                                BuffViewoffset += mesh.vertices.Length * 16;
                            }
                        }
                    }
                }
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.indices.Length * 2);
                    acc.SetData(buff, 0, mesh.indices.Length, DimensionType.SCALAR, EncodingType.UNSIGNED_SHORT, false);
                    prim.SetIndexAccessor(acc);
                    BuffViewoffset += mesh.indices.Length * 2;
                }
                var nod = model.UseScene(0).CreateNode(mesh.name);
                nod.Mesh = mes;
                if (Rig != null && mesh.weightcount > 0)
                {
                    nod.Skin = skins[0];
                }

                if (mesh.extraExist)
                {
                    string[] arr = { "GarmentSupport" };
                    var      obj = new { appNames = mesh.appNames, materialNames = mesh.materialNames, targetNames = arr };
                    mes.Extras = SharpGLTF.IO.JsonContent.Serialize(obj);
                }
                else
                {
                    var obj = new { appNames = mesh.appNames, materialNames = mesh.materialNames };
                    mes.Extras = SharpGLTF.IO.JsonContent.Serialize(obj);
                }
                if (mesh.extraExist)
                {
                    var acc  = model.CreateAccessor();
                    var buff = model.UseBufferView(buffer, BuffViewoffset, mesh.extradata.Length * 12);
                    acc.SetData(buff, 0, mesh.extradata.Length, DimensionType.VEC3, EncodingType.FLOAT, false);
                    var dict = new Dictionary <string, Accessor>();
                    dict.Add("POSITION", acc);
                    prim.SetMorphTargetAccessors(0, dict);
                    BuffViewoffset += mesh.extradata.Length * 12;
                }
            }
            model.UseScene(0).Name = "Scene";
            model.DefaultScene     = model.UseScene(0);
            model.MergeBuffers();
            return(model);
        }
        public Task WriteAsync(Stream stream, IContentContainer content)
        {
            return(Task.Run(async() =>
            {
                var context = new WriterContext
                {
                    Container = content,
                    ModelRoot = ModelRoot.CreateModel()
                };
                foreach (var textureAsset in content.Images)
                {
                    var image = context.ModelRoot.CreateImage(textureAsset.Id);
                    image.SetSatelliteContent((await textureAsset.GetContentAsync()).ToArray());
                    context.Textures.Add(textureAsset, image);
                }

                foreach (var materialAsset in content.Materials)
                {
                    var material = context.ModelRoot.CreateMaterial(materialAsset.Id);
                    material.AlphaCutoff = materialAsset.AlphaCutoff;
                    material.Alpha = GetAlphaMode(materialAsset.Alpha);
                    material.DoubleSided = materialAsset.DoubleSided;
                    if (materialAsset.Unlit)
                    {
                        material = material.WithUnlit();
                    }

                    var metallicRoughnessShader = materialAsset.Shader as MetallicRoughnessShader;
                    if (metallicRoughnessShader != null)
                    {
                        SetupMetallicRoughnessShader(material, metallicRoughnessShader, context);
                    }
                    else
                    {
                        var specularGlossinessShader = materialAsset.Shader as SpecularGlossinessShader;
                        if (specularGlossinessShader != null)
                        {
                            SetupSpecularGlossinessShader(material, specularGlossinessShader, context);
                        }
                        else
                        {
                            material.WithDefault();
                            var defaultShader = materialAsset.Shader as ShaderAsset;
                            if (defaultShader != null)
                            {
                                SetupDefaultShader(material, defaultShader, context);
                            }
                        }
                    }

                    context.Materials.Add(materialAsset, material);
                }

                foreach (var nodeAsset in GetAllNodes(content))
                {
                    if (nodeAsset.Mesh != null)
                    {
                        IList <IMaterialAsset> materials;
                        if (context.MeshInstances.TryGetValue(nodeAsset.Mesh.Mesh, out materials))
                        {
                            if (materials.Count != nodeAsset.Mesh.Materials.Count)
                            {
                                throw new FormatException("Mesh materials doesn't match all mesh instances");
                            }

                            if (!materials.Zip(nodeAsset.Mesh.Materials, (a, b) => a == b).All(_ => _))
                            {
                                throw new FormatException("Mesh materials doesn't match all mesh instances");
                            }
                            continue;
                        }

                        context.MeshInstances.Add(nodeAsset.Mesh.Mesh, nodeAsset.Mesh.Materials);
                    }
                }

                foreach (var meshAsset in content.Meshes)
                {
                    TransformMesh(context, meshAsset);
                }
                foreach (var sceneAsset in content.Scenes)
                {
                    var scene = context.ModelRoot.UseScene(sceneAsset.Id);
                    if (context.ModelRoot.DefaultScene == null)
                    {
                        context.ModelRoot.DefaultScene = scene;
                    }

                    foreach (var nodeAsset in sceneAsset.ChildNodes)
                    {
                        TransformNode(context, nodeAsset, scene.CreateNode(nodeAsset.Id));
                    }
                }

                context.ModelRoot.WriteGLB(stream);
            }));
        }