示例#1
0
        public void FbxTime_CreateLongLong_HasSeconds()
        {
            // given:
            FbxTime time;

            // when:
            time = new FbxTime(0);

            // then:
            Assert.AreEqual(0.0, time.GetSecondDouble());
            Assert.AreEqual(0L, time.GetFrameCount());

            // when:
            time = new FbxTime(-7697693000L);

            // then:
            Assert.AreEqual(-5 / 30.0, time.GetSecondDouble());
            Assert.AreEqual(-5L, time.GetFrameCount());
        }
示例#2
0
        public ModelContent ImportModel(string filename, IContentImporter importer)
        {
            if (File.Exists(filename))
            {
            }
            else if (File.Exists(filename + ".fbx"))
            {
                filename += ".fbx";
            }
            else if (next != null)
            {
                return(next(filename, importer));
            }
            else
            {
                throw new FileNotFoundException("The file could not be found", filename);
            }

            var fimporter = new Importer();

            var scene = fimporter.Import(filename);



            var model = new ModelContent();

            model.Filename = filename;


            var bonesByNode = new Dictionary <Node, BoneContent>();
            var nodesByBone = new Dictionary <BoneContent, Node>();

            foreach (var node in scene.Nodes)
            {
                var bone = BoneFromNode(node);
                bonesByNode[node] = bone;
                nodesByBone[bone] = node;
                model.Bones.Add(bone);
                if (node == scene.GetRootNode())
                {
                    model.RootBoneIndex = model.Bones.Count - 1;
                    bone.Transform      = bone.Transform.Transposed();
                }
            }
            foreach (var node in scene.Nodes)
            {
                var bone = bonesByNode[node];

                if (node.GetNodeAttributeCount() > 0 &&
                    node.GetNodeAttributeByIndex(0) is Mesh)
                {
                    var mesh  = (Mesh)node.GetNodeAttributeByIndex(0);
                    var mesh2 = new MeshContent();
                    model.Meshes.Add(mesh2);
                    mesh2.ParentBone = bone;
                    mesh2.Name       = mesh.GetName();

                    bool          isSkinned = true;
                    ShaderContent vert;
                    if (mesh.GetDeformerCount() < 1)
                    {
                        isSkinned = false;
                        vert      = importer.ImportShaderStage("$basic", ShaderType.Vertex, importer);
                    }
                    else if (mesh.GetDeformerCount() > 1)
                    {
                        throw new NotImplementedException();
                    }
                    else
                    {
                        vert = importer.ImportShaderStage("$skinned", ShaderType.Vertex, importer);
                    }
                    var frag = importer.ImportShaderStage("$basic", ShaderType.Fragment, importer);

                    // calculate the global transform for the mesh

                    var meshTransform = node.EvaluateGlobalTransform();

                    // extract the vertex postions

                    var vertices =
                        Enumerable.Range(0, mesh.GetControlPointsCount())
                        .Select(ix => {
                        var cp    = mesh.GetControlPointAt((int)ix);
                        var baked = meshTransform.MultNormalize(cp);
                        var pos   = baked.ToChamber().ToVectorXYZ();
                        return(new Vertex_PBiBwNT {
                            Position = pos
                        });
                    })
                        .ToList();

                    // extract the blend indices and weights

                    if (mesh.GetDeformerCount() == 1)
                    {
                        if (!(mesh.GetDeformer(0) is Skin))
                        {
                            throw new NotImplementedException("Only Skin deformers are implemented");
                        }

                        var boneIndicesL =
                            Enumerable.Range(
                                0,
                                mesh.GetControlPointsCount())
                            .Select(x => new List <float>())
                            .ToList();
                        var boneWeightsL =
                            Enumerable.Range(
                                0,
                                mesh.GetControlPointsCount())
                            .Select(x => new List <float>())
                            .ToList();

                        int i;

                        var skin = (Skin)mesh.GetDeformer(0);
                        foreach (var cluster in skin.Clusters)
                        {
                            var cnode     = cluster.GetLink();
                            var cbone     = bonesByNode[cnode];
                            var boneIndex = model.Bones.IndexOf(cbone);

                            for (i = 0; i < cluster.ControlPointIndices.Count; i++)
                            {
                                var index  = cluster.ControlPointIndices[i];
                                var weight = cluster.ControlPointWeights[i];

                                if (boneIndicesL[index].Count > 4 ||
                                    boneWeightsL[index].Count > 4)
                                {
                                    throw new NotImplementedException("Too many indices or weights");
                                }

                                boneIndicesL[index].Add((float)boneIndex);
                                boneWeightsL[index].Add((float)weight);

                                if (boneIndicesL[index].Count > 4 ||
                                    boneWeightsL[index].Count > 4)
                                {
                                    throw new NotImplementedException("Too many indices or weights");
                                }
                            }
                        }

                        Func <List <float>, Vector4> convert = fs => {
                            if (fs.Count == 4)
                            {
                                return(new Vector4(fs[0], fs[1], fs[2], fs[3]));
                            }
                            if (fs.Count == 3)
                            {
                                return(new Vector4(fs[0], fs[1], fs[2], 0));
                            }
                            if (fs.Count == 2)
                            {
                                return(new Vector4(fs[0], fs[1], 0, 0));
                            }
                            if (fs.Count == 1)
                            {
                                return(new Vector4(fs[0], 0, 0, 0));
                            }
                            return(Vector4.Zero);
                        };

                        var boneIndicesV = boneIndicesL.Select(convert).ToList();
                        var boneWeightsV = boneWeightsL.Select(convert).ToList();

                        for (i = 0; i < vertices.Count; i++)
                        {
                            var vertex = vertices[i];
                            vertex.SetBlendIndices(boneIndicesV[i]);
                            vertex.SetBlendWeights(boneWeightsV[i]);
                            vertices[i] = vertex;
                        }
                    }


                    // construct a list of polygons
                    //  beyond this point, we don't need `vertices` until it
                    //  gets re-used to build the vertex buffer

                    var polygons = mesh.PolygonIndexes.Select(p =>
                                                              new PolygonBuilder {
                        PolygonVertexIndexes = p,
                        Vertexes             = p.Select(ix => vertices[(int)ix]).ToList(),
                    }).ToList();

                    var polygonsByMaterial = new Dictionary <SurfaceMaterial, List <PolygonBuilder> >();

                    // organize the mesh's polygons by material

                    var layer      = mesh.GetLayer(0);
                    var matelem    = layer.GetMaterials();
                    var matindexes = matelem.MaterialIndexes.List;// GetIndexArray().List;
                    if (matelem.ReferenceMode != LayerElement.EReferenceMode.IndexToDirect)
                    {
                        throw new NotImplementedException("A materials must have a reference mode of IndexToDirect");
                    }
                    if (matelem.MappingMode == LayerElement.EMappingMode.AllSame)
                    {
                        // only one material
                        var material = node.GetMaterial(matindexes[0]);

                        polygonsByMaterial[material] = new List <PolygonBuilder>(polygons);
                    }
                    else if (matelem.MappingMode == LayerElement.EMappingMode.ByPolygon)
                    {
                        // multiple materials
                        foreach (var mat in node.Materials)
                        {
                            polygonsByMaterial[mat] = new List <PolygonBuilder>();
                        }
                        int i;
                        for (i = 0; i < matindexes.Count; i++)
                        {
                            var mat = node.Materials[matindexes[i]];
                            polygonsByMaterial[mat].Add(polygons[i]);
                        }
                    }
                    else
                    {
                        throw new NotImplementedException("Materials must have mapping modes of AllSame or ByPolygon");
                    }

                    // extract the vertex normals

                    if (layer.GetNormals() != null)
                    {
                        var normalElement = layer.GetNormals();
                        if (normalElement.MappingMode != LayerElement.EMappingMode.ByPolygonVertex)
                        {
                            throw new NotImplementedException("Normals layer elements must have a mapping mode of ByPolygonVertex");
                        }
                        if (normalElement.ReferenceMode != LayerElement.EReferenceMode.Direct &&
                            normalElement.ReferenceMode != LayerElement.EReferenceMode.IndexToDirect)
                        {
                            throw new NotImplementedException("Normals layer elements must have a reference mode of Direct or IndexToDirect");
                        }
                        int k = 0;
                        foreach (var poly in polygons)
                        {
                            int i;
                            for (i = 0; i < poly.Vertexes.Count; i++)
                            {
                                int nindex;
                                if (normalElement.ReferenceMode == LayerElement.EReferenceMode.Direct)
                                {
                                    nindex = k;
                                }
                                else
                                {
                                    nindex = normalElement.GetIndexArray().GetAt(k);
                                }

                                var v      = normalElement.GetDirectArray().GetAt(nindex);
                                var vertex = poly.Vertexes[i];
                                vertex.Normal    = meshTransform.MultNormalize(v).ToChamber().ToVectorXYZ();
                                poly.Vertexes[i] = vertex;
                                k++;
                            }
                        }
                    }

                    // extract the texture coordinates

                    if (layer.GetUVs() != null)
                    {
                        var uvElement = layer.GetUVs();
                        if (uvElement.MappingMode != LayerElement.EMappingMode.ByPolygonVertex)
                        {
                            throw new NotImplementedException("UV layer elements must have a mapping mode of ByPolygonVertex");
                        }
                        if (uvElement.ReferenceMode != LayerElement.EReferenceMode.Direct &&
                            uvElement.ReferenceMode != LayerElement.EReferenceMode.IndexToDirect)
                        {
                            throw new NotImplementedException("UV layer elements must have a reference mode of Direct or IndexToDirect");
                        }
                        int k = 0;
                        foreach (var poly in polygons)
                        {
                            int i;
                            for (i = 0; i < poly.Vertexes.Count; i++)
                            {
                                int nindex;
                                if (uvElement.ReferenceMode == LayerElement.EReferenceMode.Direct)
                                {
                                    nindex = k;
                                }
                                else
                                {
                                    nindex = uvElement.GetIndexArray().GetAt(k);
                                }

                                var v      = uvElement.GetDirectArray().GetAt(nindex);
                                var vv     = v.ToChamber();
                                var vertex = poly.Vertexes[i];
                                vertex.SetTextureCoords(new ChamberLib.Vector2(vv.X, 1 - vv.Y));
                                poly.Vertexes[i] = vertex;
                                k++;
                            }
                        }
                    }

                    // trianglize polygons with more than three points

                    foreach (var mat in polygonsByMaterial.Keys.ToArray())
                    {
                        var polys = polygonsByMaterial[mat];
                        polygonsByMaterial[mat] = polys.SelectMany(p => {
                            if (p.Vertexes.Count < 3)
                            {
                                throw new InvalidOperationException();
                            }
                            if (p.Vertexes.Count == 3)
                            {
                                return(p.Yield());
                            }
                            int i;
                            var newPolys = new List <PolygonBuilder>();
                            for (i = 2; i < p.Vertexes.Count; i++)
                            {
                                var pb = new PolygonBuilder();

                                pb.PolygonVertexIndexes = new List <long>();
                                pb.PolygonVertexIndexes.Add(p.PolygonVertexIndexes[0]);
                                pb.PolygonVertexIndexes.Add(p.PolygonVertexIndexes[i - 1]);
                                pb.PolygonVertexIndexes.Add(p.PolygonVertexIndexes[i]);

                                pb.Vertexes = new List <Vertex_PBiBwNT>();
                                pb.Vertexes.Add(p.Vertexes[0]);
                                pb.Vertexes.Add(p.Vertexes[i - 1]);
                                pb.Vertexes.Add(p.Vertexes[i]);

                                newPolys.Add(pb);
                            }
                            return(newPolys);
                        }).ToList();
                    }

                    // construct the vertex and index buffers

                    var vertset = new HashSet <Vertex_PBiBwNT>();
                    vertices.Clear();
                    var indices = new List <int>();

                    var vertexBuffer = new VertexBufferContent();
                    var indexBuffer  = new IndexBufferContent();

                    model.VertexBuffers.Add(vertexBuffer);
                    model.IndexBuffers.Add(indexBuffer);

                    var indexByVertex = new Dictionary <Vertex_PBiBwNT, int>();

                    foreach (var mat in polygonsByMaterial.Keys)
                    {
                        var polys     = polygonsByMaterial[mat];
                        var polyverts = polys.SelectMany(p => p.Vertexes).ToArray();

                        var startIndex = indices.Count;

                        int n0 = vertices.Count;
                        vertices.AddRange(polyverts.Except(vertset));
                        int n1 = vertices.Count;
                        int i;
                        for (i = n0; i < n1; i++)
                        {
                            indexByVertex[vertices[i]] = i;
                        }

                        var polyindices = polyverts.Select(p => indexByVertex[p]);
                        indices.AddRange(polyindices);

                        vertset.AddRange(polyverts);

                        mesh2.Parts.Add(new PartContent()
                        {
                            Material       = GetMaterialFromMaterial(mat, vert, frag, importer, filename),
                            StartIndex     = startIndex,
                            PrimitiveCount = polys.Count,
                            Vertexes       = vertexBuffer,
                            Indexes        = indexBuffer,
                        });
                    }

                    indexBuffer.Indexes = indices.Select(ix => (short)ix).ToArray();

                    if (isSkinned)
                    {
                        vertexBuffer.Vertices = vertices.Cast <IVertex>().ToArray();
                    }
                    else
                    {
                        vertexBuffer.Vertices =
                            vertices.Select <Vertex_PBiBwNT, IVertex>(v =>
                                                                      new Vertex_PNT {
                            Position      = v.Position,
                            Normal        = v.Normal,
                            TextureCoords = v.TextureCoords,
                        }).ToArray();
                    }
                }
            }
            foreach (var node in scene.Nodes)
            {
                var bone = bonesByNode[node];
                int i;
                int n = node.GetChildCount();
                for (i = 0; i < n; i++)
                {
                    bone.ChildBoneIndexes.Add(scene.Nodes.IndexOf(node.GetChild(i)));
                }
            }

            if (scene.Poses.Count > 0)
            {
                var pose = scene.Poses[0];
                foreach (var pi in pose.PoseInfos)
                {
                    var bone = bonesByNode[pi.Node];
                    var m    = pi.Matrix.ToChamber();
                    bone.Transform = m;
                }
            }

            // animations

            Dictionary <string, AnimationSequence> sequences = null;
            var numstacks = scene.GetSrcObjectCount <AnimStack>();
            int j;

            for (j = 0; j < numstacks; j++)
            {
                var stack = scene.GetSrcObject <AnimStack>(j);

                if (sequences == null)
                {
                    sequences = new Dictionary <string, AnimationSequence>();
                }

                var timespan = stack.GetLocalTimeSpan();
                var layer    = (AnimLayer)stack.SrcObjects.FirstOrDefault(x => x is AnimLayer);

                scene.SetCurrentAnimationStack(stack);
                var        eval   = scene.GetAnimationEvaluator();
                var        frames = new List <AnimationFrame>();
                FbxTime    t;
                int        i;
                var        startOffset     = timespan.Start.GetSecondDouble();
                const int  framesPerSecond = 60;
                const long timeStep        = FbxTime.UnitsPerSecond / framesPerSecond;
                for (t = timespan.Start; t.Value <= timespan.Stop.Value; t = new FbxTime(t.Value + timeStep))
                {
                    var transforms = new ChamberLib.Matrix[model.Bones.Count];
                    for (i = 0; i < model.Bones.Count; i++)
                    {
                        var node = nodesByBone[model.Bones[i]];
                        var m    = eval.GetNodeLocalTransform(node, t).ToChamber();

                        transforms[i] = m;
                    }
                    frames.Add(new AnimationFrame((float)(t.GetSecondDouble() - startOffset), transforms));
                }

                var name = stack.Name.Replace("AnimStack::", "");
                sequences.Add(
                    name,
                    new AnimationSequence(
                        (float)(timespan.Stop.GetSecondDouble() - timespan.Start.GetSecondDouble()),
                        frames.ToArray(),
                        name));
            }

            Matrix[]   localTransforms    = null;
            Matrix[]   absoluteTransforms = null;
            List <int> skeletonHierarchy  = null;

            if (model.Bones != null && model.Bones.Count > 0)
            {
                skeletonHierarchy = Enumerable.Repeat(-1, model.Bones.Count).ToList();
                int i;
                for (i = 0; i < model.Bones.Count; i++)
                {
                    foreach (var childIndex in model.Bones[i].ChildBoneIndexes)
                    {
                        skeletonHierarchy[childIndex] = i;
                    }
                }
                localTransforms = new Matrix[model.Bones.Count];
                var globalTransforms = model.Bones.Select(b => b.Transform).ToArray();
                for (i = 0; i < model.Bones.Count; i++)
                {
                    var p = skeletonHierarchy[i];
                    if (p < 0)
                    {
                        localTransforms[i] = globalTransforms[i];
                    }
                    else
                    {
                        localTransforms[i] = globalTransforms[i] * globalTransforms[p].Inverted();
                    }
                }

                absoluteTransforms = new Matrix[model.Bones.Count];
                for (i = 0; i < model.Bones.Count; i++)
                {
                    absoluteTransforms[i] = globalTransforms[i].Inverted();
                }
            }

            if (sequences != null ||
                localTransforms != null ||
                absoluteTransforms != null ||
                skeletonHierarchy != null)
            {
                if (sequences == null)
                {
                    sequences = new Dictionary <string, AnimationSequence>();
                }
                if (localTransforms == null)
                {
                    localTransforms = new Matrix[0];
                }
                if (absoluteTransforms == null)
                {
                    absoluteTransforms = new Matrix[0];
                }
                if (skeletonHierarchy == null)
                {
                    skeletonHierarchy = new List <int>();
                }

                model.AnimationData =
                    new AnimationData(
                        sequences,
                        localTransforms.ToList(),
                        absoluteTransforms.ToList(),
                        skeletonHierarchy);
            }

            return(model);
        }