/// <summary> /// Process a single UV dataset and return data for configuring a Mesh UV attribute /// </summary> private Vector2 [] ProcessUVSet(FbxLayerElementUV element, int [] polygonVertexIndices, int vertexCount) { Vector2 [] result = new Vector2 [polygonVertexIndices.Length]; FbxLayerElement.EReferenceMode referenceMode = element.GetReferenceMode(); FbxLayerElement.EMappingMode mappingMode = element.GetMappingMode(); // direct or via-index bool isDirect = referenceMode == FbxLayerElement.EReferenceMode.eDirect; var fbxElementArray = element.GetDirectArray(); var fbxIndexArray = isDirect ? null : element.GetIndexArray(); if (mappingMode == FbxLayerElement.EMappingMode.eByControlPoint) { if (fbxElementArray.GetCount() != vertexCount) { Debug.LogError(string.Format("UVSet size ({0}) does not match vertex count {1}", fbxElementArray.GetCount(), vertexCount)); return(null); } for (int i = 0; i < polygonVertexIndices.Length; i++) { int index = i; if (!isDirect) { index = fbxIndexArray.GetAt(i); } FbxVector2 fbxVector2 = fbxElementArray.GetAt(polygonVertexIndices [index]); Debug.Assert(fbxVector2.X >= float.MinValue && fbxVector2.X <= float.MaxValue); Debug.Assert(fbxVector2.Y >= float.MinValue && fbxVector2.Y <= float.MaxValue); result [i] = new Vector2((float)fbxVector2.X, (float)fbxVector2.Y); // UVs in FBX can contain NaNs, so we set these vertices to (0,0) if (float.IsNaN(result [i] [0]) || float.IsNaN(result [i] [1])) { Debug.LogWarning(string.Format("invalid UV detected at {0}", i)); result [i] = Vector2.zero; } } } else if (mappingMode == FbxLayerElement.EMappingMode.eAllSame) { FbxVector2 fbxVector2 = fbxElementArray.GetAt(0); Debug.Assert(fbxVector2.X >= float.MinValue && fbxVector2.X <= float.MaxValue); Debug.Assert(fbxVector2.Y >= float.MinValue && fbxVector2.Y <= float.MaxValue); Vector2 value = new Vector2((float)fbxVector2.X, (float)fbxVector2.Y); for (int i = 0; i < polygonVertexIndices.Length; i++) { result [i] = value; } } else { Debug.LogError("unsupported UV-to-Component mapping mode"); } return(result); }
protected override FbxMesh GenerateFbx() { string meshName = (Souls.meshRoot != null ? Souls.meshRoot.Name : "") + "_Mesh"; FbxMesh mesh = FbxMesh.Create(Scene, meshName); mesh.InitControlPoints(Souls.mesh.Vertices.Count); int layerIndex = mesh.CreateLayer(); FbxLayer layer = mesh.GetLayer(layerIndex); FbxLayerContainer layerContainer = FbxLayerContainer.Create(Scene, meshName + "_LayerContainer"); FbxLayerElementUV uv = FbxLayerElementUV.Create(layerContainer, "Diffuse"); layer.SetUVs(uv); FbxLayerElementNormal normal = FbxLayerElementNormal.Create(layerContainer, "Normal"); layer.SetNormals(normal); normal.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); normal.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); FbxLayerElementBinormal binormal = FbxLayerElementBinormal.Create(layerContainer, "Binormal"); layer.SetBinormals(binormal); FbxLayerElementTangent tangent = FbxLayerElementTangent.Create(layerContainer, "Tangent"); layer.SetTangents(tangent); tangent.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); tangent.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); for (int vertexIndex = 0; vertexIndex < Souls.mesh.Vertices.Count; ++vertexIndex) { FLVER.Vertex vertex = Souls.mesh.Vertices[vertexIndex]; Vector3 position = vertex.Position; // this fixes vertex positions since otherwise the model is turned inside out // and it appears like it holds weapons in the left hand position.Z = -position.Z; normal.GetDirectArray().Add(vertex.Normal.ToFbxVector4()); tangent.GetDirectArray().Add(new FbxVector4(vertex.Tangents[0].X, vertex.Tangents[0].Y, vertex.Tangents[0].Z)); Vector2 uvValue = new Vector2(0); if (vertex.UVs.Count > 0) { uvValue.X = vertex.UVs[0].X; uvValue.Y = vertex.UVs[0].Y; } uv.GetDirectArray().Add(uvValue.ToFbxVector2()); mesh.SetControlPointAt(position.ToFbxVector4(), vertexIndex); } for (int faceSetIndex = 0; faceSetIndex < Souls.mesh.FaceSets.Count; ++faceSetIndex) { FLVER2.FaceSet faceSet = Souls.mesh.FaceSets[faceSetIndex]; if (faceSet.Flags != FLVER2.FaceSet.FSFlags.None) { continue; } for (int faceStartIndex = 0; faceStartIndex < faceSet.Indices.Count; faceStartIndex += 3) { mesh.AddCompletePolygon( faceSet.Indices[faceStartIndex], faceSet.Indices[faceStartIndex + 1], faceSet.Indices[faceStartIndex + 2] ); //mesh.AddCompletePolygon( // faceSet.Indices[faceStartIndex + 2], // faceSet.Indices[faceStartIndex + 1], // faceSet.Indices[faceStartIndex] //); } } mesh.BuildMeshEdgeArray(); FbxGeometryConverter converter = new FbxGeometryConverter(Scene.GetFbxManager()); converter.ComputeEdgeSmoothingFromNormals(mesh); converter.ComputePolygonSmoothingFromEdgeSmoothing(mesh); return(mesh); }