private static MyLODDescriptor[] ReadLODs(BinaryReader reader, int version) { var length = reader.ReadInt32(); var myLodDescriptorArray = new MyLODDescriptor[length]; var num = 0; while (length-- > 0) { var myLodDescriptor = new MyLODDescriptor(); myLodDescriptorArray[num++] = myLodDescriptor; myLodDescriptor.Read(reader); } return(myLodDescriptorArray); }
private static MyLODDescriptor[] ReadMyLodDescriptorArray(BinaryReader reader) { var nCount = reader.ReadInt32(); var myLodDescriptorArray = new MyLODDescriptor[nCount]; for (var i = 0; i < nCount; i++) { var distance = reader.ReadSingle(); var model = reader.ReadString(); var renderQuality = reader.ReadString(); myLodDescriptorArray[i] = new MyLODDescriptor { Distance = distance, Model = model, RenderQuality = renderQuality }; } return(myLodDescriptorArray); }
public void Build( string filename, string intermediateDir, string outputDir, MyModelConfiguration configuration, byte[] havokCollisionShapes, bool checkOpenBoundaries, float[] lodDistances, bool overrideLods, Func <string, MyMaterialConfiguration> getMaterialByRef, IMyBuildLogger logger) { string withoutExtension = Path.GetFileNameWithoutExtension(filename); string directoryName = Path.GetDirectoryName(filename); string str1 = "content"; int num1 = directoryName.ToLower().LastIndexOf(str1) + str1.Length + 1; string path1 = directoryName.Substring(num1, directoryName.Length - num1); directoryName.Substring(0, num1); Path.Combine(path1, withoutExtension + ".FBX"); AssimpContext assimpContext = new AssimpContext(); assimpContext.SetConfig((PropertyConfig) new NormalSmoothingAngleConfig(66f)); assimpContext.SetConfig((PropertyConfig) new FBXPreservePivotsConfig(false)); Scene input = assimpContext.ImportFile(filename, PostProcessSteps.CalculateTangentSpace | PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.Triangulate | PostProcessSteps.GenerateSmoothNormals | PostProcessSteps.SplitLargeMeshes | PostProcessSteps.LimitBoneWeights | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.FindInvalidData | PostProcessSteps.GenerateUVCoords | PostProcessSteps.FlipWindingOrder); string outputDir1 = outputDir; if (input.MeshCount == 0 && input.AnimationCount == 0) { throw new Exception("Number of meshes is 0 and no animation present!"); } if (input.MaterialCount > 0) { List <MyMaterialConfiguration> materialConfigurationList = new List <MyMaterialConfiguration>(); for (int index = 0; index < input.MaterialCount; ++index) { MyMaterialConfiguration materialConfiguration = getMaterialByRef(input.Materials[index].Name); if (materialConfiguration != null) { materialConfigurationList.Add(materialConfiguration); } } if (materialConfigurationList.Count > 0) { configuration.Materials = configuration.Materials != null ? ((IEnumerable <MyMaterialConfiguration>)configuration.Materials).Union <MyMaterialConfiguration>((IEnumerable <MyMaterialConfiguration>)materialConfigurationList.ToArray()).ToArray <MyMaterialConfiguration>() : materialConfigurationList.ToArray(); } } MyModelProcessor processor = this.CreateProcessor(configuration); if (configuration.Materials != null) { foreach (MyMaterialConfiguration material in configuration.Materials) { try { Dictionary <string, object> dictionary = new Dictionary <string, object>(); if (processor.MaterialProperties.Keys.Contains <string>(material.Name)) { logger.LogMessage(MessageType.Error, "Material: " + material.Name + " is already defined in the processor. Not adding it again..", filename); } else { processor.MaterialProperties.Add(material.Name, dictionary); foreach (MyModelParameter parameter in material.Parameters) { dictionary.Add(parameter.Name, (object)parameter.Value); } } } catch (ArgumentException ex) { logger.LogMessage(MessageType.Error, "Problem when procesing materials: " + ex.Message, filename); } } } int num2 = 999; List <MyLODDescriptor> myLodDescriptorList = new List <MyLODDescriptor>(); for (int index = 0; index < num2; ++index) { string path = Path.Combine(directoryName, withoutExtension + "_LOD" + (object)(index + 1)) + ".fbx"; string str2 = Path.Combine(path1, withoutExtension + "_LOD" + (object)(index + 1)); if (File.Exists(path)) { if (overrideLods && lodDistances != null && (index < lodDistances.Length && (double)lodDistances[index] > 0.0)) { MyLODDescriptor myLodDescriptor = new MyLODDescriptor() { Distance = lodDistances[index], Model = str2 }; myLodDescriptorList.Add(myLodDescriptor); } else if (configuration.LODs != null && index < configuration.LODs.Length) { MyLODConfiguration loD = configuration.LODs[index]; MyLODDescriptor myLodDescriptor = new MyLODDescriptor() { Distance = loD.Distance, Model = configuration.LODs[index].Model, //str2, <-- FIx for LODS. Take defined path in the config. RenderQuality = loD.RenderQuality }; if (str2.ToLower() != loD.Model.ToLower()) { logger.LogMessage(MessageType.Error, "LOD" + (object)(index + 1) + " name differs " + str2 + " and " + loD.Model, filename); } myLodDescriptorList.Add(myLodDescriptor); } else { logger.LogMessage(MessageType.Error, "LOD" + (object)(index + 1) + " model exists but configuration is missing", filename); } } else if (configuration.LODs != null && index < configuration.LODs.Length) { logger.LogMessage(MessageType.Error, "LOD model " + configuration.LODs[index].Model + " is missing", filename); } else { break; } } processor.LODs = myLodDescriptorList.ToArray(); processor.BoneGridMapping = configuration.BoneGridSize; processor.BoneMapping = configuration.BoneMapping != null ? ((IEnumerable <MyModelVector>)configuration.BoneMapping).Select <MyModelVector, Vector3>((Func <MyModelVector, Vector3>)(s => new Vector3((float)s.X, (float)s.Y, (float)s.Z))).ToArray <Vector3>() : (Vector3[])null; processor.HavokCollisionShapes = havokCollisionShapes; processor.Process(input, filename, outputDir1, checkOpenBoundaries, logger); if (configuration.BoneGridSize.HasValue) { configuration.BoneMapping = ((IEnumerable <Vector3>)processor.BoneMapping).Select <Vector3, MyModelVector>((Func <Vector3, MyModelVector>)(s => (MyModelVector)s)).ToArray <MyModelVector>(); } List <MyMaterialConfiguration> materialConfigurationList1 = new List <MyMaterialConfiguration>(); foreach (KeyValuePair <string, Dictionary <string, object> > materialProperty in processor.MaterialProperties) { materialConfigurationList1.Add(new MyMaterialConfiguration() { Name = materialProperty.Key, Parameters = MyModelBuilder.GetParameters(materialProperty) }); } configuration.Materials = materialConfigurationList1.Count <= 0 ? (MyMaterialConfiguration[])null : materialConfigurationList1.ToArray(); if (processor.LODs == null) { return; } List <MyLODConfiguration> lodConfigurationList = new List <MyLODConfiguration>(); foreach (MyLODDescriptor loD in processor.LODs) { lodConfigurationList.Add(new MyLODConfiguration() { Distance = loD.Distance, Model = loD.Model, RenderQuality = loD.RenderQuality }); } configuration.LODs = lodConfigurationList.ToArray(); }
MyRenderMeshInfo LoadMesh(string assetName, out MyLODDescriptor[] LodDescriptors) { //Debug.Assert(assetName.EndsWith(".mwm")); #region Temporary for mwm endings if (!assetName.EndsWith(".mwm")) { assetName += ".mwm"; } #endregion var meshVertexInput = MyVertexInputLayout.Empty; LodDescriptors = null; MyRenderMeshInfo result = new MyRenderMeshInfo(); var importer = new MyModelImporter(); var fsPath = Path.IsPathRooted(assetName) ? assetName : Path.Combine(MyFileSystem.ContentPath, assetName); if (!MyFileSystem.FileExists(fsPath)) { System.Diagnostics.Debug.Fail("Model " + assetName + " does not exists!"); return MyAssetsLoader.GetDebugMesh().LODs[0].m_meshInfo; } string contentPath = null; if (Path.IsPathRooted(assetName) && assetName.ToLower().Contains("models")) contentPath = assetName.Substring(0, assetName.ToLower().IndexOf("models")); try { importer.ImportData(fsPath, new string[] { MyImporterConstants.TAG_VERTICES, MyImporterConstants.TAG_BLENDINDICES, MyImporterConstants.TAG_BLENDWEIGHTS, MyImporterConstants.TAG_NORMALS, MyImporterConstants.TAG_TEXCOORDS0, MyImporterConstants.TAG_TANGENTS, MyImporterConstants.TAG_BINORMALS, MyImporterConstants.TAG_BONES, MyImporterConstants.TAG_MESH_PARTS, MyImporterConstants.TAG_BOUNDING_BOX, MyImporterConstants.TAG_BOUNDING_SPHERE, MyImporterConstants.TAG_LODS, }); Dictionary<string, object> tagData = importer.GetTagData(); // extract data var positions = (HalfVector4[])tagData[MyImporterConstants.TAG_VERTICES]; System.Diagnostics.Debug.Assert(positions.Length > 0); var verticesNum = positions.Length; var boneIndices = (Vector4I[])tagData[MyImporterConstants.TAG_BLENDINDICES]; var boneWeights = (Vector4[])tagData[MyImporterConstants.TAG_BLENDWEIGHTS]; var normals = (Byte4[])tagData[MyImporterConstants.TAG_NORMALS]; var texcoords = (HalfVector2[])tagData[MyImporterConstants.TAG_TEXCOORDS0]; var tangents = (Byte4[])tagData[MyImporterConstants.TAG_TANGENTS]; var bintangents = (Byte4[])tagData[MyImporterConstants.TAG_BINORMALS]; var tangentBitanSgn = new Byte4[verticesNum]; for (int i = 0; i < verticesNum; i++) { var N = VF_Packer.UnpackNormal(normals[i].PackedValue); var T = VF_Packer.UnpackNormal(tangents[i].PackedValue); var B = VF_Packer.UnpackNormal(bintangents[i].PackedValue); var tanW = new Vector4(T.X, T.Y, T.Z, 0); tanW.W = T.Cross(N).Dot(B) < 0 ? -1 : 1; tangentBitanSgn[i] = VF_Packer.PackTangentSignB4(ref tanW); } bool hasBonesInfo = boneIndices.Length > 0 && boneWeights.Length > 0; var bones = (MyModelBone[])tagData[MyImporterConstants.TAG_BONES]; // var vertexBuffers = new List<IVertexBuffer>(); IIndexBuffer indexBuffer = null; var submeshes = new Dictionary<MyMeshDrawTechnique, List<MyDrawSubmesh>>(); var submeshes2 = new Dictionary<MyMeshDrawTechnique, List<MySubmeshInfo>>(); var submeshesMeta = new List<MySubmeshInfo>(); int indicesNum = 0; bool missingMaterial = false; if (tagData.ContainsKey(MyImporterConstants.TAG_MESH_PARTS)) { var indices = new List<uint>(positions.Length); uint maxIndex = 0; var meshParts = tagData[MyImporterConstants.TAG_MESH_PARTS] as List<MyMeshPartInfo>; foreach (MyMeshPartInfo meshPart in meshParts) { # region Bones indirection int[] bonesRemapping = null; if (boneIndices.Length > 0 && bones.Length > MyRender11Constants.SHADER_MAX_BONES) { Dictionary<int, int> vertexChanged = new Dictionary<int, int>(); Dictionary<int, int> bonesUsed = new Dictionary<int, int>(); int trianglesNum = meshPart.m_indices.Count / 3; for (int i = 0; i < trianglesNum; i++) { for (int j = 0; j < 3; j++) { int index = meshPart.m_indices[i * 3 + j]; if (boneWeights[index].X > 0) bonesUsed[boneIndices[index].X] = 1; if (boneWeights[index].Y > 0) bonesUsed[boneIndices[index].Y] = 1; if (boneWeights[index].Z > 0) bonesUsed[boneIndices[index].Z] = 1; if (boneWeights[index].W > 0) bonesUsed[boneIndices[index].W] = 1; } } if (bonesUsed.Count > MyRender11Constants.SHADER_MAX_BONES) { Debug.Assert(bonesUsed.Count <= MyRender11Constants.SHADER_MAX_BONES, "Model \"" + assetName + "\"'s part uses more than 60 bones, please split model on more parts"); } var partBones = new List<int>(bonesUsed.Keys); partBones.Sort(); if (partBones.Count > 0 && partBones[partBones.Count - 1] >= MyRender11Constants.SHADER_MAX_BONES) { for (int i = 0; i < partBones.Count; i++) { bonesUsed[partBones[i]] = i; } Dictionary<int, int> vertexTouched = new Dictionary<int, int>(); for (int i = 0; i < trianglesNum; i++) { for (int j = 0; j < 3; j++) { int index = meshPart.m_indices[i * 3 + j]; if (!vertexTouched.ContainsKey(index)) { if (boneWeights[index].X > 0) boneIndices[index].X = bonesUsed[boneIndices[index].X]; if (boneWeights[index].Y > 0) boneIndices[index].Y = bonesUsed[boneIndices[index].Y]; if (boneWeights[index].Z > 0) boneIndices[index].Z = bonesUsed[boneIndices[index].Z]; if (boneWeights[index].W > 0) boneIndices[index].W = bonesUsed[boneIndices[index].W]; vertexTouched[index] = 1; int changes = 0; vertexChanged.TryGetValue(index, out changes); vertexChanged[index] = changes + 1; } } } bonesRemapping = partBones.ToArray(); } if (vertexChanged.Values.Count > 0) Debug.Assert(vertexChanged.Values.Max() < 2, "Vertex shared between model parts, will likely result in wrong skinning"); } #endregion int startIndex = indices.Count; int indexCount = meshPart.m_indices.Count; uint minIndex = (uint)meshPart.m_indices[0]; foreach (var i in meshPart.m_indices) { indices.Add((uint)i); minIndex = Math.Min(minIndex, (uint)i); } uint baseVertex = minIndex; for (int i = startIndex; i < startIndex + indexCount; i++) { indices[i] -= minIndex; maxIndex = Math.Max(maxIndex, indices[i]); } #region Material var materialDesc = meshPart.m_MaterialDesc; var matId = MyMeshMaterials1.GetMaterialId(materialDesc, contentPath); var partKey = MyMeshMaterials1.Table[matId.Index].Technique; var materialName = MyMeshMaterials1.Table[matId.Index].Name; var list = submeshes.SetDefault(partKey, new List<MyDrawSubmesh>()); list.Add(new MyDrawSubmesh(indexCount, startIndex, (int)baseVertex, MyMeshMaterials1.GetProxyId(matId), bonesRemapping)); submeshesMeta.Add(new MySubmeshInfo { IndexCount = indexCount, StartIndex = startIndex, BaseVertex = (int)baseVertex, BonesMapping = bonesRemapping, Material = materialName.ToString(), Technique = partKey }); var list2 = submeshes2.SetDefault(partKey, new List<MySubmeshInfo>()); list2.Add(submeshesMeta[submeshesMeta.Count - 1]); #endregion } indicesNum = indices.Count; #region Fill gpu buffes unsafe { if (maxIndex <= ushort.MaxValue) { // create 16 bit indices var indices16 = new ushort[indices.Count]; for (int i = 0; i < indices.Count; i++) { indices16[i] = (ushort)indices[i]; } result.Indices = indices16; fixed (ushort* I = indices16) { indexBuffer = MyManagers.Buffers.CreateIndexBuffer(assetName + " index buffer", indices16.Length, new IntPtr(I), MyIndexBufferFormat.UShort, ResourceUsage.Immutable); } } else { var indicesArray = indices.ToArray(); fixed (uint* I = indicesArray) { indexBuffer = MyManagers.Buffers.CreateIndexBuffer(assetName + " index buffer", indices.Count, new IntPtr(I), MyIndexBufferFormat.UInt, ResourceUsage.Immutable); } } } unsafe { if (!hasBonesInfo) { var vertices = new MyVertexFormatPositionH4[verticesNum]; for (int i = 0; i < verticesNum; i++) { vertices[i] = new MyVertexFormatPositionH4(positions[i]); } meshVertexInput = meshVertexInput.Append(MyVertexInputComponentType.POSITION_PACKED); result.VertexPositions = vertices; fixed (MyVertexFormatPositionH4* V = vertices) { vertexBuffers.Add( MyManagers.Buffers.CreateVertexBuffer( assetName + " vertex buffer " + vertexBuffers.Count, verticesNum, sizeof(MyVertexFormatPositionH4), new IntPtr(V), ResourceUsage.Immutable)); } } else { var vertices = new MyVertexFormatPositionSkinning[verticesNum]; for (int i = 0; i < verticesNum; i++) { vertices[i] = new MyVertexFormatPositionSkinning( positions[i], new Byte4(boneIndices[i].X, boneIndices[i].Y, boneIndices[i].Z, boneIndices[i].W), boneWeights[i]); } meshVertexInput = meshVertexInput.Append(MyVertexInputComponentType.POSITION_PACKED) .Append(MyVertexInputComponentType.BLEND_WEIGHTS) .Append(MyVertexInputComponentType.BLEND_INDICES); fixed (MyVertexFormatPositionSkinning* V = vertices) { vertexBuffers.Add(MyManagers.Buffers.CreateVertexBuffer( assetName + " vertex buffer " + vertexBuffers.Count, verticesNum, sizeof(MyVertexFormatPositionSkinning), new IntPtr(V), ResourceUsage.Immutable)); } } // add second stream { var vertices = new MyVertexFormatTexcoordNormalTangent[verticesNum]; for (int i = 0; i < verticesNum; i++) { vertices[i] = new MyVertexFormatTexcoordNormalTangent(texcoords[i], normals[i], tangentBitanSgn[i]); } fixed (MyVertexFormatTexcoordNormalTangent* V = vertices) { vertexBuffers.Add(MyManagers.Buffers.CreateVertexBuffer( assetName + " vertex buffer " + vertexBuffers.Count, verticesNum, sizeof(MyVertexFormatTexcoordNormalTangent), new IntPtr(V), ResourceUsage.Immutable)); } result.VertexExtendedData = vertices; meshVertexInput = meshVertexInput .Append(MyVertexInputComponentType.NORMAL, 1) .Append(MyVertexInputComponentType.TANGENT_SIGN_OF_BITANGENT, 1) .Append(MyVertexInputComponentType.TEXCOORD0_H, 1); } } #endregion } #region Extract lods if (tagData.ContainsKey(MyImporterConstants.TAG_LODS)) { var tagLODs = tagData[MyImporterConstants.TAG_LODS]; if (((MyLODDescriptor[])tagLODs).Length > 0) { } LodDescriptors = (MyLODDescriptor[])((MyLODDescriptor[])tagLODs).Clone(); } #endregion if (missingMaterial) { Debug.WriteLine(String.Format("Mesh {0} has missing material", assetName)); } //indexBuffer.SetDebugName(assetName + " index buffer"); int c = 0; //vertexBuffers.ForEach(x => x.SetDebugName(assetName + " vertex buffer " + c++)); // result.BoundingBox = (BoundingBox)tagData[MyImporterConstants.TAG_BOUNDING_BOX]; result.BoundingSphere = (BoundingSphere)tagData[MyImporterConstants.TAG_BOUNDING_SPHERE]; result.VerticesNum = verticesNum; result.IndicesNum = indicesNum; result.VertexLayout = meshVertexInput; result.IB = indexBuffer; result.VB = vertexBuffers.ToArray(); result.IsAnimated = hasBonesInfo; result.Parts = submeshes.ToDictionary(x => x.Key, x => x.Value.ToArray()); result.PartsMetadata = submeshes2.ToDictionary(x => x.Key, x => x.Value.ToArray()); result.m_submeshes = submeshesMeta; IsAnimated |= result.IsAnimated; importer.Clear(); return result; }
public bool ExportData(string tagName, MyLODDescriptor[] lodDescriptions) { WriteTag(tagName); m_writer.Write(lodDescriptions.Length); foreach (var desc in lodDescriptions) { desc.Write(m_writer); } return true; }
private static bool ExportData(this BinaryWriter writer, string tagName, MyLODDescriptor[] lodArray) { WriteTag(writer, tagName); writer.Write(lodArray.Length); foreach (var lodVal in lodArray) { lodVal.Write(writer); } return true; }
private static MyLODDescriptor[] ReadMyLodDescriptorArray(BinaryReader reader) { var nCount = reader.ReadInt32(); var myLodDescriptorArray = new MyLODDescriptor[nCount]; for (var i = 0; i < nCount; i++) { var distance = reader.ReadSingle(); var model = reader.ReadString(); var renderQuality = reader.ReadString(); myLodDescriptorArray[i] = new MyLODDescriptor { Distance = distance, Model = model, RenderQuality = renderQuality }; } return myLodDescriptorArray; }
public void Build( string filename, string intermediateDir, string outputDir, MyModelConfiguration configuration, byte[] havokCollisionShapes, bool checkOpenBoundaries, float[] lodDistances, bool overrideLods, Func <string, MyMaterialConfiguration> getMaterialByRef, IMyBuildLogger logger) { logger.LogMessage(MessageType.Info, "**FileName: " + filename); string withoutExtension = Path.GetFileNameWithoutExtension(filename); logger.LogMessage(MessageType.Info, "**Filename (without extension): " + withoutExtension); string directoryName = Path.GetDirectoryName(filename); logger.LogMessage(MessageType.Info, "**Directory Name: " + directoryName); //string contentDirectoryString = "content"; // int numberOfPathCharactersToCull = directoryName.ToLower().LastIndexOf(contentDirectoryString) + contentDirectoryString.Length + 1; var numberOfPathCharactersToCull = filename.LastIndexOf("models\\", StringComparison.OrdinalIgnoreCase); if (numberOfPathCharactersToCull == -1) { throw new Exception("Couldn't find 'models\\' in path provided: " + filename); } logger.LogMessage(MessageType.Info, "**Number of characters to cull: " + numberOfPathCharactersToCull); string culledPath = directoryName.Substring(numberOfPathCharactersToCull, directoryName.Length - numberOfPathCharactersToCull); // Used to cull 'content' from path name to create relative pathing. logger.LogMessage(MessageType.Info, "**Culled Path: " + culledPath); directoryName.Substring(0, numberOfPathCharactersToCull); Path.Combine(directoryName, withoutExtension + ".FBX"); AssimpContext assimpContext = new AssimpContext(); assimpContext.SetConfig((PropertyConfig) new NormalSmoothingAngleConfig(66f)); assimpContext.SetConfig((PropertyConfig) new FBXPreservePivotsConfig(false)); Scene scene = assimpContext.ImportFile(filename, PostProcessSteps.CalculateTangentSpace | PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.Triangulate | PostProcessSteps.GenerateSmoothNormals | PostProcessSteps.SplitLargeMeshes | PostProcessSteps.LimitBoneWeights | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.FindInvalidData | PostProcessSteps.GenerateUVCoords | PostProcessSteps.FlipWindingOrder); string outputDir1 = outputDir; if (scene.MeshCount == 0 && scene.AnimationCount == 0) { throw new Exception("Number of meshes is 0 and no animation present!"); } else { logger.LogMessage(MessageType.Info, "Found " + scene.MeshCount + " meshe(s).", "Meshes"); logger.LogMessage(MessageType.Info, "Found " + scene.AnimationCount + " animation(s).", "Animations"); } #region check UV for 0-sized faces if (scene.MeshCount > 0) { void LogUVError(Assimp.Mesh mesh, string message) { //logger.LogMessage(MessageType.Error, $"Mesh '{mesh.Name}' {message}"); throw new Exception($"Mesh '{mesh.Name}' {message}"); } for (int meshIdx = 0; meshIdx < scene.MeshCount; meshIdx++) { Assimp.Mesh mesh = scene.Meshes[meshIdx]; if (mesh.TextureCoordinateChannels == null || mesh.TextureCoordinateChannels.Length == 0) { LogUVError(mesh, "has no UV map/channel!"); continue; } int channels = 1; // don't care about other channels; if you want to, replace with: mesh.TextureCoordinateChannels.Length; for (int chIdx = 0; chIdx < channels; chIdx++) { if (!mesh.HasTextureCoords(0)) { LogUVError(mesh, "has no UV map/channel!"); continue; } List <Assimp.Vector3D> vectors = mesh.TextureCoordinateChannels[chIdx]; if (vectors == null || vectors.Count == 0) { LogUVError(mesh, "has no UV vectors in first map/channel!"); continue; } //Console.WriteLine($" channel={chIdx}"); //for (int v = 0; v < vectors.Count; v++) //{ // Console.WriteLine($" {v} == {vectors[v]}"); //} Assimp.Vector3D?lastVec = null; int sameVecInARow = 1; // these can be triangles, quads and prob more... so not safe to assume they're in pairs of 3. for (int v = 0; v < vectors.Count; v++) { Assimp.Vector3D vec = vectors[v]; if (!lastVec.HasValue) { lastVec = vec; } else { if (lastVec.Value == vec) { sameVecInARow++; if (sameVecInARow >= 3) { // Changed this to a warning instead of a LogUVError logger.LogMessage(MessageType.Warning, mesh.ToString() + "has UV with 3 identical vectors in a row, this likely means you have a face with an UV is 0-size which will cause SE to make the entire model shaderless."); break; } } else { lastVec = vec; sameVecInARow = 1; } } } } } } #endregion if (scene.MaterialCount > 0) { List <MyMaterialConfiguration> materialConfigurationList = new List <MyMaterialConfiguration>(); for (int index = 0; index < scene.MaterialCount; ++index) { MyMaterialConfiguration materialConfiguration = getMaterialByRef(scene.Materials[index].Name); if (materialConfiguration != null) { materialConfigurationList.Add(materialConfiguration); } } if (materialConfigurationList.Count > 0) { configuration.Materials = configuration.Materials != null ? ((IEnumerable <MyMaterialConfiguration>)configuration.Materials).Union <MyMaterialConfiguration>((IEnumerable <MyMaterialConfiguration>)materialConfigurationList.ToArray()).ToArray <MyMaterialConfiguration>() : materialConfigurationList.ToArray(); } } MyModelProcessor processor = this.CreateProcessor(configuration); if (configuration.Materials != null) { foreach (MyMaterialConfiguration material in configuration.Materials) { try { Dictionary <string, object> dictionary = new Dictionary <string, object>(); if (processor.MaterialProperties.Keys.Contains <string>(material.Name)) { logger.LogMessage(MessageType.Warning, "Material: " + material.Name + " is already defined in the processor. Not adding it again..", filename); } else { processor.MaterialProperties.Add(material.Name, dictionary); foreach (MyModelParameter parameter in material.Parameters) { dictionary.Add(parameter.Name, (object)parameter.Value); } } } catch (ArgumentException ex) { logger.LogMessage(MessageType.Warning, "Problem when processing materials: " + ex.Message, filename); } } } int num2 = 999; List <MyLODDescriptor> myLodDescriptorList = new List <MyLODDescriptor>(); for (int index = 0; index < num2; ++index) { string path = Path.Combine(directoryName, withoutExtension + "_LOD" + (object)(index + 1)) + ".fbx"; string str2 = Path.Combine(culledPath, withoutExtension + "_LOD" + (object)(index + 1)); if (File.Exists(path)) { if (overrideLods && lodDistances != null && (index < lodDistances.Length && (double)lodDistances[index] > 0.0)) { MyLODDescriptor myLodDescriptor = new MyLODDescriptor() { Distance = lodDistances[index], Model = str2 }; myLodDescriptorList.Add(myLodDescriptor); } else if (configuration.LODs != null && index < configuration.LODs.Length) { MyLODConfiguration loD = configuration.LODs[index]; MyLODDescriptor myLodDescriptor = new MyLODDescriptor() { Distance = loD.Distance, Model = str2, RenderQuality = loD.RenderQuality }; if (str2.ToLower() != loD.Model.ToLower()) { logger.LogMessage(MessageType.Warning, "LOD" + (object)(index + 1) + " name differs " + str2 + " and " + loD.Model, filename); } myLodDescriptorList.Add(myLodDescriptor); } else { logger.LogMessage(MessageType.Warning, "LOD" + (object)(index + 1) + " model exists but configuration is missing", filename); } } else if (configuration.LODs != null && index < configuration.LODs.Length) { logger.LogMessage(MessageType.Warning, "LOD model " + configuration.LODs[index].Model + " is missing", filename); } else { break; } } processor.LODs = myLodDescriptorList.ToArray(); processor.BoneGridMapping = configuration.BoneGridSize; processor.BoneMapping = configuration.BoneMapping != null ? ((IEnumerable <MyModelVector>)configuration.BoneMapping).Select <MyModelVector, Vector3>((Func <MyModelVector, Vector3>)(s => new Vector3((float)s.X, (float)s.Y, (float)s.Z))).ToArray <Vector3>() : (Vector3[])null; processor.HavokCollisionShapes = havokCollisionShapes; processor.Process(scene, filename, outputDir1, checkOpenBoundaries, logger); if (configuration.BoneGridSize.HasValue) { configuration.BoneMapping = ((IEnumerable <Vector3>)processor.BoneMapping).Select <Vector3, MyModelVector>((Func <Vector3, MyModelVector>)(s => (MyModelVector)s)).ToArray <MyModelVector>(); } List <MyMaterialConfiguration> materialConfigurationList1 = new List <MyMaterialConfiguration>(); foreach (KeyValuePair <string, Dictionary <string, object> > materialProperty in processor.MaterialProperties) { materialConfigurationList1.Add(new MyMaterialConfiguration() { Name = materialProperty.Key, Parameters = MyModelBuilder.GetParameters(materialProperty) }); } configuration.Materials = materialConfigurationList1.Count <= 0 ? (MyMaterialConfiguration[])null : materialConfigurationList1.ToArray(); if (processor.LODs == null) { return; } List <MyLODConfiguration> lodConfigurationList = new List <MyLODConfiguration>(); foreach (MyLODDescriptor loD in processor.LODs) { lodConfigurationList.Add(new MyLODConfiguration() { Distance = loD.Distance, Model = loD.Model, RenderQuality = loD.RenderQuality }); } configuration.LODs = lodConfigurationList.ToArray(); }