public void TestMaterialFbx(string filename) { var testFile = Path.Combine(PathHelper.FilesPath, filename); var documentNode = FbxIO.Read(testFile, ErrorLevel.Strict); var scaleFactor = documentNode.GetScaleFactor(); var materialIds = documentNode.GetMaterialIds(); Assert.True(materialIds.Length > 0); foreach (var materialId in materialIds) { var materialName = documentNode.GetMaterialName(materialId); var diffuseColor = documentNode.GetMaterialDiffuseColor(materialId); } var geometryIds = documentNode.GetGeometryIds(); Assert.True(geometryIds.Length > 0); foreach (var geometryId in geometryIds) { var vertexIndices = documentNode.GetVertexIndices(geometryId); var positions = documentNode.GetPositions(geometryId, vertexIndices); var tangents = documentNode.GetTangents(geometryId, vertexIndices); var binormals = documentNode.GetBinormals(geometryId, vertexIndices); var texCoords = documentNode.GetTexCoords(geometryId, vertexIndices); var materials = documentNode.GetMaterials(geometryId, vertexIndices); var hasTexCoords = documentNode.GetGeometryHasTexCoords(geometryId); var hasTangents = documentNode.GetGeometryHasTangents(geometryId); var hasBinormals = documentNode.GetGeometryHasBinormals(geometryId); } }
public static FbxAsset Import(string path) { if (!File.Exists(path)) { throw new FileNotFoundException("The file could not be found", path); } var document = FbxIO.ReadBinary("E:\\projects\\NEngineResources\\Glock.fbx"); var verticesNode = document.GetRelative("Objects/Geometry/Vertices"); var fbxAsset = new FbxAsset(); fbxAsset.Mesh = new Mesh(); if (verticesNode.Properties[0] is double[] vertices) { fbxAsset.Mesh.Vertices = new Vector3[vertices.Length / 3]; for (int i = 0, j = 0, len = vertices.Length; i < len; i += 3, j++) { var xPos = vertices[i]; var yPos = vertices[i + 1]; var zPos = vertices[i + 2]; fbxAsset.Mesh.Vertices[j] = new Vector3(xPos, yPos, zPos); } } var polygonVertexIndexNode = document.GetRelative("Objects/Geometry/PolygonVertexIndex"); if (polygonVertexIndexNode.Properties[0] is int[] polygonVertexIndex && polygonVertexIndex.Length >= 2) { bool quadMode = polygonVertexIndex[2] >= 0; if (quadMode) { fbxAsset.Mesh.Triangles = new Triangle[(polygonVertexIndex.Length / 4) * 2]; for (int i = 0, j = 0, len = polygonVertexIndex.Length; i < len; i += 4, j += 2) { var v1 = polygonVertexIndex[i]; var v2 = polygonVertexIndex[i + 1]; var v3 = polygonVertexIndex[i + 2]; var v4 = -polygonVertexIndex[i + 3] - 1; fbxAsset.Mesh.Triangles[j] = new Triangle(v1, v2, v4); fbxAsset.Mesh.Triangles[j + 1] = new Triangle(v4, v2, v3); } } else { fbxAsset.Mesh.Triangles = new Triangle[polygonVertexIndex.Length / 3]; for (int i = 0, j = 0, len = polygonVertexIndex.Length; i < len; i += 3, j++) { var v1 = polygonVertexIndex[i]; var v2 = polygonVertexIndex[i + 1]; var v3 = -polygonVertexIndex[i + 2] - 1; fbxAsset.Mesh.Triangles[j] = new Triangle(v1, v2, v3); } } } return(fbxAsset); }
private void TestCommon(byte[] data, bool isBinary) { // Binary using (var streamIn = new MemoryStream(data)) using (var streamOut = new MemoryStream()) using (var streamTmp = new MemoryStream()) { if (isBinary) { var reader = new FbxBinaryReader(streamIn); var doc = reader.Read(); FbxIO.WriteAscii(doc, streamOut); // read output again and ensure for correct output data streamOut.Position = 0; reader = new FbxBinaryReader(streamOut); FbxIO.WriteBinary(doc, streamTmp); } else { var reader = new FbxAsciiReader(streamIn); var doc = reader.Read(); FbxIO.WriteAscii(doc, streamOut); // read output again and ensure for correct output data streamOut.Position = 0; reader = new FbxAsciiReader(streamOut); FbxIO.WriteAscii(doc, streamTmp); } } }
public static void CompareBinaryFiles(string filename) { var testFile = Path.Combine(PathHelper.FilesPath, filename); var originalData = File.ReadAllBytes(testFile); var isBinary = FbxIO.IsBinaryFbx(testFile); Assert.True(isBinary); var documentNode = FbxIO.Read(testFile); using (var newStream = new MemoryStream()) { FbxIO.WriteBinary(documentNode, newStream); var newData = newStream.ToArray(); Assert.True(newData.Length <= originalData.Length, $"Unexpected size comparisson"); var identical = true; for (var i = 0; i < newData.Length; i++) { if (originalData[i] != newData[i]) { identical = false; break; } } Assert.True(identical, $"Files data did not match as expected"); } }
public static void StoreCurveNode(FbxAnimUtilities.CurveNodeIntfce pData, FbxIO mFileObject) { FbxWrapperNativePINVOKE.FbxAnimUtilities_StoreCurveNode(FbxAnimUtilities.CurveNodeIntfce.getCPtr(pData), FbxIO.getCPtr(mFileObject)); if (FbxWrapperNativePINVOKE.SWIGPendingException.Pending) { throw FbxWrapperNativePINVOKE.SWIGPendingException.Retrieve(); } }
static void ParseFbxTextures(string path, string downloadRoot, string destinationRoot) { //var isBinary = FbxIO.IsBinaryFbx(path); var documentNode = FbxIO.Read(path); Console.WriteLine("Parsing fbx - {0}", path); ParseNodes(documentNode.Nodes, downloadRoot, destinationRoot); }
public static FbxAnimUtilities.CurveNodeIntfce CreateCurveNode(FbxIO pFileObject, FbxAnimUtilities.CurveNodeIntfce pParent) { FbxAnimUtilities.CurveNodeIntfce ret = new FbxAnimUtilities.CurveNodeIntfce(FbxWrapperNativePINVOKE.FbxAnimUtilities_CreateCurveNode__SWIG_3(FbxIO.getCPtr(pFileObject), FbxAnimUtilities.CurveNodeIntfce.getCPtr(pParent)), true); if (FbxWrapperNativePINVOKE.SWIGPendingException.Pending) { throw FbxWrapperNativePINVOKE.SWIGPendingException.Retrieve(); } return(ret); }
public static FbxAnimUtilities.CurveNodeIntfce CreateCurveNode(FbxIO pFileObject, FbxAnimUtilities.CurveNodeIntfce pParent, bool pOnlyDefaults) { FbxAnimUtilities.CurveNodeIntfce ret = new FbxAnimUtilities.CurveNodeIntfce(fbx_wrapperPINVOKE.FbxAnimUtilities_CreateCurveNode__SWIG_2(FbxIO.getCPtr(pFileObject), FbxAnimUtilities.CurveNodeIntfce.getCPtr(pParent), pOnlyDefaults), true); if (fbx_wrapperPINVOKE.SWIGPendingException.Pending) { throw fbx_wrapperPINVOKE.SWIGPendingException.Retrieve(); } return(ret); }
static void Main(string[] args) { //var document = FbxIO.ReadBinary(args[0]); //FbxIO.WriteAscii(document, Path.GetDirectoryName(args[0]) + "/test_ascii.fbx"); var reader = new FbxAsciiReader(new FileStream(Path.GetDirectoryName(args[0]) + "/test_ascii.fbx", FileMode.Open)); var doc = reader.Read(); FbxIO.WriteAscii(doc, Path.GetDirectoryName(args[0]) + "/test_ascii_2.fbx"); }
public Task <IContentContainer> ReadAsync(Stream stream) { return(Task.Run(() => { var contentContainer = new ContentContainer(); var fbxDocument = FbxIO.Read(stream, ErrorLevel.Permissive); return (IContentContainer)contentContainer; })); }
public void Load(string path) { var rootNode = new View.FbxNodeItem(System.IO.Path.GetFileName(path)); var content = FbxIO.ReadBinary(path); foreach (var item in content.Nodes.Where(n => n != null)) { SeekNode(rootNode, item); } nodeModel.Nodes.Add(rootNode); }
public static void CompareAsciiFiles(string filename) { var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); var testFile = Path.Combine(path, "Files", filename); var isBinary = FbxIO.IsBinaryFbx(testFile); Assert.False(isBinary); var documentNode = FbxIO.Read(testFile); using (var tempStream = new MemoryStream()) { FbxIO.WriteAscii(documentNode, tempStream); tempStream.Position = 0; var originalBuffer = string.Empty; using (StreamReader originalStream = new StreamReader(testFile)) { while (originalStream.EndOfStream) { originalBuffer += FilterLine(originalStream.ReadLine()); } } var newBuffer = string.Empty; using (StreamReader newStream = new StreamReader(tempStream)) { while (newStream.EndOfStream) { newBuffer += FilterLine(newStream.ReadLine()); } } Assert.True(originalBuffer.Length == newBuffer.Length, $"Unexpected size comparisson"); var identical = true; for (var i = 0; i < newBuffer.Length; i++) { if (originalBuffer[i] != newBuffer[i]) { identical = false; break; } } Assert.True(identical, $"Files data did not match as expected"); } }
static void Test1() { string dir = @"C:\Users\dell\AppData\Local\Colossal Order\Cities_Skylines\Addons\Import\ARDumps\"; string file1 = "RoadMediumNode._ascii.fbx"; var doc = FbxIO.ReadAscii(dir + file1); string fileA = "testA_" + file1; FbxIO.WriteAscii(doc, dir + fileA); doc = FbxIO.ReadAscii(dir + fileA); string fileB = "testB_" + file1; FbxIO.WriteBinary(doc, dir + fileB); // i can't open this doc = FbxIO.ReadBinary(dir + fileB); FbxIO.WriteAscii(doc, dir + "testC_" + file1); // i can open this }
public YdrFile ConvertToYdr(string name, byte[] fbxdata) { var fdoc = FbxIO.Read(fbxdata); if (fdoc == null) { return(null); } var dwbl = TryConvertDrawable(fdoc, name); YdrFile ydr = new YdrFile(); ydr.Drawable = dwbl; ydr.Name = name; return(ydr); }
static void Test4() { Test3(); string dir = @"C:\Users\dell\AppData\Local\Colossal Order\Cities_Skylines\Addons\Import\ARDumps\"; string file1 = "RoadMediumNode._ascii.fbx"; // can open this string file2 = "TEST3_RoadMediumNode.binary.fbx"; // can open this string file3 = "TEST3_RoadMediumNode.ascii.fbx"; string fileB = "TEST3B_RoadMediumNode.binary.fbx"; Console.WriteLine("reading binary ..."); var doc1 = FbxIO.ReadBinary(dir + file2); FbxIO.WriteAscii(doc1, dir + file3); var doc2 = FbxIO.ReadAscii(dir + file3); doc1.Diff(doc2); FbxIO.WriteBinary(doc2, dir + fileB); }
public static FbxAnimUtilities.CurveNodeIntfce CreateCurveNode(FbxIO pFileObject) { FbxAnimUtilities.CurveNodeIntfce ret = new FbxAnimUtilities.CurveNodeIntfce(FbxWrapperNativePINVOKE.FbxAnimUtilities_CreateCurveNode__SWIG_1(FbxIO.getCPtr(pFileObject)), true); return(ret); }
public void TestFbx(string filename, bool expectedIsBinary, double expectedScaleFacor, bool expectedHasTexCoord, bool expectedHasTangent, bool expectedHasBinormal) { var testFile = Path.Combine(PathHelper.FilesPath, filename); Assert.True(expectedIsBinary == FbxIO.IsBinaryFbx(testFile), $"IsBinaryFbx expected {expectedIsBinary}"); var documentNode = FbxIO.Read(testFile, ErrorLevel.Strict); var scaleFactor = documentNode.GetScaleFactor(); Assert.True(expectedScaleFacor == scaleFactor, $"ScaleFactor expected {expectedScaleFacor}"); var materialIds = documentNode.GetMaterialIds(); var geometryIds = documentNode.GetGeometryIds(); Assert.True(geometryIds.Length > 0); var fbxIndexer = new FbxIndexer(); foreach (var geometryId in geometryIds) { var vertexIndices = documentNode.GetVertexIndices(geometryId); var positions = documentNode.GetPositions(geometryId, vertexIndices); var normals = documentNode.GetNormals(geometryId, vertexIndices); var tangents = documentNode.GetTangents(geometryId, vertexIndices); var binormals = documentNode.GetBinormals(geometryId, vertexIndices); var texCoords = documentNode.GetTexCoords(geometryId, vertexIndices); var materials = documentNode.GetMaterials(geometryId, vertexIndices); var hasNormals = documentNode.GetGeometryHasNormals(geometryId); var hasTexCoords = documentNode.GetGeometryHasTexCoords(geometryId); Assert.True(expectedHasTexCoord == hasTexCoords, $"HasTexCoord expected {expectedHasTexCoord}"); var hasTangents = documentNode.GetGeometryHasTangents(geometryId); Assert.True(expectedHasTangent == hasTangents, $"HasTangent expected {expectedHasTangent}"); var hasBinormals = documentNode.GetGeometryHasBinormals(geometryId); Assert.True(expectedHasBinormal == hasBinormals, $"HasBinormal expected {expectedHasBinormal}"); var hasMaterials = documentNode.GetGeometryHasMaterials(geometryId); for (var i = 0; i < positions.Length; i++) { var vertex = new FbxVertex { Position = positions[i], Normal = hasNormals ? normals[i] : new Vector3(), Tangent = hasTangents ? tangents[i] : new Vector3(), Binormal = hasBinormals ? binormals[i] : new Vector3(), TexCoord = hasTexCoords ? texCoords[i] : new Vector2() }; var materialId = hasMaterials ? materials[i] : 0; fbxIndexer.AddVertex(vertex, materialId); } } foreach (var materialId in materialIds) { var materialName = documentNode.GetMaterialName(materialId); var diffuseColor = documentNode.GetMaterialDiffuseColor(materialId); fbxIndexer.Index(materialId, out var indexedVertices, out var indexedIndices); } }
public bool Export(FbxDocument pDocument, FbxIO pFbxObject) { bool ret = FbxWrapperNativePINVOKE.FbxExporter_Export__SWIG_2(swigCPtr, FbxDocument.getCPtr(pDocument), FbxIO.getCPtr(pFbxObject)); return(ret); }
public virtual bool ReadExtendedHeaderInformation(FbxIO arg0) { bool ret = fbx_wrapperPINVOKE.FbxIOFileHeaderInfo_ReadExtendedHeaderInformation(swigCPtr, FbxIO.getCPtr(arg0)); return(ret); }
public static void ExportBinaryFbx(this Mesh mesh, string path) => FbxIO.WriteBinary(mesh.ToFBXDocument(), path);
public bool GetExportOptions(FbxIO pFbxObject) { bool ret = FbxWrapperNativePINVOKE.FbxExporter_GetExportOptions__SWIG_1(swigCPtr, FbxIO.getCPtr(pFbxObject)); return(ret); }
public override bool Store(FbxIO pFileObject) { bool ret = fbx_wrapperPINVOKE.FbxAnimCurve_Store__SWIG_1(swigCPtr, FbxIO.getCPtr(pFileObject)); return(ret); }
public override bool Retrieve(FbxIO pFileObject) { bool ret = fbx_wrapperPINVOKE.FbxAnimCurve_Retrieve(swigCPtr, FbxIO.getCPtr(pFileObject)); return(ret); }
public virtual bool Retrieve(FbxIO pFileObject) { bool ret = FbxWrapperNativePINVOKE.FbxAnimCurveBase_Retrieve(swigCPtr, FbxIO.getCPtr(pFileObject)); return(ret); }
public override bool Store(FbxIO pFileObject, bool pLegacyVersion) { bool ret = fbx_wrapperPINVOKE.FbxAnimCurve_Store__SWIG_0(swigCPtr, FbxIO.getCPtr(pFileObject), pLegacyVersion); return(ret); }
public virtual bool Store(FbxIO pFileObject) { bool ret = FbxWrapperNativePINVOKE.FbxAnimCurveBase_Store__SWIG_1(swigCPtr, FbxIO.getCPtr(pFileObject)); return(ret); }
public virtual bool Store(FbxIO pFileObject, bool pLegacyVersion) { bool ret = FbxWrapperNativePINVOKE.FbxAnimCurveBase_Store__SWIG_0(swigCPtr, FbxIO.getCPtr(pFileObject), pLegacyVersion); return(ret); }
public bool GetImportOptions(FbxIO pFbxObject) { bool ret = fbx_wrapperPINVOKE.FbxImporter_GetImportOptions__SWIG_2(swigCPtr, FbxIO.getCPtr(pFbxObject)); return(ret); }
public static void LoadFbx(string path, ref Vector3[] positions, ref Vector3[] normals, ref Vector2[] texCoords, ref int[] vertexIndices) { var isBinary = FbxIO.IsBinaryFbx(path); var documentNode = FbxIO.Read(path); // Scale factor usually 1 or 2.54 var scaleFactor = documentNode.GetScaleFactor(); var geometryIds = documentNode.GetGeometryIds(); var fbxIndexer = new FbxIndexer(); foreach (var geometryId in geometryIds) { vertexIndices = documentNode.GetVertexIndices(geometryId); long[] normalLayerIndices = documentNode.GetLayerIndices(geometryId, FbxLayerElementType.Normal); long[] tangentLayerIndices = documentNode.GetLayerIndices(geometryId, FbxLayerElementType.Tangent); long[] binormalLayerIndices = documentNode.GetLayerIndices(geometryId, FbxLayerElementType.Binormal); long[] texCoordLayerIndices = documentNode.GetLayerIndices(geometryId, FbxLayerElementType.TexCoord); long[] materialLayerIndices = documentNode.GetLayerIndices(geometryId, FbxLayerElementType.Material); positions = documentNode.GetPositions(geometryId, vertexIndices); normals = documentNode.GetNormals(geometryId, vertexIndices, normalLayerIndices[0]); texCoords = documentNode.GetTexCoords(geometryId, vertexIndices, texCoordLayerIndices[0]); int[] materials = documentNode.GetMaterials(geometryId, vertexIndices, materialLayerIndices[0]); bool hasNormals = documentNode.GetGeometryHasNormals(geometryId); bool hasTexCoords = documentNode.GetGeometryHasTexCoords(geometryId); bool hasTangents = documentNode.GetGeometryHasTangents(geometryId); bool hasBinormals = documentNode.GetGeometryHasBinormals(geometryId); bool hasMaterials = documentNode.GetGeometryHasMaterials(geometryId); Vector3[] tangents = Array.Empty <Vector3>(); Vector3[] binormals = Array.Empty <Vector3>(); if (hasTangents) { tangents = documentNode.GetTangents(geometryId, vertexIndices, tangentLayerIndices[0]); } if (hasBinormals) { binormals = documentNode.GetBinormals(geometryId, vertexIndices, binormalLayerIndices[0]); } for (var i = 0; i < positions.Length; i++) { var vertex = new FbxVertex { Position = positions[i], Normal = hasNormals ? normals[i] : new Vector3(), Tangent = hasTangents ? tangents[i] : new Vector3(), Binormal = hasBinormals ? binormals[i] : new Vector3(), TexCoord = hasTexCoords ? texCoords[i] : new Vector2() }; var materialId = hasMaterials ? materials[i] : 0; fbxIndexer.AddVertex(vertex, materialId, 0); } } }
private static IKn5 LodFbxToKn5(IKn5 preparedKn5, string fbxFilename, CarLodGeneratorStageParams stage) { var fbx = FbxIO.Read(fbxFilename); var geometries = fbx.GetGeometryIds() .Select(id => new { id, name = fbx.GetNode("Model", fbx.GetConnection(id)).GetName("Model") }) .GroupBy(v => v.name).ToDictionary(x => x.Key, x => x.Select(v => v.id).ToList()); MergeNode(preparedKn5.RootNode); foreach (var geometry in geometries.Where(g => g.Value.Count > 0)) { var parent = preparedKn5.FirstByName(geometry.Key); if (parent == null) { AcToolsLogging.Write($"Error: parent {geometry.Key} is missing"); continue; } var mesh = Kn5MeshUtils.Create($"{geometry.Key}__mesh_", parent.Children[0].MaterialId); if (parent.Children.Count != 1) { throw new Exception("Unexpected arrangement"); } MergeMeshWith(parent, mesh, geometry.Value.Select(x => Tuple.Create(fbx.GetGeometry(x), 1d))); parent.Children.Add(mesh); } RemoveEmpty(preparedKn5.RootNode); return(preparedKn5); void MergeMeshWith(Kn5Node parent, Kn5Node mesh, IEnumerable <Tuple <FbxNode, double> > geometriesList) { var builder = new Kn5MeshBuilder(); var subCounter = 1; foreach (var geometry in geometriesList) { var fbxIndices = geometry?.Item1?.GetRelative("PolygonVertexIndex")?.Value?.GetAsIntArray(); if (fbxIndices == null) { continue; } var fbxVertices = geometry.Item1.GetRelative("Vertices").Value.GetAsFloatArray(); var fbxNormals = geometry.Item1.GetRelative("LayerElementNormal").GetRelative("Normals").Value.GetAsFloatArray(); var fbxUvs = geometry.Item1.GetRelative("LayerElementUV").GetRelative("UV").Value.GetAsFloatArray(); var offset = MoveAsideDistance(geometry.Item2, stage); var scale = (float)(1d / geometry.Item2); for (var i = 0; i < fbxIndices.Length; ++i) { if (i % 3 == 0 && builder.IsCloseToLimit) { builder.SetTo(mesh); mesh.RecalculateTangents(); builder.Clear(); var oldIndex = parent.Children.IndexOf(mesh); mesh = Kn5MeshUtils.Create(mesh.Name + $"___$sub:{subCounter}", mesh.MaterialId); ++subCounter; if (oldIndex != -1 && oldIndex < parent.Children.Count - 1) { parent.Children.Insert(oldIndex + 1, mesh); } else { parent.Children.Add(mesh); } } var index = fbxIndices[i] < 0 ? -fbxIndices[i] - 1 : fbxIndices[i]; builder.AddVertex(new Kn5Node.Vertex { Position = new Vec3((fbxVertices[index * 3] - offset.X) * scale, (fbxVertices[index * 3 + 1] - offset.Y) * scale, (fbxVertices[index * 3 + 2] - offset.Z) * scale), Normal = new Vec3(fbxNormals[i * 3], fbxNormals[i * 3 + 1], fbxNormals[i * 3 + 2]), Tex = new Vec2(fbxUvs[i * 2], 1f - fbxUvs[i * 2 + 1]) }); } } builder.SetTo(mesh); mesh.RecalculateTangents(); } void MergeMesh(Kn5Node parent, Kn5Node node, IEnumerable <Kn5Node> merges) { if (Regex.IsMatch(node.Name, @"___\$extra:\d+$")) { node.Vertices = new Kn5Node.Vertex[0]; return; } MergeMeshWith(parent, node, Enumerable.Range(-1, 100).Select(i => GetGeometry(node, i)).TakeWhile(i => i != null) .Concat(merges.Select(n => GetGeometry(n)))); } Tuple <FbxNode, double> GetGeometry(Kn5Node node, int extraBit = -1) { var name = extraBit < 0 ? node.Name : $"{node.Name}___$extra:{extraBit}"; if (geometries.TryGetValue(name, out var list)) { if (list.Count == 0) { return(null); } var geometryId = list[0]; list.RemoveAt(0); return(Tuple.Create(fbx.GetGeometry(geometryId), node.Tag is double priority ? priority : 1d)); } return(null); } void MergeNode(Kn5Node node) { foreach (var child in node.Children.ToList()) { if (child.NodeClass == Kn5NodeClass.Base) { MergeNode(child); } else if (child.NodeClass == Kn5NodeClass.Mesh && child.Vertices.Length > 0) { var mergeKey = MergeKey(child); var merge = node.Children.ApartFrom(child).Where(c => c.NodeClass == Kn5NodeClass.Mesh && MergeKey(c) == mergeKey).ToList(); MergeMesh(node, child, merge); merge.ForEach(m => m.Vertices = new Kn5Node.Vertex[0]); } } } int MergeKey(Kn5Node node) { return((int)(node.MaterialId * 397) | (node.IsTransparent ? 1 << 31 : 0) | (node.CastShadows ? 1 << 30 : 0)); } bool RemoveEmpty(Kn5Node node) { if (node.NodeClass == Kn5NodeClass.Mesh) { if (Regex.IsMatch(node.Name, @"___\$extra:\d+$")) { return(false); } return(node.Vertices.Length > 0); } if (node.NodeClass == Kn5NodeClass.SkinnedMesh) { return(false); } var found = node.Name.IndexOf("___$unique:", StringComparison.Ordinal); if (found != -1) { node.Name = node.Name.Substring(0, found); } for (var i = 0; i < node.Children.Count; ++i) { if (!RemoveEmpty(node.Children[i])) { node.Children.RemoveAt(i); --i; } } return(node.Children.Count > 0); } }