protected override FbxScene CreateScene(FbxManager manager) { FbxScene scene = base.CreateScene(manager); // mesh shared by all instances FbxMesh sharedMesh = FbxMesh.Create(scene, m_meshName); FbxSurfaceMaterial sharedMaterial = FbxSurfacePhong.Create(scene, m_materialName); // add mesh to all nodes Queue <FbxNode> nodes = new Queue <FbxNode>(); for (int i = 0; i < scene.GetRootNode().GetChildCount(); i++) { nodes.Enqueue(scene.GetRootNode().GetChild(i)); } while (nodes.Count > 0) { FbxNode node = nodes.Dequeue(); node.SetNodeAttribute(sharedMesh); node.AddMaterial(sharedMaterial); for (int i = 0; i < node.GetChildCount(); i++) { nodes.Enqueue(node.GetChild(i)); } } return(scene); }
/// <summary> /// Unconditionally export this mesh object to the file. /// We have decided; this mesh is definitely getting exported. /// </summary> public FbxMesh ExportMesh(GameObject unityGo, FbxScene fbxScene) { var meshInfo = GetMeshInfo(unityGo); if (!meshInfo.IsValid) { return(null); } // create the mesh structure. FbxMesh fbxMesh = FbxMesh.Create(fbxScene, "Scene"); // Create control points. int NumControlPoints = meshInfo.VertexCount; fbxMesh.InitControlPoints(NumControlPoints); // copy control point data from Unity to FBX for (int v = 0; v < NumControlPoints; v++) { fbxMesh.SetControlPointAt(new FbxVector4(meshInfo.Vertices [v].x, meshInfo.Vertices [v].y, meshInfo.Vertices [v].z), v); } for (int f = 0; f < meshInfo.Triangles.Length / 3; f++) { fbxMesh.BeginPolygon(); fbxMesh.AddPolygon(meshInfo.Triangles [3 * f]); fbxMesh.AddPolygon(meshInfo.Triangles [3 * f + 1]); fbxMesh.AddPolygon(meshInfo.Triangles [3 * f + 2]); fbxMesh.EndPolygon(); } return(fbxMesh); }
public void TestGetMesh() { // make sure it doesn't crash using (FbxNode node = CreateObject("root")) { FbxMesh mesh = FbxMesh.Create(Manager, "mesh"); node.SetNodeAttribute(mesh); Assert.AreEqual(mesh, node.GetMesh()); } }
public void Init() { m_fbxManager = FbxManager.Create(); m_fbxMesh = FbxMesh.Create(m_fbxManager, ""); m_fbxLayer = m_fbxMesh.GetLayer(0); if (m_fbxLayer == null) { m_fbxMesh.CreateLayer(); m_fbxLayer = m_fbxMesh.GetLayer(0 /* default layer */); } }
/// <summary> /// Unconditionally export this mesh object to the file. /// We have decided; this mesh is definitely getting exported. /// </summary> public void ExportMesh(MeshInfo mesh, FbxNode fbxNode, FbxScene fbxScene) { if (!mesh.IsValid) { return; } NumMeshes++; NumTriangles += mesh.Triangles.Length / 3; NumVertices += mesh.VertexCount; // create the mesh structure. FbxMesh fbxMesh = FbxMesh.Create(fbxScene, "Mesh"); // Create control points. int NumControlPoints = mesh.VertexCount; fbxMesh.InitControlPoints(NumControlPoints); // copy control point data from Unity to FBX for (int v = 0; v < NumControlPoints; v++) { // convert from left to right-handed by negating x (Unity negates x again on import) fbxMesh.SetControlPointAt(new FbxVector4(-mesh.Vertices [v].x, mesh.Vertices [v].y, mesh.Vertices [v].z), v); } ExportNormalsEtc(mesh, fbxMesh); ExportVertexColors(mesh, fbxMesh); ExportUVs(mesh, fbxMesh); /* * Create polygons * Triangles have to be added in reverse order, * or else they will be inverted on import * (due to the conversion from left to right handed coords) */ for (int f = 0; f < mesh.Triangles.Length / 3; f++) { fbxMesh.BeginPolygon(); fbxMesh.AddPolygon(mesh.Triangles [3 * f + 2]); fbxMesh.AddPolygon(mesh.Triangles [3 * f + 1]); fbxMesh.AddPolygon(mesh.Triangles [3 * f]); fbxMesh.EndPolygon(); } // set the fbxNode containing the mesh fbxNode.SetNodeAttribute(fbxMesh); fbxNode.SetShadingMode(FbxNode.EShadingMode.eWireFrame); }
/// <summary> /// Unconditionally export this mesh object to the file. /// We have decided; this mesh is definitely getting exported. /// </summary> public FbxNode ExportMesh(MeshInfo meshInfo, FbxScene fbxScene, FbxNode fbxNode) { if (!meshInfo.IsValid) { Debug.LogError("Invalid mesh info"); return(null); } // create a node for the mesh FbxNode meshNode = FbxNode.Create(fbxScene, "geo"); // create the mesh structure. FbxMesh fbxMesh = FbxMesh.Create(fbxScene, "Mesh"); // Create control points. int NumControlPoints = meshInfo.VertexCount; fbxMesh.InitControlPoints(NumControlPoints); // copy control point data from Unity to FBX for (int v = 0; v < NumControlPoints; v++) { // convert from left to right-handed by negating x (Unity negates x again on import) fbxMesh.SetControlPointAt(new FbxVector4(-meshInfo.Vertices [v].x, meshInfo.Vertices [v].y, meshInfo.Vertices [v].z), v); } /* * Create polygons * Triangles have to be added in reverse order, * or else they will be inverted on import * (due to the conversion from left to right handed coords) */ for (int f = 0; f < meshInfo.Triangles.Length / 3; f++) { fbxMesh.BeginPolygon(); fbxMesh.AddPolygon(meshInfo.Triangles [3 * f + 2]); fbxMesh.AddPolygon(meshInfo.Triangles [3 * f + 1]); fbxMesh.AddPolygon(meshInfo.Triangles [3 * f]); fbxMesh.EndPolygon(); } // set the fbxNode containing the mesh meshNode.SetNodeAttribute(fbxMesh); meshNode.SetShadingMode(FbxNode.EShadingMode.eWireFrame); fbxNode.AddChild(meshNode); return(meshNode); }
/// <summary> /// Unconditionally export this mesh object to the file. /// We have decided; this mesh is definitely getting exported. /// </summary> public FbxMesh ExportMesh(MeshInfo meshInfo, FbxNode fbxNode, FbxScene fbxScene) { if (!meshInfo.IsValid) { return(null); } // create the mesh structure. FbxMesh fbxMesh = FbxMesh.Create(fbxScene, "Mesh"); // Create control points. int NumControlPoints = meshInfo.VertexCount; fbxMesh.InitControlPoints(NumControlPoints); // copy control point data from Unity to FBX for (int v = 0; v < NumControlPoints; v++) { // convert from left to right-handed by negating x (Unity negates x again on import) fbxMesh.SetControlPointAt(new FbxVector4(-meshInfo.Vertices [v].x, meshInfo.Vertices [v].y, meshInfo.Vertices [v].z), v); } ExportNormalsEtc(meshInfo, fbxMesh); ExportUVs(meshInfo, fbxMesh); var fbxMaterial = ExportMaterial(meshInfo.Material, fbxScene); fbxNode.AddMaterial(fbxMaterial); /* * Create polygons after FbxLayerElementMaterial have been created. * Triangles have to be added in reverse order, * or else they will be inverted on import * (due to the conversion from left to right handed coords) */ for (int f = 0; f < meshInfo.Triangles.Length / 3; f++) { fbxMesh.BeginPolygon(); fbxMesh.AddPolygon(meshInfo.Triangles [3 * f + 2]); fbxMesh.AddPolygon(meshInfo.Triangles [3 * f + 1]); fbxMesh.AddPolygon(meshInfo.Triangles [3 * f]); fbxMesh.EndPolygon(); } return(fbxMesh); }
protected override FbxScene CreateScene(FbxManager manager) { // Create a cube as a static mesh FbxScene scene = FbxScene.Create(manager, "myScene"); FbxNode meshNode = FbxNode.Create(scene, "MeshNode"); FbxMesh cubeMesh = FbxMesh.Create(scene, "cube"); meshNode.SetNodeAttribute(cubeMesh); scene.GetRootNode().AddChild(meshNode); cubeMesh.InitControlPoints(24); for (int i = 0; i < cubeMesh.GetControlPointsCount(); i++) { cubeMesh.SetControlPointAt(m_controlPoints [i], i); } // A cube: 6 polygons with 4 vertices each int[] vertices = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; for (int i = 0; i < 6; i++) { cubeMesh.BeginPolygon(pGroup: -1); for (int j = 0; j < 4; j++) { cubeMesh.AddPolygon(vertices[i * 4 + j]); } cubeMesh.EndPolygon(); } return(scene); }
/// <summary> /// Unconditionally export this mesh object to the file. /// We have decided; this mesh is definitely getting exported. /// </summary> public void ExportMesh(MeshInfo mesh, FbxNode fbxNode, FbxScene fbxScene) { if (!mesh.IsValid) { return; } NumMeshes++; NumTriangles += mesh.Triangles.Length / 3; NumVertices += mesh.VertexCount; // create the mesh structure. FbxMesh fbxMesh = FbxMesh.Create(fbxScene, "Mesh"); // Create control points. int NumControlPoints = mesh.VertexCount; fbxMesh.InitControlPoints(NumControlPoints); // copy control point data from Unity to FBX for (int v = 0; v < NumControlPoints; v++) { fbxMesh.SetControlPointAt(new FbxVector4(mesh.Vertices[v].x, mesh.Vertices[v].y, mesh.Vertices[v].z), v); } /* * Create polygons after FbxGeometryElementMaterial are created. * TODO: Assign material indices. */ int vId = 0; for (int f = 0; f < mesh.Triangles.Length / 3; f++) { fbxMesh.BeginPolygon(); fbxMesh.AddPolygon(mesh.Triangles [vId++]); fbxMesh.AddPolygon(mesh.Triangles [vId++]); fbxMesh.AddPolygon(mesh.Triangles [vId++]); fbxMesh.EndPolygon(); } // set the fbxNode containing the mesh fbxNode.SetNodeAttribute(fbxMesh); fbxNode.SetShadingMode(FbxNode.EShadingMode.eWireFrame); }
protected override FbxScene CreateScene(FbxManager manager) { // Create a cube as a static mesh FbxScene scene = FbxScene.Create(manager, "myScene"); FbxNode meshNode = FbxNode.Create(scene, "MeshNode"); FbxMesh cubeMesh = FbxMesh.Create(scene, "cube"); meshNode.SetNodeAttribute(cubeMesh); scene.GetRootNode().AddChild(meshNode); cubeMesh.InitControlPoints(24); for (int i = 0; i < cubeMesh.GetControlPointsCount(); i++) { cubeMesh.SetControlPointAt(m_controlPoints [i], i); } return(scene); }
public void TestBasics() { Assert.That(!string.IsNullOrEmpty(ModelExporter.GetVersionFromReadme())); // Test GetOrCreateLayer using (var fbxManager = FbxManager.Create()) { var fbxMesh = FbxMesh.Create(fbxManager, "name"); var layer0 = ModelExporter.GetOrCreateLayer(fbxMesh); Assert.That(layer0, Is.Not.Null); Assert.That(ModelExporter.GetOrCreateLayer(fbxMesh), Is.EqualTo(layer0)); var layer5 = ModelExporter.GetOrCreateLayer(fbxMesh, layer: 5); Assert.That(layer5, Is.Not.Null); Assert.That(layer5, Is.Not.EqualTo(layer0)); } // Test axis conversion: a x b in left-handed is the same as b x a // in right-handed (that's why we need to flip the winding order). var a = new Vector3(1, 0, 0); var b = new Vector3(0, 0, 1); var crossLeft = Vector3.Cross(a, b); Assert.That(ModelExporter.DefaultMaterial); // Test non-static functions. using (var fbxManager = FbxManager.Create()) { var fbxScene = FbxScene.Create(fbxManager, "scene"); var fbxNode = FbxNode.Create(fbxScene, "node"); var exporter = new ModelExporter(); // Test ExportMaterial: it exports and it re-exports bool result = exporter.ExportMaterial(ModelExporter.DefaultMaterial, fbxScene, fbxNode); Assert.IsTrue(result); var fbxMaterial = fbxNode.GetMaterial(0); Assert.That(fbxMaterial, Is.Not.Null); result = exporter.ExportMaterial(ModelExporter.DefaultMaterial, fbxScene, fbxNode); var fbxMaterial2 = fbxNode.GetMaterial(1); Assert.AreEqual(fbxMaterial, fbxMaterial2); // Test ExportTexture: it finds the same texture for the default-material (it doesn't create a new one) var fbxMaterialNew = FbxSurfaceLambert.Create(fbxScene, "lambert"); exporter.ExportTexture(ModelExporter.DefaultMaterial, "_MainTex", fbxMaterialNew, FbxSurfaceLambert.sBump); Assert.AreEqual( fbxMaterial.FindProperty(FbxSurfaceLambert.sDiffuse).GetSrcObject(), fbxMaterialNew.FindProperty(FbxSurfaceLambert.sBump).GetSrcObject() ); // Test ExportMesh: make sure we exported a mesh with welded vertices. var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); var cubeNode = FbxNode.Create(fbxScene, "cube"); exporter.ExportMesh(cube.GetComponent <MeshFilter>().sharedMesh, cubeNode); Assert.That(cubeNode.GetMesh(), Is.Not.Null); Assert.That(cubeNode.GetMesh().GetControlPointsCount(), Is.EqualTo(8)); } // Test exporting a skinned-mesh. Make sure it doesn't leak (it did at one point) { var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); var character = new GameObject(); var smr = character.AddComponent <SkinnedMeshRenderer>(); smr.sharedMesh = cube.GetComponent <MeshFilter>().sharedMesh; var meshCount = Object.FindObjectsOfType <Mesh>().Length; ModelExporter.ExportObject(GetRandomFbxFilePath(), character); Assert.AreEqual(meshCount, Object.FindObjectsOfType <Mesh>().Length); } // Test euler to quaternion conversion { // EulerToQuaternionZXY var v = new Vector3(50, 45, 190); var quat = ModelExporter.EulerToQuaternionZXY(v); var unityQuat = Quaternion.Euler(v); Assert.That((float)quat.X, Is.EqualTo(unityQuat.x)); Assert.That((float)quat.Y, Is.EqualTo(unityQuat.y)); Assert.That((float)quat.Z, Is.EqualTo(unityQuat.z)); Assert.That((float)quat.W, Is.EqualTo(unityQuat.w)); // EulerToQuaternionXYZ var fbxV = new FbxVector4(v.x, v.y, v.z); var xyzQuat = ModelExporter.EulerToQuaternionXYZ(fbxV); // get the vector from the quaternion FbxAMatrix m = new FbxAMatrix(); m.SetR(fbxV); var actualQuat = m.GetQ(); // since this quaternion is XYZ instead of ZXY, it should not match the quaternion // created with EulerToQuaternionZXY Assert.That(xyzQuat, Is.Not.EqualTo(quat)); Assert.That(xyzQuat, Is.EqualTo(actualQuat)); } }
// For use only by FbxExportGlobals. internal static FbxMesh CreateFbxMesh(FbxExportGlobals G, GeometryPool pool, string poolName) { FbxMesh fbxMesh = FbxMesh.Create(G.m_manager, poolName); ExportMesh mesh = new ExportMesh(pool); int nVerts = mesh.m_pool.m_Vertices.Count; fbxMesh.InitControlPoints(nVerts); unsafe { fixed(Vector3 *f = mesh.m_pool.m_Vertices.GetBackingArray()) { Globals.SetControlPoints(fbxMesh, (IntPtr)f); } } List <int> triangles = mesh.m_pool.m_Tris; // Not available in Unity's wrappers // fbxMesh.ReservePolygonCount(triangles.Count / 3); // fbxMesh.ReservePolygonVertexCount(triangles.Count); for (int i = 0; i < triangles.Count; i += 3) { fbxMesh.BeginPolygon(-1 /* Material */, -1 /* Texture */, -1 /* Group */, false /* Legacy */); fbxMesh.AddPolygon(triangles[i]); fbxMesh.AddPolygon(triangles[i + 1]); fbxMesh.AddPolygon(triangles[i + 2]); fbxMesh.EndPolygon(); } FbxLayer layer0 = fbxMesh.GetLayer(0); if (layer0 == null) { fbxMesh.CreateLayer(); layer0 = fbxMesh.GetLayer(0); } var layerElementNormal = FbxLayerElementNormal.Create(fbxMesh, "normals"); layerElementNormal.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); layerElementNormal.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); CopyToFbx(layerElementNormal.GetDirectArray(), mesh.m_pool.m_Normals); layer0.SetNormals(layerElementNormal); var layerElementColor = FbxLayerElementVertexColor.Create(fbxMesh, "color"); layerElementColor.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); layerElementColor.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); CopyToFbx(layerElementColor.GetDirectArray(), mesh.m_linearColor); layer0.SetVertexColors(layerElementColor); var layerElementTangent = FbxLayerElementTangent.Create(fbxMesh, "tangents"); layerElementTangent.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); layerElementTangent.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); CopyToFbx(layerElementTangent.GetDirectArray(), mesh.m_pool.m_Tangents); layer0.SetTangents(layerElementTangent); // Compute and export binormals since Unity's FBX importer won't import the tangents without // them, even though they're not used. var layerElementBinormal = FbxLayerElementBinormal.Create(fbxMesh, "binormals"); layerElementBinormal.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); layerElementBinormal.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); var binormals = mesh.m_pool.m_Tangents .Select((tan, idx) => { var b3 = Vector3.Cross(tan, mesh.m_pool.m_Normals[idx]) * tan.w; return(new Vector4(b3.x, b3.y, b3.z, 1)); }) .ToList(); CopyToFbx(layerElementBinormal.GetDirectArray(), binormals); layer0.SetBinormals(layerElementBinormal); var layerElementMaterial = FbxLayerElementMaterial.Create(fbxMesh, "materials"); layerElementMaterial.SetMappingMode(FbxLayerElement.EMappingMode.eAllSame); layer0.SetMaterials(layerElementMaterial); // Export everything up to the last uvset containing data // even if some intermediate uvsets have no data. // Otherwise Unity will get the uvset numbering wrong on import List <List <Vector2> > uvSets = DemuxTexcoords(mesh.m_pool); for (int i = 0; i < uvSets.Count; i++) { FbxLayer layerN = fbxMesh.GetLayer(i); while (layerN == null) { fbxMesh.CreateLayer(); layerN = fbxMesh.GetLayer(i); } var layerElementUV = FbxLayerElementUV.Create(fbxMesh, String.Format("uv{0}", i)); layerElementUV.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); layerElementUV.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); List <Vector2> uvSet = uvSets[i]; if (uvSet == null) { // Do nothing // Replicates what the old fbx export code did; seems to work fine } else { Debug.Assert(uvSet.Count == nVerts); CopyToFbx(layerElementUV.GetDirectArray(), uvSet); } layerN.SetUVs(layerElementUV, FbxLayerElement.EType.eTextureDiffuse); } return(fbxMesh); }
public static bool ExportToFBX(Component_Mesh sourceMesh, string realFileName, out string error) { //!!!!как для Vegetation. оверрайдить в Component_Mesh? //get mesh data var operations = new List <Component_RenderingPipeline.RenderSceneData.MeshDataRenderOperation>(); foreach (var geometry in sourceMesh.GetComponents <Component_MeshGeometry>()) { if (geometry.Enabled) { geometry.CompileDataOfThisObject(out var operation); if (operation != null) { operations.Add(operation); } } } //foreach( var geometry in mesh.Result.MeshData.RenderOperations ) //{ //} FbxManager manager = null; FbxIOSettings setting = null; FbxExporter exporter = null; FbxScene scene = null; try { //init FBX manager manager = FbxManager.Create(); setting = FbxIOSettings.Create(manager, "IOSRoot"); manager.SetIOSettings(setting); scene = FbxScene.Create(manager, "scene"); scene.GetGlobalSettings().SetAxisSystem(new FbxAxisSystem(FbxAxisSystem.EPreDefinedAxisSystem.eMax)); scene.GetGlobalSettings().SetSystemUnit(new FbxSystemUnit(100)); //init FBX scene for (int nOper = 0; nOper < operations.Count; nOper++) { var oper = operations[nOper]; //get data Vector3F[] positions = null; Vector3F[] normals = null; var texCoords = new List <Vector2F[]>(); ColorValue[] colors = null; Vector3F[] tangents = null; Vector3F[] binormals = null; //Position { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Position, out VertexElement element) && element.Type == VertexElementType.Float3) { var buffer = oper.VertexBuffers[element.Source]; positions = buffer.ExtractChannel <Vector3F>(element.Offset); } } //Normal { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Normal, out VertexElement element) && element.Type == VertexElementType.Float3) { var buffer = oper.VertexBuffers[element.Source]; normals = buffer.ExtractChannel <Vector3F>(element.Offset); } } //TexCoord for (var channel = VertexElementSemantic.TextureCoordinate0; channel <= VertexElementSemantic.TextureCoordinate3; channel++) { if (oper.VertexStructure.GetElementBySemantic(channel, out VertexElement element) && element.Type == VertexElementType.Float2) { var buffer = oper.VertexBuffers[element.Source]; texCoords.Add(buffer.ExtractChannel <Vector2F>(element.Offset)); } } //Color { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Color0, out VertexElement element)) { if (element.Type == VertexElementType.Float4) { var buffer = oper.VertexBuffers[element.Source]; var values = buffer.ExtractChannel <Vector4F>(element.Offset); colors = new ColorValue[positions.Length]; int destIndex = 0; foreach (var p in values) { colors[destIndex++] = p.ToColorValue(); } } else if (element.Type == VertexElementType.ColorABGR) { //!!!!check var buffer = oper.VertexBuffers[element.Source]; var values = buffer.ExtractChannel <uint>(element.Offset); colors = new ColorValue[positions.Length]; int destIndex = 0; foreach (var p in values) { colors[destIndex++] = new ColorValue(ColorByte.FromABGR(p)); } } else if (element.Type == VertexElementType.ColorARGB) { //!!!!check var buffer = oper.VertexBuffers[element.Source]; var values = buffer.ExtractChannel <uint>(element.Offset); colors = new ColorValue[positions.Length]; int destIndex = 0; foreach (var p in values) { colors[destIndex++] = new ColorValue(ColorByte.FromARGB(p)); } } } } //Tangent, Binormal if (normals != null) { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Tangent, out VertexElement element) && element.Type == VertexElementType.Float4) { var buffer = oper.VertexBuffers[element.Source]; var tangents4 = buffer.ExtractChannel <Vector4F>(element.Offset); tangents = new Vector3F[tangents4.Length]; binormals = new Vector3F[tangents4.Length]; int destIndex = 0; foreach (var p in tangents4) { tangents[destIndex] = p.ToVector3F(); binormals[destIndex] = Vector3F.Cross(p.ToVector3F(), normals[destIndex]) * p.W; destIndex++; } } } //indices int[] indices = null; if (oper.IndexBuffer != null) { indices = oper.IndexBuffer.Indices; } //create geometry var geometryName = "Geometry " + nOper.ToString(); var mesh = FbxMesh.Create(scene, geometryName); mesh.InitControlPoints(positions.Length); FbxLayerElementNormal elementNormals = null; if (normals != null) { elementNormals = mesh.CreateElementNormal(); elementNormals.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementNormals.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } FbxLayerElementVertexColor elementColors = null; if (colors != null) { elementColors = mesh.CreateElementVertexColor(); elementColors.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementColors.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } FbxLayerElementTangent elementTangents = null; if (tangents != null) { elementTangents = mesh.CreateElementTangent(); elementTangents.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementTangents.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } FbxLayerElementBinormal elementBinormals = null; if (binormals != null) { elementBinormals = mesh.CreateElementBinormal(); elementBinormals.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementBinormals.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } var uvElements = new List <FbxLayerElementUV>(); for (int uvIndex = 0; uvIndex < texCoords.Count; uvIndex++) { var pUVElement = mesh.CreateElementUV("texcoord" + uvIndex.ToString()); pUVElement.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); pUVElement.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); uvElements.Add(pUVElement); } for (int n = 0; n < positions.Length; n++) { mesh.SetControlPointAt(ToFbxVector4(positions[n]), n); if (normals != null) { elementNormals.GetDirectArray().Add(ToFbxVector4(normals[n])); } for (int uvIndex = 0; uvIndex < texCoords.Count; uvIndex++) { var texCoord = texCoords[uvIndex][n]; texCoord.Y = 1.0f - texCoord.Y; uvElements[uvIndex].GetDirectArray().Add(ToFbxVector2(texCoord)); } if (colors != null) { elementColors.GetDirectArray().Add(ToFbxColor(colors[n])); } if (tangents != null) { elementTangents.GetDirectArray().Add(ToFbxVector4(tangents[n])); } if (binormals != null) { elementBinormals.GetDirectArray().Add(ToFbxVector4(binormals[n])); } } if (normals != null) { mesh.GetLayer(0).SetNormals(elementNormals); } if (colors != null) { mesh.GetLayer(0).SetVertexColors(elementColors); } if (tangents != null) { mesh.GetLayer(0).SetTangents(elementTangents); } if (binormals != null) { mesh.GetLayer(0).SetBinormals(elementBinormals); } int polygonCount = indices.Length / 3; for (int i = 0; i < polygonCount; i++) { mesh.BeginPolygon(-1, -1, -1, false); for (int j = 0; j < 3; j++) { int currentIndex = i * 3 + j; int vertexIndex = indices[currentIndex]; mesh.AddPolygon(vertexIndex); } mesh.EndPolygon(); } var node = FbxNode.Create(scene, geometryName); node.SetNodeAttribute(mesh); scene.GetRootNode().AddChild(mesh.GetNode()); } //save exporter = FbxExporter.Create(manager, ""); if (!exporter.Initialize(realFileName, -1, manager.GetIOSettings())) { error = "Can't initialize FBX exporter."; return(false); } if (!exporter.Export(scene)) { error = "Export to FBX failed."; return(false); } } finally { try { scene?.Destroy(); } catch { } try { exporter?.Destroy(); } catch { } try { setting?.Destroy(); } catch { } try { manager?.Destroy(); } catch { } } foreach (var op in operations) { op.DisposeBuffers(); } error = ""; return(true); }
public void TestBasics() { Assert.That(!string.IsNullOrEmpty(ModelExporter.GetVersionFromReadme())); // Test GetOrCreateLayer using (var fbxManager = FbxManager.Create()) { var fbxMesh = FbxMesh.Create(fbxManager, "name"); var layer0 = ModelExporter.GetOrCreateLayer(fbxMesh); Assert.That(layer0, Is.Not.Null); Assert.That(ModelExporter.GetOrCreateLayer(fbxMesh), Is.EqualTo(layer0)); var layer5 = ModelExporter.GetOrCreateLayer(fbxMesh, layer: 5); Assert.That(layer5, Is.Not.Null); Assert.That(layer5, Is.Not.EqualTo(layer0)); } // Test axis conversion: a x b in left-handed is the same as b x a // in right-handed (that's why we need to flip the winding order). var a = new Vector3(1, 0, 0); var b = new Vector3(0, 0, 1); var crossLeft = Vector3.Cross(a, b); var afbx = ModelExporter.ConvertToRightHanded(a); var bfbx = ModelExporter.ConvertToRightHanded(b); Assert.AreEqual(ModelExporter.ConvertToRightHanded(crossLeft), bfbx.CrossProduct(afbx)); // Test scale conversion. Nothing complicated here... var afbxPosition = ModelExporter.ConvertToRightHanded(a, ModelExporter.UnitScaleFactor); Assert.AreEqual(100, afbxPosition.Length()); // Test rotation conversion. var q = Quaternion.Euler(new Vector3(0, 90, 0)); var fbxAngles = ModelExporter.ConvertQuaternionToXYZEuler(q); Assert.AreEqual(fbxAngles.X, 0); Assert.That(fbxAngles.Y, Is.InRange(-90.001, -89.999)); Assert.AreEqual(fbxAngles.Z, 0); Assert.That(ModelExporter.DefaultMaterial); // Test non-static functions. using (var fbxManager = FbxManager.Create()) { var fbxScene = FbxScene.Create(fbxManager, "scene"); var fbxNode = FbxNode.Create(fbxScene, "node"); var exporter = new ModelExporter(); // Test ExportMaterial: it exports and it re-exports bool result = exporter.ExportMaterial(ModelExporter.DefaultMaterial, fbxScene, fbxNode); Assert.IsTrue(result); var fbxMaterial = fbxNode.GetMaterial(0); Assert.That(fbxMaterial, Is.Not.Null); result = exporter.ExportMaterial(ModelExporter.DefaultMaterial, fbxScene, fbxNode); var fbxMaterial2 = fbxNode.GetMaterial(1); Assert.AreEqual(fbxMaterial, fbxMaterial2); // Test ExportTexture: it finds the same texture for the default-material (it doesn't create a new one) var fbxMaterialNew = FbxSurfaceLambert.Create(fbxScene, "lambert"); exporter.ExportTexture(ModelExporter.DefaultMaterial, "_MainTex", fbxMaterialNew, FbxSurfaceLambert.sBump); Assert.AreEqual( fbxMaterial.FindProperty(FbxSurfaceLambert.sDiffuse).GetSrcObject(), fbxMaterialNew.FindProperty(FbxSurfaceLambert.sBump).GetSrcObject() ); // Test ExportMesh: make sure we exported a mesh with welded vertices. var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); var cubeNode = FbxNode.Create(fbxScene, "cube"); exporter.ExportMesh(cube.GetComponent <MeshFilter>().sharedMesh, cubeNode); Assert.That(cubeNode.GetMesh(), Is.Not.Null); Assert.That(cubeNode.GetMesh().GetControlPointsCount(), Is.EqualTo(8)); } // Test exporting a skinned-mesh. Make sure it doesn't leak (it did at one point) { var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); var character = new GameObject(); var smr = character.AddComponent <SkinnedMeshRenderer>(); smr.sharedMesh = cube.GetComponent <MeshFilter>().sharedMesh; var meshCount = Object.FindObjectsOfType <Mesh>().Length; ModelExporter.ExportObject(GetRandomFbxFilePath(), character); Assert.AreEqual(meshCount, Object.FindObjectsOfType <Mesh>().Length); } }