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); }
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); }
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); }
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); }
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"); }
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"); }
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"); }
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); }
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"); }
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); }
/// <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); }
// 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"); }
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); }
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); }
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); }
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); })); }