Пример #1
0
        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");
        }
Пример #2
0
        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);
        }