Пример #1
0
        static void ReadMeshElements(MeshData data, ImportOptions importOptions, ref Matrix4 transform)
        {
            ReadUvSets(data);

            //flip with disabled FlipUVs, no flip when enabled
            if (!importOptions.ImportPostProcessFlags.HasFlag(ImportPostProcessFlags.FlipUVs))
            {
                CalcMiscProcess.FlipUVs(data.Vertices, data.VertexComponents);

                //ToDo : !!! Доделать FlipUV для Materials - там тоже Flip для Transform текстуры  .... tex->UVScaling(); tex->UVTranslation();
            }
            ReadColor(data);
            TransformVertices(data, transform);

            int uvSetIndexForNormalsAndTangents = 0;             //ToDo : пока 0, может не всегда?

            if (3 <= data.PolygonSize)
            {
                ReadNormals(data, importOptions, uvSetIndexForNormalsAndTangents, data.CalcCache, ref transform);
                if (importOptions.ImportPostProcessFlags.HasFlag(ImportPostProcessFlags.FixInfacingNormals) && data.NormalsSource != TangentsAndNormalsSource.None)
                {
                    if (CalcNormalsProcess.FixInfacingNormals(data.Vertices))
                    {
                        FbxImportLog.LogMessage(data.Node, "Infacing Normals Fixed");
                    }
                }

                ReadTangents(data, importOptions, uvSetIndexForNormalsAndTangents, data.CalcCache, ref transform);
            }
        }
Пример #2
0
        public static MeshData[] ProcMesh(FbxManager manager, FbxNode node, FbxMesh mesh, ImportOptions importOptions, Matrix4 additionalTransform)
        {
            var transform = additionalTransform * FbxMath.EvaluateGlobalTransform(node).ToMatrix4();

            transform = transform * FbxMath.GetGeometryOffset(node).ToMatrix4();
            var  converter = new FbxGeometryConverter(manager);
            bool success   = false;

            try
            {
                mesh    = FbxMesh.Cast(converter.Triangulate(mesh, false));                  //ToDo :? Может true? Чтобы не создавать второй mesh в Attribute
                success = true;
            }
            catch (Exception ex)
            {
                FbxImportLog.LogError(node, "Inside Triangulate error: " + ex);
            }
            if (!success || mesh == null)
            {
                return(null);
            }
            MeshData data = ReadTriangles(mesh, node);
            var      ret  = ReadMaterialsAndSplitByMaterials(data);

            foreach (var m in ret)
            {
                ReadMeshElements(m, importOptions, ref transform);
            }

            return(ret);
        }
Пример #3
0
        // key - control point index
        public static Dictionary <int, BoneAssignment> GetBoneAssignments(FbxMesh mesh, Skeleton skeleton)
        {
            var boneAssignments = new Dictionary <int, BoneAssignment>();
            var weightLists     = new Dictionary <int, List <(int, double)> >();

            int skinCount = mesh.GetDeformerCount(FbxDeformer.EDeformerType.eSkin);

            if (skinCount == 0)
            {
                return(null);
            }
            if (1 < skinCount)
            {
                FbxImportLog.LogMessage(mesh.GetNode(), "Warning! Multiple skins for the mesh");                   //??? Может ли быть в одном Mesh несколько Skins? Скорее всего нет, хоть API позволяет.
            }
            FbxSkin pSkin = FbxSkin.Cast(mesh.GetDeformer(0, FbxDeformer.EDeformerType.eSkin));

            int clusterCount = pSkin.GetClusterCount();

            for (int iCluster = 0; iCluster < clusterCount; iCluster++)
            {
                FbxCluster pCluster = pSkin.GetCluster(iCluster);

                FbxNode pLink = pCluster.GetLink();
                if (pLink == null)
                {
                    continue;
                }

                int weightCount = pCluster.GetControlPointIndicesCount();
                if (weightCount == 0)
                {
                    continue;
                }

                int boneIndex = skeleton.GetBoneIndexByNode(pLink);

                var weightIndices = IntArray.frompointer(pCluster.GetControlPointIndices());
                var weightValues  = DoubleArray.frompointer(pCluster.GetControlPointWeights());
                for (int i = 0; i < weightCount; i++)
                {
                    int    vertexIndex = weightIndices.getitem(i);
                    double weight      = weightValues.getitem(i);

                    if (!weightLists.TryGetValue(vertexIndex, out var lst))
                    {
                        lst = new List <(int, double)>();
                        weightLists[vertexIndex] = lst;
                    }

                    lst.Add((boneIndex, weight));
                }
            }

            foreach (var pair in weightLists)
            {
                boneAssignments[pair.Key] = ConvertBoneWeightListToBoneAssignment(pair.Value);
            }
            return(boneAssignments);
        }
Пример #4
0
        //Find the cluster that links to the skeleton bone node
        public static FbxCluster FindCluster(FbxNode boneNode, FbxSkin[] skins, out FbxSkin skin)
        {
            for (int i = 0; i < skins.Length; i++)
            {
                skin = skins[i];

                int nClusterCount = skin.GetClusterCount();
                for (int j = 0; j < nClusterCount; j++)
                {
                    FbxCluster fbxCluster = skin.GetCluster(j);
                    if (fbxCluster == null)
                    {
                        continue;
                    }

                    if (fbxCluster.GetLinkMode() == FbxCluster.ELinkMode.eAdditive && fbxCluster.GetAssociateModel() != null)
                    {
                        FbxImportLog.LogMessage(boneNode, "Warning! Associated model.");
                    }

                    if (fbxCluster.GetLink()?.GetUniqueID() == boneNode.GetUniqueID())
                    {
                        return(fbxCluster);
                    }
                }
            }

            skin = null;
            return(null);
        }
Пример #5
0
        // Compute per-face normals but store them per-vertex
        static void CalculateNormalForFace(VertexInfo[] vertices, RangeI indexRange, bool normalize)
        {
            if (indexRange.Size < 3)
            {
                for (int i = indexRange.Minimum; i < indexRange.Maximum; i++)
                {
                    vertices[i].Vertex.Normal = new Vector3F(Single.NaN, Single.NaN, Single.NaN);
                }
                FbxImportLog.LogWarning("To calculate the tangents a polygon must have > 2 vertices");
            }

            ref Vector3F p0     = ref vertices[indexRange.Minimum].Vertex.Position;
Пример #6
0
        static void CalculateTangentForFace(VertexInfo[] vertices, RangeI indexRange, Vector3F[] tangents, Vector3F[] bitangents, GetTextureCoord getTextureCoord = null)
        {
            // triangle or polygon... we always use only the first three indices. A polygon
            // is supposed to be planar anyways....

            if (indexRange.Size < 3)
            {
                for (int i = indexRange.Minimum; i < indexRange.Maximum; i++)
                {
                    tangents[i]   = new Vector3F(float.NaN, float.NaN, float.NaN);
                    bitangents[i] = new Vector3F(float.NaN, float.NaN, float.NaN);
                }
                FbxImportLog.LogWarning("To calculate the tangents a polygon must have > 2 vertices");
                return;
            }

            ref StandardVertex pt0 = ref vertices[indexRange.Minimum].Vertex;
Пример #7
0
        static void ReadColor(MeshData data)
        {
            FbxLayerElementVertexColor pVertexColors = data.Mesh.GetElementVertexColor();

            if (pVertexColors == null)
            {
                for (int i = 0; i < data.Vertices.Length; i++)
                {
                    data.Vertices[i].Vertex.Color = new ColorValue(1, 1, 1);
                }
                return;
            }

            var mappingMode = pVertexColors.GetMappingMode();

            if (!CheckPolygonVertexOrControlPoint(mappingMode))
            {
                FbxImportLog.LogWarning(data.Node, $"has unsupported VertexColors mapping mode: {pVertexColors.GetMappingMode()}");
                return;
            }
            data.VertexComponents |= StandardVertex.Components.Color;
            var indexArray  = pVertexColors.GetReferenceMode() != FbxLayerElement.EReferenceMode.eDirect ? pVertexColors.GetIndexArray() : null;
            var directArray = pVertexColors.GetDirectArray();

            for (int i = 0; i < data.Vertices.Length; i++)
            {
                ref VertexInfo vertex = ref data.Vertices[i];
                FbxColor       color  = null;
                switch (pVertexColors.GetMappingMode())
                {
                case FbxLayerElement.EMappingMode.eByPolygonVertex:
                    color = directArray.GetAt(indexArray?.GetAt(vertex.PolygonVertexIndex) ?? vertex.PolygonVertexIndex);
                    break;

                case FbxLayerElement.EMappingMode.eByControlPoint:
                    color = directArray.GetAt(indexArray?.GetAt(vertex.ControlPointIndex) ?? vertex.ControlPointIndex);
                    break;
                }
                data.Vertices[i].Vertex.Color = color?.ToColorValue() ?? new ColorValue(1, 1, 1);
            }
Пример #8
0
        //Calculates global transform of the node.
        //This function was taken from FBX SDK/Smaples/Transformations. Originaly it did not take into account AxisSystem, so the corrections to use AxisSystem was added.
        //Has the fbx sdk equivalent pNode.EvaluateGlobalTransform();
        //
        //Note: FBX Documentation for ConvertScene states - "The adjustment will affect the translation animation curves and the objects pivots values
        //(the rotation transformation is applied as a pre-rotation transform therefore the rotation animation curves do not need to be transformed)"
        //But ConvertScene, does not realy change node.PreRotation, these changes are in the matrix : node.GetScene().GetGlobalSettings().GetAxisSystem().GetMatrix
        //

        /*
         * Terminology:
         * Suffix "M" means this is a matrix, suffix "V" means it is a vector.
         * T is translation.
         * R is rotation.
         * S is scaling.
         * SH is shear.
         * GlobalRM(x) means the Global Rotation Matrix of node "x".
         * GlobalRM(P(x)) means the Global Rotation Matrix of the parent node of node "x".
         * All other transforms are described in the similar way.
         *
         * The algorithm description:
         * To calculate global transform of a node x according to different InheritType,
         * we need to calculate GlobalTM(x) and [GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x))] separately.
         * GlobalM(x) = GlobalTM(x) * [GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x))];
         *
         * InhereitType = RrSs:
         * GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * LocalRM(x) * [GlobalSHM(P(x)) * GlobalSM(P(x))] * LocalSM(x);
         *
         * InhereitType = RSrs:
         * GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * [GlobalSHM(P(x)) * GlobalSM(P(x))] * LocalRM(x) * LocalSM(x);
         *
         * InhereitType = Rrs:
         * GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * LocalRM(x) * LocalSM(x);
         *
         * LocalM(x)= TM(x) * RoffsetM(x)  * RpivotM(x) * RpreM(x) * RM(x) * RpostM(x) * RpivotM(x)^-1 * SoffsetM(x) *SpivotM(x) * SM(x) * SpivotM(x)^-1
         * LocalTWithAllPivotAndOffsetInformationV(x) = Local(x).GetT();
         * GlobalTV(x) = GlobalM(P(x)) * LocalTWithAllPivotAndOffsetInformationV(x);
         *
         * Notice: FBX SDK does not support shear yet, so all local transform won't have shear.
         * However, global transform might bring in shear by combine the global transform of node in higher hierarchy.
         * For example, if you scale the parent by a non-uniform scale and then rotate the child node, then a shear will
         * be generated on the child node's global transform.
         * In this case, we always compensates shear and store it in the scale matrix too according to following formula:
         * Shear*Scaling = RotationMatrix.Inverse * TranslationMatrix.Inverse * WholeTranformMatrix
         */
        // ReSharper disable InconsistentNaming
        static FbxAMatrix CalculateGlobalTransform(FbxNode node)
        {
            if (node == null)
            {
                var ret = new FbxAMatrix();
                ret.SetIdentity();
                return(ret);
            }
            var lTranlationM     = new FbxAMatrix();
            var lScalingM        = new FbxAMatrix();
            var lScalingPivotM   = new FbxAMatrix();
            var lScalingOffsetM  = new FbxAMatrix();
            var lRotationOffsetM = new FbxAMatrix();
            var lRotationPivotM  = new FbxAMatrix();
            var lPreRotationM    = new FbxAMatrix();
            var lRotationM       = new FbxAMatrix();
            var lPostRotationM   = new FbxAMatrix();

            FbxAMatrix lParentGX = new FbxAMatrix();
            FbxAMatrix lGlobalT  = new FbxAMatrix();
            FbxAMatrix lGlobalRS = new FbxAMatrix();

            // Construct translation matrix
            FbxVector4 lTranslation = new FbxVector4(node.LclTranslation.Get());               //The fourth component of this object is assigned 1.

            lTranlationM.SetT(lTranslation);

            // Construct rotation matrices
            FbxVector4 lRotation     = new FbxVector4(node.LclRotation.Get());
            FbxVector4 lPreRotation  = new FbxVector4(node.PreRotation.Get());
            FbxVector4 lPostRotation = new FbxVector4(node.PostRotation.Get());

            lRotationM.SetR(lRotation);
            lPreRotationM.SetR(lPreRotation);
            lPostRotationM.SetR(lPostRotation);

            // Construct scaling matrix
            FbxVector4 lScaling = new FbxVector4(node.LclScaling.Get());

            lScalingM.SetS(lScaling);

            // Construct offset and pivot matrices
            FbxVector4 lScalingOffset  = new FbxVector4(node.ScalingOffset.Get());
            FbxVector4 lScalingPivot   = new FbxVector4(node.ScalingPivot.Get());
            FbxVector4 lRotationOffset = new FbxVector4(node.RotationOffset.Get());
            FbxVector4 lRotationPivot  = new FbxVector4(node.RotationPivot.Get());

            lScalingOffsetM.SetT(lScalingOffset);
            lScalingPivotM.SetT(lScalingPivot);
            lRotationOffsetM.SetT(lRotationOffset);
            lRotationPivotM.SetT(lRotationPivot);

            // Calculate the global transform matrix of the parent node
            FbxNode lParentNode = node.GetParent();

            if (lParentNode != null)
            {
                //Children of the root node must take into account the axis matrix.
                //Warning: this function CalculateGlobalTransform was taken from FBX SDK/Smaples/Transformations. Originaly it did not take into account AxisSystem
                if (lParentNode.GetParent() == null)
                {
                    FbxAMatrix axisMarix = new FbxAMatrix();
                    node.GetScene().GetGlobalSettings().GetAxisSystem().GetMatrix(axisMarix);
                    lPreRotationM = axisMarix.mul(lPreRotationM);
                }

                lParentGX = CalculateGlobalTransform(lParentNode);
            }
            else
            {
                lParentGX.SetIdentity();
            }

            //Construct Global Rotation
            FbxAMatrix lParentGRM = new FbxAMatrix();
            FbxVector4 lParentGR  = lParentGX.GetR();

            lParentGRM.SetR(lParentGR);
            var lLRM = lPreRotationM.mul(lRotationM).mul(lPostRotationM);

            //Construct Global Shear*Scaling
            //FBX SDK does not support shear, to patch this, we use:
            //Shear*Scaling = RotationMatrix.Inverse * TranslationMatrix.Inverse * WholeTranformMatrix
            FbxAMatrix lParentTM = new FbxAMatrix();
            FbxVector4 lParentGT = lParentGX.GetT();

            lParentTM.SetT(lParentGT);
            var lParentGRSM = lParentTM.Inverse().mul(lParentGX);
            var lParentGSM  = lParentGRM.Inverse().mul(lParentGRSM);
            var lLSM        = lScalingM;


            //Do not consider translation now
            FbxTransform.EInheritType lInheritType = node.InheritType.Get();
            if (lInheritType == FbxTransform.EInheritType.eInheritRrSs)
            {
                lGlobalRS = lParentGRM.mul(lLRM).mul(lParentGSM).mul(lLSM);
            }
            else if (lInheritType == FbxTransform.EInheritType.eInheritRSrs)
            {
                lGlobalRS = lParentGRM.mul(lParentGSM).mul(lLRM).mul(lLSM);
            }
            else if (lInheritType == FbxTransform.EInheritType.eInheritRrs)
            {
                if (lParentNode != null)
                {
                    FbxAMatrix lParentLSM = new FbxAMatrix();
                    FbxVector4 lParentLS  = new FbxVector4(lParentNode.LclScaling.Get());
                    lParentLSM.SetS(lParentLS);
                    FbxAMatrix lParentGSM_noLocal = lParentGSM.mul(lParentLSM.Inverse());
                    lGlobalRS = lParentGRM.mul(lLRM).mul(lParentGSM_noLocal).mul(lLSM);
                }
                else
                {
                    lGlobalRS = lParentGRM.mul(lLRM).mul(lLSM);
                }
            }
            else
            {
                FbxImportLog.LogError(node, "error, unknown inherit type!");
            }

            // Construct translation matrix
            // Calculate the local transform matrix
            var lTransform = lTranlationM.mul(lRotationOffsetM).mul(lRotationPivotM).mul(lPreRotationM).mul(lRotationM).mul(lPostRotationM)
                             .mul(lRotationPivotM.Inverse()).mul(lScalingOffsetM).mul(lScalingPivotM).mul(lScalingM).mul(lScalingPivotM.Inverse());
            FbxVector4 lLocalTWithAllPivotAndOffsetInfo = lTransform.GetT();
            // Calculate global translation vector according to:
            // GlobalTranslation = ParentGlobalTransform * LocalTranslationWithPivotAndOffsetInfo
            FbxVector4 lGlobalTranslation = lParentGX.MultT(lLocalTWithAllPivotAndOffsetInfo);

            lGlobalT.SetT(lGlobalTranslation);

            //Construct the whole global transform
            lTransform = lGlobalT.mul(lGlobalRS);

            return(lTransform);
        }