public void ExportMeshes(string path) { TestContext.CurrentContext.AttachShowDirLink(); TestContext.CurrentContext.AttachGltfValidatorLinks(); path = TestFiles .GetSampleModelsPaths() .FirstOrDefault(item => item.Contains(path)); // load the glTF model var srcModel = ModelRoot.Load(path, Validation.ValidationMode.TryFix); Assert.NotNull(srcModel); srcModel.AttachToCurrentTest("GearBoxAssy.plotly"); // convert it to a SceneBuilder so we can manipulate it: var srcScene = srcModel.DefaultScene.ToSceneBuilder(); // export all the individual meshes to OBJ: for (int i = 0; i < srcScene.Instances.Count; ++i) { var inst = srcScene.Instances[i].Content; // scan for meshes: if (inst.Content is MeshContent mesh) { var newScene = new SceneBuilder(); newScene.AddRigidMesh(mesh.Mesh, inst.GetPoseWorldMatrix()); newScene.AttachToCurrentTest($"result_{i}.obj"); } } }
public void CreateSharedNodeInstanceScene() { // SceneBuilder API supports reusing a NodeBuilder in multiple instances with different content. // but glTF nodes can only hold one mesh per node, so if we find this case we need to internally // add an additional child node to give room to the the extra mesh. TestContext.CurrentContext.AttachShowDirLink(); TestContext.CurrentContext.AttachGltfValidatorLinks(); var m = MaterialBuilder.CreateDefault(); var cube = new Cube <MaterialBuilder>(m, 1.7f, 1.7f, 1.7f).ToMesh(Matrix4x4.Identity); var sphere = new IcoSphere <MaterialBuilder>(m).ToMesh(Matrix4x4.Identity); var armature1 = new NodeBuilder("Skeleton1"); var joint0 = armature1 .CreateNode("Joint 0") .WithLocalTranslation(new Vector3(0, 1, 0)); var scene = new SceneBuilder(); scene.AddRigidMesh(cube, joint0); scene.AddRigidMesh(sphere, joint0); scene.AttachToCurrentTest("instanced.glb"); scene.AttachToCurrentTest("instanced.gltf"); }
public void CreateAnimatedCubeScene() { TestContext.CurrentContext.AttachShowDirLink(); TestContext.CurrentContext.AttachGltfValidatorLinks(); var material = MaterialBuilder.CreateDefault(); var mesh = new Cube <MaterialBuilder>(material) .ToMesh(Matrix4x4.Identity); var pivot = new NodeBuilder(); pivot.UseTranslation("track1") .WithPoint(0, Vector3.Zero) .WithPoint(1, Vector3.One); pivot.UseRotation("track1") .WithPoint(0, Quaternion.Identity) .WithPoint(1, Quaternion.CreateFromAxisAngle(Vector3.UnitY, 1.5f)); pivot.UseScale("track1") .WithPoint(0, Vector3.One) .WithPoint(1, new Vector3(0.5f)); var scene = new SceneBuilder(); scene.AddRigidMesh(mesh, pivot); scene.AttachToCurrentTest("animated.glb"); scene.AttachToCurrentTest("animated.gltf"); }
public SceneBuilder DeepClone() { var clone = new SceneBuilder(); clone._Name = this._Name; clone._Instances.AddRange(this._Instances.Select(item => item.DeepClone(this))); return(clone); }
internal InstanceBuilder DeepClone(SceneBuilder newParent) { var clone = new InstanceBuilder(newParent); clone._Name = this.Name; clone._ContentTransformer = this._ContentTransformer?.DeepClone(); return(clone); }
public void CreateSceneWithRandomShapes() { TestContext.CurrentContext.AttachShowDirLink(); TestContext.CurrentContext.AttachGltfValidatorLinks(); var rnd = new Random(177); // create materials var materials = Enumerable .Range(0, 10) .Select(idx => new Materials.MaterialBuilder() .WithChannelParam("BaseColor", new Vector4(rnd.NextVector3(), 1))) .ToList(); // create scene var scene = new SceneBuilder(); for (int i = 0; i < 100; ++i) { // create mesh var mat = materials[rnd.Next(0, 10)]; var mesh = VPOSNRM.CreateCompatibleMesh("shape"); #if DEBUG mesh.VertexPreprocessor.SetValidationPreprocessors(); #else mesh.VertexPreprocessor.SetSanitizerPreprocessors(); #endif if ((i & 1) == 0) { mesh.AddCube(mat, Matrix4x4.Identity); } else { mesh.AddSphere(mat, 0.5f, Matrix4x4.Identity); } mesh.Validate(); // create random transform var r = rnd.NextVector3() * 5; var xform = Matrix4x4.CreateFromYawPitchRoll(r.X, r.Y, r.Z) * Matrix4x4.CreateTranslation(rnd.NextVector3() * 25); scene.AddRigidMesh(mesh, xform); } // save the model as GLB scene.AttachToCurrentTest("shapes.glb"); scene.AttachToCurrentTest("shapes.plotly"); }
public void CreateAllAnimationTypesScene() { // 3D View 7.1908.9012.0 has an issue displaying off-center meshes with animated morph targets. TestContext.CurrentContext.AttachShowDirLink(); TestContext.CurrentContext.AttachGltfValidatorLinks(); // create two materials var pink = new MaterialBuilder("material1") .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 0, 1, 1)); var yellow = new MaterialBuilder("material2") .WithChannelParam(KnownChannel.BaseColor, new Vector4(1, 1, 0, 1)); var scene = new SceneBuilder(); var mesh1 = VPOSNRM.CreateCompatibleMesh("shape1"); mesh1.AddCube(MaterialBuilder.CreateDefault(), Matrix4x4.Identity); var inst1 = scene.AddRigidMesh(mesh1, Matrix4x4.Identity); var mesh2 = VPOSNRM.CreateCompatibleMesh("shape2"); mesh2.AddCube(pink, Matrix4x4.Identity); var inst2 = scene.AddRigidMesh(mesh2, Matrix4x4.CreateTranslation(2, 0, 0)); scene.AttachToCurrentTest("static.glb"); scene.AttachToCurrentTest("static.gltf"); var morphBuilder = mesh2.UseMorphTarget(0); morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(0), (Vector3.UnitY, Vector3.Zero)); morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(1), (Vector3.UnitY, Vector3.Zero)); morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(2), (Vector3.UnitY, Vector3.Zero)); morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(3), (Vector3.UnitY, Vector3.Zero)); inst2.Content.UseMorphing().Value = Transforms.SparseWeight8.Create(1); var curve = inst2.Content.UseMorphing().UseTrackBuilder("Default"); curve.SetPoint(0, Transforms.SparseWeight8.Create(0)); curve.SetPoint(1, Transforms.SparseWeight8.Create(1)); curve.SetPoint(2, Transforms.SparseWeight8.Create(0)); var gltf = scene.ToGltf2(); // Assert.AreEqual(1, gltf.LogicalMeshes[1].MorphWeights[0]); scene.AttachToCurrentTest("mopth.glb"); scene.AttachToCurrentTest("mopth.gltf"); }
public SceneBuilder DeepClone() { var clone = new SceneBuilder(); clone._Name = this._Name; foreach (var inst in this._Instances) { inst._CopyTo(clone); } return(clone); }
public void AddScene(Scene dstScene, SceneBuilder srcScene) { _Nodes.Clear(); AddArmatureResources(dstScene.CreateNode, new[] { srcScene }); var schema2Instances = srcScene .Instances .OfType <IOperator <Scene> >(); foreach (var inst in schema2Instances) { inst.Setup(dstScene, this); } }
public void CreateCubeScene() { TestContext.CurrentContext.AttachShowDirLink(); TestContext.CurrentContext.AttachGltfValidatorLinks(); var mesh = new Cube <MaterialBuilder>(MaterialBuilder.CreateDefault()) .ToMesh(Matrix4x4.Identity); var scene = new SceneBuilder(); scene.AddMesh(mesh, Matrix4x4.Identity); scene.AttachToCurrentTest("cube.glb"); }
public static SceneBuilder CreateFrom(Scene srcScene) { if (srcScene == null) { return(null); } // Process armatures var dstNodes = new Dictionary <Node, NodeBuilder>(); foreach (var srcArmature in srcScene.VisualChildren) { var dstArmature = new NodeBuilder(); _CopyToNodeBuilder(dstArmature, srcArmature, dstNodes); } // TODO: we must also process the armatures of every skin, in case the joints are outside the scene. var dstScene = new SceneBuilder(); dstScene.SetNameAndExtrasFrom(srcScene); // process mesh instances var srcMeshInstances = Node.Flatten(srcScene) .Where(item => item.Mesh != null) .ToList(); _AddMeshInstances(dstScene, dstNodes, srcMeshInstances); // process cameras var srcCameraInstances = Node.Flatten(srcScene) .Where(item => item.Camera != null) .ToList(); _AddCameraInstances(dstScene, dstNodes, srcCameraInstances); var srcLightInstances = Node.Flatten(srcScene) .Where(item => item.PunctualLight != null) .ToList(); _AddLightInstances(dstScene, dstNodes, srcCameraInstances); #if DEBUG dstScene._VerifyConversion(srcScene); #endif return(dstScene); }
public void TestCreateEmptyMesh() { // create a scenebuilder with an empty mesh var sb = new SceneBuilder(); sb.AddRigidMesh(VPOSNRM.CreateCompatibleMesh("Empty"), Matrix4x4.Identity); var schema = sb.ToGltf2(); Assert.AreEqual(0, schema.LogicalMeshes.Count, "SceneBuilder should detect empty meshes and remove them."); schema.CreateMesh("Empty2"); var fileName = AttachmentInfo.From("empty.glb").File.FullName; Assert.Throws <SharpGLTF.Validation.SchemaException>(() => schema.SaveGLB(fileName)); }
public void CreateSceneWithMixedVertexFormats() { TestContext.CurrentContext.AttachGltfValidatorLinks(); var scene = new SceneBuilder(); var mesh1 = new MeshBuilder <VertexPosition, VertexEmpty, VertexEmpty>(); var mesh2 = new MeshBuilder <VertexPositionNormal, VertexEmpty, VertexEmpty>(); mesh1.AddCube(MaterialBuilder.CreateDefault(), Matrix4x4.Identity); mesh2.AddCube(MaterialBuilder.CreateDefault(), Matrix4x4.Identity); scene.AddRigidMesh(mesh1, Matrix4x4.CreateTranslation(-2, 0, 0)); scene.AddRigidMesh(mesh2, Matrix4x4.CreateTranslation(2, 0, 0)); scene.AttachToCurrentTest("scene.glb"); }
public void CreateQuadsScene() { TestContext.CurrentContext.AttachShowDirLink(); TestContext.CurrentContext.AttachGltfValidatorLinks(); // this test checks that non convex quads are created correctly. var mesh = new MeshBuilder <VertexPosition>(); var prim = mesh.UsePrimitive(MaterialBuilder.CreateDefault()); var idx = prim.AddQuadrangle(new VertexPosition(0, -1, 0), new VertexPosition(1, 0, 0), new VertexPosition(0, 1, 0), new VertexPosition(-1, 0, 0)); Assert.AreEqual((0, 1, 2, 3), idx); idx = prim.AddQuadrangle(new VertexPosition(0, -1, 1), new VertexPosition(1, 0, 1), new VertexPosition(0, 1, 1), new VertexPosition(0.5f, 0, 1)); Assert.AreEqual((4, 5, 6, 7), idx); idx = prim.AddQuadrangle(new VertexPosition(0, 0.5f, 2), new VertexPosition(1, 0, 2), new VertexPosition(0, 1, 2), new VertexPosition(-1, 0, 2)); Assert.AreEqual((8, 9, 10, 11), idx); idx = prim.AddQuadrangle(new VertexPosition(1, 0, 3), new VertexPosition(0, 1, 3), new VertexPosition(0.5f, 0, 3), new VertexPosition(0, -1, 3)); Assert.AreEqual((12, 13, 14, 15), idx); idx = prim.AddQuadrangle(new VertexPosition(1, 0, 4), new VertexPosition(1, 0, 4), new VertexPosition(0, 1, 4), new VertexPosition(-1, 0, 4)); Assert.AreEqual((-1, 16, 17, 18), idx); idx = prim.AddQuadrangle(new VertexPosition(1, 0, 4), new VertexPosition(1, 0, 4), new VertexPosition(0, 1, 4), new VertexPosition(0, 1, 4)); Assert.AreEqual((-1, -1, -1, -1), idx); idx = prim.AddQuadrangle(new VertexPosition(0, 0, 5), new VertexPosition(10, -1, 5), new VertexPosition(9, 0, 5), new VertexPosition(10, 1, 5)); Assert.AreEqual((19, 20, 21, 22), idx); idx = prim.AddQuadrangle(new VertexPosition(10, -1, 6), new VertexPosition(9, 0, 6), new VertexPosition(10, 1, 6), new VertexPosition(0, 0, 6)); Assert.AreEqual((23, 24, 25, 26), idx); var scene = new SceneBuilder(); scene.AddMesh(mesh, Matrix4x4.Identity); scene.AttachToCurrentTest("cube.glb"); }
private static void _AddMeshInstances(SceneBuilder dstScene, IReadOnlyDictionary <Node, NodeBuilder> dstNodes, IReadOnlyList <Node> srcInstances) { var dstMeshes = srcInstances .Select(item => item.Mesh) .Distinct() .ToDictionary(item => item, item => item.ToMeshBuilder()); foreach (var srcInstance in srcInstances) { var dstMesh = dstMeshes[srcInstance.Mesh]; if (srcInstance.Skin == null) { var dstNode = dstNodes[srcInstance]; var dstInst = dstScene.AddRigidMesh(dstMesh, dstNode); _CopyMorphingAnimation(dstInst, srcInstance); } else { var joints = new (NodeBuilder, Matrix4x4)[srcInstance.Skin.JointsCount];
private static void _AddMeshInstances(SceneBuilder dstScene, IEnumerable <Node> srcNodes, IReadOnlyDictionary <Node, NodeBuilder> nodesDict, IReadOnlyDictionary <Node, MESHBUILDER> meshesDict) { foreach (var srcNode in srcNodes) { if (!meshesDict.TryGetValue(srcNode, out var dstMesh)) { continue; // nothing to do. } if (srcNode.Skin == null) { // rigid mesh instance var dstNode = nodesDict[srcNode]; var gpuInstancing = srcNode.GetGpuInstancing(); if (gpuInstancing == null) { var dstInstance = dstScene.AddRigidMesh(dstMesh, dstNode); _CopyMorphingAnimation(dstInstance, srcNode); } else { // use gpu instancing extension foreach (var xinst in gpuInstancing.LocalTransforms) { var dstInstance = dstScene.AddRigidMesh(dstMesh, dstNode, xinst); // if we add morphing to the mesh, all meshes would morph simultaneously?? _CopyMorphingAnimation(dstInstance, srcNode); } } } else { // skinned mesh instance var joints = new (NodeBuilder, Matrix4x4)[srcNode.Skin.JointsCount];
private static void _AddMeshInstances(SceneBuilder dstScene, IReadOnlyDictionary <Node, NodeBuilder> dstNodes, IReadOnlyList <Node> srcInstances) { var dstMeshes = srcInstances .Select(item => item.Mesh) .Distinct() .ToDictionary(item => item, item => item.ToMeshBuilder()); foreach (var srcInstance in srcInstances) { var dstMesh = dstMeshes[srcInstance.Mesh]; if (srcInstance.Skin == null) { var dstNode = dstNodes[srcInstance]; var gpuInstancing = srcInstance.GetGpuInstancing(); if (gpuInstancing != null) { foreach (var xinst in gpuInstancing.LocalTransforms) { var dstInst = dstScene.AddRigidMesh(dstMesh, dstNode, xinst); // if we add morphing the the mesh, all meshes would morph simultaneously?? _CopyMorphingAnimation(dstInst, srcInstance); } } else { var dstInst = dstScene.AddRigidMesh(dstMesh, dstNode); _CopyMorphingAnimation(dstInst, srcInstance); } } else { var joints = new (NodeBuilder, Matrix4x4)[srcInstance.Skin.JointsCount];
public void CreateCubeSceneWithExtras() { TestContext.CurrentContext.AttachGltfValidatorLinks(); var material = MaterialBuilder.CreateDefault(); material.Name = "hello name"; material.Extras = IO.JsonContent.Serialize(new KeyValuePair <string, int>("hello", 16)); var mesh = new Cube <MaterialBuilder>(material).ToMesh(Matrix4x4.Identity); mesh.Name = "world name"; mesh.Extras = "world extras"; var scene = new SceneBuilder(); scene.AddRigidMesh(mesh, Matrix4x4.Identity) .WithName("Cube") .WithExtras(17); scene.AttachToCurrentTest("cube.glb"); scene.AttachToCurrentTest("cube.gltf"); scene.AttachToCurrentTest("cube.plotly"); }
public void AddScene(Scene dstScene, SceneBuilder srcScene) { _Nodes.Clear(); AddArmatureResources(new[] { srcScene }, () => dstScene.CreateNode()); // gather single operators (RigidTransformer and SkinnedTransformer) var srcSingleOperators = srcScene .Instances .Select(item => item.Content) .Where(item => !Geometry.MeshBuilderToolkit.IsEmpty(item.GetGeometryAsset())) .OfType <IOperator <Scene> >(); // gather multi operators (Fixed Transformer) var srcChildren = srcScene .Instances .Select(item => item.Content) .Where(item => !Geometry.MeshBuilderToolkit.IsEmpty(item.GetGeometryAsset())) .OfType <FixedTransformer>(); var srcMultiOperators = _MeshInstancing.CreateFrom(srcChildren, this.GpuMeshInstancingMinCount); // apply operators var srcOperators = srcSingleOperators.Concat(srcMultiOperators); foreach (var op in srcOperators) { op.ApplyTo(dstScene, this); } #if DEBUG srcScene._VerifyConversion(dstScene); #endif }
public void AddScene(Scene dstScene, SceneBuilder srcScene, bool useStridedBuffers = true) { // gather all unique MeshBuilders var srcMeshes = srcScene.Instances .Select(item => item.Content?.GetGeometryAsset()) .Where(item => item != null) .Distinct() .ToArray(); // gather all unique MaterialBuilders var materialGroups = srcMeshes .SelectMany(item => item.Primitives) .Where(item => !Geometry.MeshBuilderToolkit.IsEmpty(item)) .Select(item => item.Material) .Distinct() .ToList() // group by equal content, to reduce material splitting whenever possible. .GroupBy(item => item, Materials.MaterialBuilder.ContentComparer); // create a Schema2.Material for every MaterialBuilder. foreach (var mg in materialGroups) { var val = dstScene.LogicalParent.CreateMaterial(mg.Key); foreach (var key in mg) { _Materials[key] = val; } } // create a Schema2.Mesh for every MeshBuilder. var dstMeshes = dstScene.LogicalParent.CreateMeshes(mat => _Materials[mat], useStridedBuffers, srcMeshes); for (int i = 0; i < srcMeshes.Length; ++i) { _Meshes[srcMeshes[i]] = dstMeshes[i]; } // TODO: here we could check that every dstMesh has been correctly created. // gather all NodeBuilder unique armatures var armatures = srcScene.Instances .Select(item => item.Content?.GetArmatureAsset()) .Where(item => item != null) .Select(item => item.Root) .Distinct() .ToList(); // create Schema2.Node trees for every armature foreach (var armature in armatures) { CreateArmature(dstScene, armature); } // process instances var schema2Instances = srcScene .Instances .OfType <IOperator <Scene> >(); foreach (var inst in schema2Instances) { inst.Setup(dstScene, this); } }
public void CreateAllAnimationTypesScene() { // 3D View 7.1908.9012.0 has an issue displaying off-center meshes with animated morph targets. TestContext.CurrentContext.AttachGltfValidatorLinks(); // create two materials var pink = new MaterialBuilder("material1") .WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 0, 1, 1)); var yellow = new MaterialBuilder("material2") .WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 1, 0, 1)); var mesh1 = VPOSNRM.CreateCompatibleMesh("shape1"); mesh1.AddCube(pink, Matrix4x4.Identity); var mesh2 = VPOSNRM.CreateCompatibleMesh("shape2"); mesh2.AddCube(yellow, Matrix4x4.Identity); var scene = new SceneBuilder(); var inst1 = scene.AddRigidMesh(mesh1, Matrix4x4.Identity); // meshes intended to support animation must be created using an armature var armature = new NodeBuilder(); armature.LocalTransform = Matrix4x4.CreateTranslation(2, 0, 0); var inst2 = scene.AddRigidMesh(mesh2, armature); scene.AttachToCurrentTest("static.glb"); scene.AttachToCurrentTest("static.gltf"); // up to this point, the scene has two plain unanimated cubes. var morphBuilder = mesh2.UseMorphTarget(0); morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(0), (Vector3.UnitY, Vector3.Zero)); morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(1), (Vector3.UnitY, Vector3.Zero)); morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(2), (Vector3.UnitY, Vector3.Zero)); morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(3), (Vector3.UnitY, Vector3.Zero)); // set default value. inst2.Content.UseMorphing().SetValue(1); // ser animation curve. var curve = inst2.Content.UseMorphing().UseTrackBuilder("Default"); curve.SetPoint(0, true, 0); curve.SetPoint(1, true, 1); curve.SetPoint(2, true, 0); var gltf = scene.ToGltf2(); TestContext.WriteLine(gltf.GetJsonPreview()); var meshIdx = 1; Assert.AreEqual(1, gltf.LogicalMeshes[meshIdx].Primitives[0].MorphTargetsCount); Assert.AreEqual(1, gltf.LogicalMeshes[meshIdx].MorphWeights[0]); Assert.AreEqual(1, gltf.LogicalAnimations.Count); scene.AttachToCurrentTest("mopth.glb"); scene.AttachToCurrentTest("mopth.gltf"); }
public void CreateDoubleSkinnedScene() { TestContext.CurrentContext.AttachGltfValidatorLinks(); // create two materials var pink = new MaterialBuilder("material1") .WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 0, 1, 1)) .WithDoubleSide(true); var yellow = new MaterialBuilder("material2") .WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 1, 0, 1)) .WithDoubleSide(true); // create the mesh const int jointIdx0 = 0; // index of joint node 0 const int jointIdx1 = 1; // index of joint node 1 const int jointIdx2 = 2; // index of joint node 2 var v1 = new SKINNEDVERTEX4(new Vector3(-10, 0, +10), (jointIdx0, 1)); var v2 = new SKINNEDVERTEX4(new Vector3(+10, 0, +10), (jointIdx0, 1)); var v3 = new SKINNEDVERTEX4(new Vector3(+10, 0, -10), (jointIdx0, 1)); var v4 = new SKINNEDVERTEX4(new Vector3(-10, 0, -10), (jointIdx0, 1)); var v5 = new SKINNEDVERTEX4(new Vector3(-10, 40, +10), (jointIdx0, 0.5f), (jointIdx1, 0.5f)); var v6 = new SKINNEDVERTEX4(new Vector3(+10, 40, +10), (jointIdx0, 0.5f), (jointIdx1, 0.5f)); var v7 = new SKINNEDVERTEX4(new Vector3(+10, 40, -10), (jointIdx0, 0.5f), (jointIdx1, 0.5f)); var v8 = new SKINNEDVERTEX4(new Vector3(-10, 40, -10), (jointIdx0, 0.5f), (jointIdx1, 0.5f)); var v9 = new SKINNEDVERTEX4(new Vector3(-5, 80, +5), (jointIdx2, 1)); var v10 = new SKINNEDVERTEX4(new Vector3(+5, 80, +5), (jointIdx2, 1)); var v11 = new SKINNEDVERTEX4(new Vector3(+5, 80, -5), (jointIdx2, 1)); var v12 = new SKINNEDVERTEX4(new Vector3(-5, 80, -5), (jointIdx2, 1)); var mesh = SKINNEDVERTEX4.CreateCompatibleMesh("mesh1"); #if DEBUG mesh.VertexPreprocessor.SetValidationPreprocessors(); #else mesh.VertexPreprocessor.SetSanitizerPreprocessors(); #endif mesh.UsePrimitive(pink).AddQuadrangle(v1, v2, v6, v5); mesh.UsePrimitive(pink).AddQuadrangle(v2, v3, v7, v6); mesh.UsePrimitive(pink).AddQuadrangle(v3, v4, v8, v7); mesh.UsePrimitive(pink).AddQuadrangle(v4, v1, v5, v8); mesh.UsePrimitive(yellow).AddQuadrangle(v5, v6, v10, v9); mesh.UsePrimitive(yellow).AddQuadrangle(v6, v7, v11, v10); mesh.UsePrimitive(yellow).AddQuadrangle(v7, v8, v12, v11); mesh.UsePrimitive(yellow).AddQuadrangle(v8, v5, v9, v12); mesh.Validate(); // create the skeleton armature 1 for the skinned mesh. var armature1 = new NodeBuilder("Skeleton1"); var joint0 = armature1.CreateNode("Joint 0").WithLocalTranslation(new Vector3(0, 0, 0)); // jointIdx0 var joint1 = joint0.CreateNode("Joint 1").WithLocalTranslation(new Vector3(0, 40, 0)); // jointIdx1 var joint2 = joint1.CreateNode("Joint 2").WithLocalTranslation(new Vector3(0, 40, 0)); // jointIdx2 joint1.UseRotation("Base Track") .WithPoint(1, Quaternion.Identity) .WithPoint(2, Quaternion.CreateFromYawPitchRoll(0, 1, 0)) .WithPoint(3, Quaternion.CreateFromYawPitchRoll(0, 0, 1)) .WithPoint(4, Quaternion.Identity); // create the skeleton armature 2 for the skinned mesh. var armature2 = new NodeBuilder("Skeleton2").WithLocalTranslation(new Vector3(100, 0, 0)); var joint3 = armature2.CreateNode("Joint 3").WithLocalTranslation(new Vector3(0, 0, 0)); // jointIdx0 var joint4 = joint3.CreateNode("Joint 4").WithLocalTranslation(new Vector3(0, 40, 0)); // jointIdx1 var joint5 = joint4.CreateNode("Joint 5").WithLocalTranslation(new Vector3(0, 40, 0)); // jointIdx2 joint4.UseRotation("Base Track") .WithPoint(1, Quaternion.Identity) .WithPoint(2, Quaternion.CreateFromYawPitchRoll(0, 1, 0)) .WithPoint(3, Quaternion.CreateFromYawPitchRoll(0, 0, 1)) .WithPoint(4, Quaternion.Identity); // create scene var scene = new SceneBuilder(); scene.AddSkinnedMesh ( mesh, armature1.WorldMatrix, joint0, // joint used for skinning joint index 0 joint1, // joint used for skinning joint index 1 joint2 // joint used for skinning joint index 2 ); scene.AddSkinnedMesh ( mesh, armature2.WorldMatrix, joint3, // joint used for skinning joint index 0 joint4, // joint used for skinning joint index 1 joint5 // joint used for skinning joint index 2 ); scene.AttachToCurrentTest("skinned.glb"); scene.AttachToCurrentTest("skinned.gltf"); }
public void CreateSceneWithRandomShapes(bool useGpuInstancing) { TestContext.CurrentContext.AttachGltfValidatorLinks(); var rnd = new Random(177); // create materials var materials = Enumerable .Range(0, 10) .Select(idx => new MaterialBuilder() .WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(rnd.NextVector3(), 1))) .ToList(); // create meshes var sphereMeshes = Enumerable .Range(0, 10) .Select(idx => materials[idx]) .Select(mat => { var mesh = VPOSNRM.CreateCompatibleMesh("shape"); #if DEBUG mesh.VertexPreprocessor.SetValidationPreprocessors(); #else mesh.VertexPreprocessor.SetSanitizerPreprocessors(); #endif mesh.AddSphere(mat, 0.5f, Matrix4x4.Identity); mesh.Validate(); return(mesh); }); var cubeMeshes = Enumerable .Range(0, 10) .Select(idx => materials[idx]) .Select(mat => { var mesh = VPOSNRM.CreateCompatibleMesh("shape"); #if DEBUG mesh.VertexPreprocessor.SetValidationPreprocessors(); #else mesh.VertexPreprocessor.SetSanitizerPreprocessors(); #endif mesh.AddCube(mat, Matrix4x4.Identity); mesh.Validate(); return(mesh); }); var meshes = sphereMeshes.Concat(cubeMeshes).ToArray(); // create scene var scene = new SceneBuilder(); for (int i = 0; i < 100; ++i) { var mesh = meshes[rnd.Next(0, 20)]; // create random transform var r = rnd.NextQuaternion(); var t = rnd.NextVector3() * 25; scene.AddRigidMesh(mesh, (r, t)); } // collapse to glTF var gltf = scene.ToGltf2(useGpuInstancing ? SceneBuilderSchema2Settings.WithGpuInstancing : SceneBuilderSchema2Settings.Default); var bounds = Runtime.MeshDecoder.EvaluateBoundingBox(gltf.DefaultScene); // Assert.AreEqual(defaultBounds,instancedBounds); // save the model as GLB gltf.AttachToCurrentTest("shapes.glb"); scene.AttachToCurrentTest("shapes.plotly"); }
public static void AttachToCurrentTest(this Scenes.SceneBuilder scene, string fileName) { var model = scene.ToSchema2(); model.AttachToCurrentTest(fileName); }
internal static void _AddCameraTo(CameraTransform3D?_Camera, GLTFWriteSettings?settings, SharpGLTF.Scenes.SceneBuilder scene) { if (!_Camera.HasValue) { return; } var vcam = _Camera.Value; var camNode = new SharpGLTF.Scenes.NodeBuilder("CameraNode"); camNode.WorldMatrix = vcam.WorldMatrix; var cam = vcam; cam.WorldMatrix = Matrix4x4.Identity; vcam = cam; if (vcam.TryGetPerspectiveFieldOfView(out var vfov)) { var persp = new SharpGLTF.Scenes.CameraBuilder.Perspective(null, vfov, 0.1f); scene.AddCamera(persp, camNode); } else if (vcam.TryGetOrthographicScale(out var oscale)) { var ortho = new SharpGLTF.Scenes.CameraBuilder.Orthographic(oscale, oscale, 0.1f, 1000); scene.AddCamera(ortho, camNode); } if ((settings?.CameraSize ?? 0) > 0) { var camMesh = new GltfMeshScene3D(); vcam.DrawCameraTo(camMesh, settings.Value.CameraSize.Value); vcam.DrawFustrumTo(camMesh, settings.Value.CameraSize.Value * 0.05f, System.Drawing.Color.Yellow); scene.AddRigidMesh(camMesh.Mesh, camNode); } if (Matrix4x4.Invert(_Camera.Value.AxisMatrix, out var invMatrix)) { // scene.ApplyBasisTransform(invMatrix); } }
public ModelRoot SceneGroup( List <Vitaboy.Mesh> meshes, List <Vitaboy.Animation> animations, List <Microsoft.Xna.Framework.Graphics.Texture2D> textures, Vitaboy.Skeleton skel ) { var builder = new SharpGLTF.Scenes.SceneBuilder(); var framerate = 1 / 36f; var nodes = new Dictionary <Vitaboy.Bone, NodeBuilder>(); var transforms = new List <Matrix4x4>(); skel.ComputeBonePositions(skel.RootBone, Microsoft.Xna.Framework.Matrix.Identity); ConvertBone(nodes, skel.RootBone, new NodeBuilder(skel.RootBone.Name)); //animations must be uploaded as part of the bone. add them as animation tracks to the existing nodes var timeprops = new Dictionary <string, float>(); var useAnimID = animations.Count > 1; foreach (var anim in animations) { var name = anim.XSkillName ?? anim.Name; foreach (var motion in anim.Motions) { //find the bone we're creating a curve for var bone = nodes.Values.FirstOrDefault(x => x.Name == motion.BoneName); if (bone == null) { continue; //cannot add this curve to a bone } var root = bone.Name == "ROOT"; var scale = RecursiveScale(bone.Parent); if (motion.TimeProperties != null) { foreach (var tps in motion.TimeProperties) { foreach (var tp in tps.Items) { foreach (var prop in tp.Properties.Items) { foreach (var keyPair in prop.KeyPairs) { var tpname = name + "/" + tp.ID.ToString() + "/" + keyPair.Key; float value = 1; if (!float.TryParse(keyPair.Value, out value)) { value = 1; tpname += "=" + keyPair.Value; } timeprops[tpname] = value; } } } } } //create curves for rotation and translation CurveBuilder <Vector3> transCurve = null; CurveBuilder <Quaternion> rotCurve = null; if (motion.HasTranslation) { transCurve = bone.Translation.UseTrackBuilder(name); } if (motion.HasRotation) { rotCurve = bone.Rotation.UseTrackBuilder(name); } for (int i = 0; i < motion.FrameCount; i++) { var quat = new Quaternion(); Vector3 trans = new Vector3(); if (rotCurve != null) { quat = QuatConvert(anim.Rotations[i + motion.FirstRotationIndex]); } if (transCurve != null) { trans = Vec3Convert(anim.Translations[i + motion.FirstTranslationIndex]) / scale; } if (root) { quat = RotateQ * quat; trans = Vector3.Transform(trans, RotateM); } rotCurve?.SetPoint(i * framerate, quat, true); transCurve?.SetPoint(i * framerate, trans, true); } if (bone.Name == "R_LEG") { } } } var resultMeshes = new List <MeshBuilder <VertexPositionNormal, VertexTexture1, VertexJoints8x4> >(); var orderedBones = skel.Bones.Select(x => nodes[x]).ToArray(); var world = Matrix4x4.Identity; //Matrix4x4.CreateFromAxisAngle(new Vector3(0, 1, 0), (float)Math.PI / 2f); var outMesh = new MeshBuilder <VertexPositionNormal, VertexTexture1, VertexJoints8x4>("Avatar"); var meshi = 0; foreach (var mesh in meshes) { var tex = textures[meshi++]; var data = TextureToPng(tex); var material = new MaterialBuilder(mesh.SkinName ?? ("mesh_" + meshi)); var mtex = material.UseChannel(KnownChannels.BaseColor).UseTexture().WithPrimaryImage(new ArraySegment <byte>(data)); var prim = outMesh.UsePrimitive(material, 3); //todo: blend verts var previous = new List <VertexBuilder <VertexPositionNormal, VertexTexture1, VertexJoints8x4> >(); for (int i = 0; i < mesh.IndexBuffer.Length; i++) { var point = mesh.IndexBuffer[(i / 3) * 3 + (2 - (i % 3))]; //flip triangles var vert = mesh.VertexBuffer[point]; var texc = new Vector2(vert.TextureCoordinate.X, vert.TextureCoordinate.Y); var boneInd = (int)vert.Parameters.X; var blendInd = (int)vert.Parameters.Y; var mat = skel.Bones[boneInd].AbsoluteMatrix * RotateMX; var bmat = skel.Bones[blendInd].AbsoluteMatrix * RotateMX; VertexBuilder <VertexPositionNormal, VertexTexture1, VertexJoints8x4> nvert = ( new VertexPositionNormal( Vector3.Lerp(Vec3Convert(Microsoft.Xna.Framework.Vector3.Transform(vert.Position, mat)), Vec3Convert(Microsoft.Xna.Framework.Vector3.Transform(vert.BvPosition, bmat)), vert.Parameters.Z), Vector3.Lerp(Vec3Convert(Microsoft.Xna.Framework.Vector3.TransformNormal(vert.Normal, mat)), Vec3Convert(Microsoft.Xna.Framework.Vector3.TransformNormal(vert.BvNormal, bmat)), vert.Parameters.Z) ), new VertexTexture1(texc), new VertexJoints8x4(new SharpGLTF.Transforms.SparseWeight8(new Vector4(boneInd, blendInd, 0, 0), new Vector4(1 - vert.Parameters.Z, vert.Parameters.Z, 0, 0))) ); if (previous.Count == 2) { prim.AddTriangle(previous[0], previous[1], nvert); previous.Clear(); } else { previous.Add(nvert); } } } var skin = builder.AddSkinnedMesh(outMesh, world, orderedBones); skin.Name = "Skeleton"; var schema = builder.ToSchema2(); /* * var children = schema.LogicalScenes.FirstOrDefault().VisualChildren; * foreach (var child in children) * { * if (child.Skin == null) { //armature * var extras = child.TryUseExtrasAsDictionary(true); * foreach (var tp in timeprops) * { * extras.Add(tp.Key, tp.Value); * } * } * } */ //var extras = schema.LogicalNodes.FirstOrDefault(x => x.Name == "ROOT").TryUseExtrasAsDictionary(true); var extras = schema.LogicalScenes.FirstOrDefault().TryUseExtrasAsDictionary(true); foreach (var tp in timeprops) { extras.Add(tp.Key, tp.Value); } return(schema); }
internal InstanceBuilder(SceneBuilder parent) { _Parent = parent; }