} //OnImportAsset public void ReadWithoutAssetImportContext(string filePath) { Fmdl fmdl = new Fmdl(Path.GetFileNameWithoutExtension(filePath)); fmdl.Read(filePath); int boneCount = fmdl.fmdlBones != null ? fmdl.fmdlBones.Length : 0; int materialCount = fmdl.fmdlMaterialInstances.Length; int textureCount = fmdl.fmdlTextures != null ? fmdl.fmdlTextures.Length : 0; int meshCount = fmdl.fmdlMeshInfos.Length; int meshGroupCount = fmdl.fmdlMeshGroups.Length; GameObject mainObject = new GameObject(fmdl.name); FoxModel foxModel = mainObject.AddComponent<FoxModel>(); foxModel.meshGroups = new FoxMeshGroup[meshGroupCount]; foxModel.meshDefinitions = new FoxMeshDefinition[meshCount]; Transform[] bones = new Transform[boneCount]; Texture[] textures = new Texture[textureCount]; Material[] materials = new Material[materialCount]; Mesh[] meshes = new Mesh[meshCount]; Transform rootBone = new GameObject().transform; rootBone.name = "[Root]"; rootBone.parent = mainObject.transform; Read(fmdl, mainObject, foxModel, bones, textures, materials, meshes, rootBone); } //ReadWithoutAssetImportContext
public static void FMDLWrite(string path) { FileStream stream = new FileStream(path, FileMode.Create); GameObject selectedGameObject = Selection.activeGameObject; Fmdl fmdl = new Fmdl(selectedGameObject.name); fmdl.Write(selectedGameObject, stream); stream.Close(); }
public override void OnImportAsset(AssetImportContext ctx) { FileStream stream = new FileStream(ctx.assetPath, FileMode.Open); Fmdl fmdl = new Fmdl(Path.GetFileNameWithoutExtension(ctx.assetPath)); UnityModel model = new UnityModel(); fmdl.Read(stream); GameObject fmdlGameObject = model.GetDataFromFmdl(fmdl); ctx.AddObjectToAsset(ctx.assetPath, fmdlGameObject); ctx.SetMainObject(fmdlGameObject); stream.Close(); }
public static void ExportFMDLOption() { if (Selection.activeGameObject != null) { string windowPath = EditorUtility.SaveFilePanel("Export To FMDL", "", Selection.activeGameObject.name, "fmdl"); if (!string.IsNullOrWhiteSpace(windowPath)) { Fmdl fmdl = new Fmdl(Selection.activeGameObject.name); fmdl.Write(Selection.activeGameObject, windowPath); Debug.Log("Fmdl Exported to: " + windowPath); } //if else Debug.Log("No path selected."); } else Debug.Log("No objects selected."); } //ExportFMDLOption
} //LoadTextureDXT private void ReadWithAssetImportContext(AssetImportContext ctx, string filePath) { Fmdl fmdl = new Fmdl(Path.GetFileNameWithoutExtension(filePath)); fmdl.Read(filePath); int boneCount = fmdl.fmdlBones != null ? fmdl.fmdlBones.Length : 0; int materialCount = fmdl.fmdlMaterialInstances.Length; int textureCount = fmdl.fmdlTextures != null ? fmdl.fmdlTextures.Length : 0; int meshCount = fmdl.fmdlMeshInfos.Length; int meshGroupCount = fmdl.fmdlMeshGroups.Length; GameObject mainObject = new GameObject(fmdl.name); FoxModel foxModel = mainObject.AddComponent<FoxModel>(); foxModel.meshGroups = new FoxMeshGroup[meshGroupCount]; foxModel.meshDefinitions = new FoxMeshDefinition[meshCount]; Transform[] bones = new Transform[boneCount]; Texture[] textures = new Texture[textureCount]; Material[] materials = new Material[materialCount]; Mesh[] meshes = new Mesh[meshCount]; Transform rootBone = new GameObject().transform; rootBone.name = "[Root]"; rootBone.parent = mainObject.transform; Read(fmdl, mainObject, foxModel, bones, textures, materials, meshes, rootBone); ctx.AddObjectToAsset("mainObject", mainObject); ctx.SetMainObject(mainObject); for (int i = 0; i < textureCount; i++) ctx.AddObjectToAsset($"Texture {i}", textures[i]); for (int i = 0; i < materialCount; i++) ctx.AddObjectToAsset($"Material {i}", materials[i]); for (int i = 0; i < meshCount; i++) ctx.AddObjectToAsset($"Mesh {i}", meshes[i]); } //ReadWithAssetImportContext
public void Import(Stream input, string path) { var prefabPath = Path.GetDirectoryName(path) + "/" + Path.GetFileNameWithoutExtension(path) + ".prefab"; if (File.Exists(prefabPath)) { return; } try { var reader = new Fmdl(); reader.Read(input); Directory.CreateDirectory(Path.GetDirectoryName(Directory.GetParent(assetPath) + "/" + path)); var createMeshCommand = new CreateMesh(() => reader.CreateAndSaveMesh(path)); unityThreadDispacher.DispatchCommand(createMeshCommand); } catch (Exception e) { UnityEngine.Debug.LogError(e); throw; } }
} //ReadWithAssetImportContext private void Read(Fmdl fmdl, GameObject mainObject, FoxModel foxModel, Transform[] bones, Texture[] textures, Material[] materials, Mesh[] meshes, Transform rootBone) { bool isGZFormat = fmdl.version == 2.03f; int boneCount = fmdl.fmdlBones != null ? fmdl.fmdlBones.Length : 0; int materialCount = fmdl.fmdlMaterialInstances.Length; int textureCount = fmdl.fmdlTextures != null ? fmdl.fmdlTextures.Length : 0; int meshCount = fmdl.fmdlMeshInfos.Length; int meshGroupCount = fmdl.fmdlMeshGroups.Length; { Fmdl.FmdlBoundingBox fmdlBoundingBox = fmdl.fmdlBoundingBoxes[0]; Bounds bounds = new Bounds(); bounds.SetMinMax(new Vector3(-fmdlBoundingBox.min.x, fmdlBoundingBox.min.y, fmdlBoundingBox.min.z), new Vector3(-fmdlBoundingBox.max.x, fmdlBoundingBox.max.y, fmdlBoundingBox.max.z)); BoxCollider boxCollider = rootBone.gameObject.AddComponent<BoxCollider>(); boxCollider.center = rootBone.InverseTransformPoint(bounds.center); boxCollider.size = bounds.size; } //code block for (int i = 0; i < boneCount; i++) { bones[i] = new GameObject().transform; Fmdl.FmdlBone fmdlBone = fmdl.fmdlBones[i]; Fmdl.FmdlBoundingBox fmdlBoundingBox = fmdl.fmdlBoundingBoxes[fmdlBone.boundingBoxIndex]; //Get the name. if (isGZFormat) bones[i].gameObject.name = fmdl.fmdlStrings[fmdlBone.nameIndex]; else bones[i].gameObject.name = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlBone.nameIndex]); try { UInt64.Parse(bones[i].gameObject.name, System.Globalization.NumberStyles.HexNumber); bones[i].name = $"SKL_{(Int32.Parse(bones[i - 1].name.Substring(4, 3)) + 1).ToString("000")}_UNKNOWN ({bones[i].name})"; } //try catch { } //Assign the parent. if (fmdlBone.parentIndex != -1) bones[i].parent = bones[fmdlBone.parentIndex]; else bones[i].parent = rootBone.transform; bones[i].position = new Vector3(-fmdlBone.worldPosition.x, fmdlBone.worldPosition.y, fmdlBone.worldPosition.z); //Set up the bounding box. Bounds bounds = new Bounds(); //The x min and max are swapped here on purpose! The max value will end up as the smallest value and the min value will end up as the largest value if they aren't swapped here! bounds.SetMinMax(new Vector3(-fmdlBoundingBox.max.x, fmdlBoundingBox.min.y, fmdlBoundingBox.min.z), new Vector3(-fmdlBoundingBox.min.x, fmdlBoundingBox.max.y, fmdlBoundingBox.max.z)); BoxCollider boxCollider = bones[i].gameObject.AddComponent<BoxCollider>(); boxCollider.center = bones[i].InverseTransformPoint(bounds.center); boxCollider.size = bounds.size; } //for for (int i = 0; i < textureCount; i++) { string name; Fmdl.FmdlTexture fmdlTexture = fmdl.fmdlTextures[i]; //Get the name. if (isGZFormat) { name = fmdl.fmdlStrings[fmdlTexture.pathIndex] + fmdl.fmdlStrings[fmdlTexture.nameIndex]; name = name.Substring(0, name.IndexOf(".")) + ".dds"; } //if else name = Hashing.TryGetPathName(fmdl.fmdlPathCode64s[fmdlTexture.pathIndex]) + ".dds"; //Read the file. if (File.Exists($"{Globals.GetTexturePath()}\\{name}")) textures[i] = LoadTextureDXT($"{Globals.GetTexturePath()}\\{name}"); else { Debug.LogWarning($"Could not find {Globals.GetTexturePath()}\\{name}"); Texture2D texture = new Texture2D(512, 512); for (int j = 0; j < 512; j++) for (int h = 0; h < 512; h++) { Color c = new Color(0.25f, 0.25f, 0.25f); if (((j / 32) % 2 == 0 && (h / 32) % 2 != 0) || ((j / 32) % 2 != 0 && (h / 32) % 2 == 0)) c = new Color(0.5f, 0.5f, 0.5f); texture.SetPixel(j, h, c); } //for texture.Apply(); textures[i] = texture; } //else textures[i].name = name; } //for for (int i = 0; i < materialCount; i++) { string shaderName; string materialName; Fmdl.FmdlMaterialInstance fmdlMaterialInstance = fmdl.fmdlMaterialInstances[i]; //Get the shader and material name. if (isGZFormat) { shaderName = fmdl.fmdlStrings[fmdl.fmdlMaterials[fmdlMaterialInstance.materialIndex].typeIndex]; materialName = fmdl.fmdlStrings[fmdlMaterialInstance.nameIndex]; } //if else { shaderName = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdl.fmdlMaterials[fmdlMaterialInstance.materialIndex].typeIndex]); materialName = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMaterialInstance.nameIndex]); } //else //Some ombs models have broken, unused, materials in them. Try catch here is necessary to handle them. try { materials[i] = new Material(Shader.Find($"FoxShaders/{shaderName}")); } //try catch { materials[i] = new Material(Shader.Find($"FoxShaders/fox3DDF_Blin_LNM")); Debug.LogWarning($"Material {materialName} trying to use missing shader: {shaderName}! Defaulting to fox3DDF_Blin_LNM!"); } //catch materials[i].name = materialName; //Link textures. for (int j = fmdlMaterialInstance.firstTextureIndex; j < fmdlMaterialInstance.firstTextureIndex + fmdlMaterialInstance.textureCount; j++) { string textureType; Fmdl.FmdlMaterialParameter fmdlMaterialParameter = fmdl.fmdlMaterialParameters[j]; if (isGZFormat) textureType = fmdl.fmdlStrings[fmdlMaterialParameter.nameIndex]; else textureType = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMaterialParameter.nameIndex]); materials[i].SetTexture($"_{textureType}", textures[fmdlMaterialParameter.referenceIndex]); materials[i].SetTextureScale($"_{textureType}", new Vector2(1, -1)); //Have to flip textures here because Texture2D.LoadRawData is bugged an imports DDS files upside down. } //for //Set parameters. for (int j = fmdlMaterialInstance.firstParameterIndex; j < fmdlMaterialInstance.firstParameterIndex + fmdlMaterialInstance.parameterCount; j++) { string parameterName; Fmdl.FmdlMaterialParameter fmdlMaterialParameter = fmdl.fmdlMaterialParameters[j]; if (isGZFormat) parameterName = fmdl.fmdlStrings[fmdlMaterialParameter.nameIndex]; else parameterName = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMaterialParameter.nameIndex]); materials[i].SetVector($"_{parameterName}", fmdl.fmdlMaterialParameterVectors[fmdlMaterialParameter.referenceIndex]); } //for } //for for (int i = 0; i < meshGroupCount; i++) { foxModel.meshGroups[i] = new FoxMeshGroup(); string name; Fmdl.FmdlMeshGroup fmdlMeshGroup = fmdl.fmdlMeshGroups[i]; if (isGZFormat) name = fmdl.fmdlStrings[fmdlMeshGroup.nameIndex]; else name = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMeshGroup.nameIndex]); foxModel.meshGroups[i].name = name; foxModel.meshGroups[i].parent = fmdlMeshGroup.parentIndex; if (fmdlMeshGroup.invisibilityFlag == 0) foxModel.meshGroups[i].visible = true; else foxModel.meshGroups[i].visible = false; } //for for (int i = 0; i < meshCount; i++) { meshes[i] = new Mesh(); GameObject gameObject = new GameObject(); gameObject.transform.parent = mainObject.transform; SkinnedMeshRenderer skinnedMeshRenderer = gameObject.AddComponent<SkinnedMeshRenderer>(); foxModel.meshDefinitions[i] = new FoxMeshDefinition(); Fmdl.FmdlMesh fmdlMesh = fmdl.fmdlMeshes[i]; Fmdl.FmdlMeshInfo fmdlMeshInfo = fmdl.fmdlMeshInfos[i]; Fmdl.FmdlBoneGroup fmdlBoneGroup = fmdl.fmdlBoneGroups != null ? fmdl.fmdlBoneGroups[fmdlMeshInfo.boneGroupIndex] : new Fmdl.FmdlBoneGroup(); int vertexLength = fmdlMesh.vertices.Length; int faceLength = fmdlMesh.triangles.Length; string name; Vector3[] vertices = new Vector3[vertexLength]; Vector3[] normals = new Vector3[vertexLength]; Vector4[] tangents = fmdlMesh.tangents != null ? new Vector4[vertexLength] : new Vector4[0]; Color[] colors = fmdlMesh.colors != null ? new Color[vertexLength] : new Color[0]; BoneWeight[] boneWeights = fmdlMesh.boneWeights != null ? new BoneWeight[vertexLength] : new BoneWeight[0]; Vector2[] uv = fmdlMesh.uv != null ? new Vector2[vertexLength] : new Vector2[0]; Vector2[] uv2 = fmdlMesh.uv2 != null ? new Vector2[vertexLength] : new Vector2[0]; Vector2[] uv3 = fmdlMesh.uv3 != null ? new Vector2[vertexLength] : new Vector2[0]; Vector2[] uv4 = fmdlMesh.uv4 != null ? new Vector2[vertexLength] : new Vector2[0]; int[] triangles = new int[faceLength]; Matrix4x4[] bindPoses; List<Transform> usedBones = new List<Transform>(0); Transform[] usedBonesArray; for (int j = 0; j < vertexLength; j++) { vertices[j] = new Vector3(-fmdlMesh.vertices[j].x, fmdlMesh.vertices[j].y, fmdlMesh.vertices[j].z); normals[j] = new Vector3(-fmdlMesh.normals[j].x, fmdlMesh.normals[j].y, fmdlMesh.normals[j].z); if (tangents.Length > 0) tangents[j] = new Vector4(-fmdlMesh.tangents[j].x, fmdlMesh.tangents[j].y, fmdlMesh.tangents[j].z, fmdlMesh.tangents[j].w); if (colors.Length > 0) colors[j] = new Color(fmdlMesh.colors[j].x / 255f, fmdlMesh.colors[j].y / 255f, fmdlMesh.colors[j].z / 255f, fmdlMesh.colors[j].w / 255f); if (boneWeights.Length > 0) { boneWeights[j].weight0 = fmdlMesh.boneWeights[j].x / 255f; boneWeights[j].weight1 = fmdlMesh.boneWeights[j].y / 255f; boneWeights[j].weight2 = fmdlMesh.boneWeights[j].z / 255f; boneWeights[j].weight3 = fmdlMesh.boneWeights[j].w / 255f; boneWeights[j].boneIndex0 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].x]; boneWeights[j].boneIndex1 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].y]; boneWeights[j].boneIndex2 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].z]; boneWeights[j].boneIndex3 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].w]; } //if if (uv.Length > 0) uv[j] = new Vector2(fmdlMesh.uv[j].x, 1 - fmdlMesh.uv[j].y); if (uv2.Length > 0) uv2[j] = new Vector2(fmdlMesh.uv2[j].x, 1 - fmdlMesh.uv2[j].y); if (uv3.Length > 0) uv3[j] = new Vector2(fmdlMesh.uv3[j].x, 1 - fmdlMesh.uv3[j].y); if (uv4.Length > 0) uv4[j] = new Vector2(fmdlMesh.uv4[j].x, 1 - fmdlMesh.uv4[j].y); } //for for (int j = 0; j < faceLength; j++) triangles[j] = fmdlMesh.triangles[j]; for (int j = 0; j < boneWeights.Length; j++) { if (boneWeights[j].weight0 > 0f) { if (usedBones.Contains(bones[boneWeights[j].boneIndex0])) boneWeights[j].boneIndex0 = usedBones.IndexOf(bones[boneWeights[j].boneIndex0]); else { usedBones.Add(bones[boneWeights[j].boneIndex0]); boneWeights[j].boneIndex0 = usedBones.IndexOf(bones[boneWeights[j].boneIndex0]); } //else } //if else boneWeights[j].boneIndex0 = 0; if (boneWeights[j].weight1 > 0f) { if (usedBones.Contains(bones[boneWeights[j].boneIndex1])) boneWeights[j].boneIndex1 = usedBones.IndexOf(bones[boneWeights[j].boneIndex1]); else { usedBones.Add(bones[boneWeights[j].boneIndex1]); boneWeights[j].boneIndex1 = usedBones.IndexOf(bones[boneWeights[j].boneIndex1]); } //else } //if else boneWeights[j].boneIndex1 = 0; if (boneWeights[j].weight2 > 0f) { if (usedBones.Contains(bones[boneWeights[j].boneIndex2])) boneWeights[j].boneIndex2 = usedBones.IndexOf(bones[boneWeights[j].boneIndex2]); else { usedBones.Add(bones[boneWeights[j].boneIndex2]); boneWeights[j].boneIndex2 = usedBones.IndexOf(bones[boneWeights[j].boneIndex2]); } //else } //if else boneWeights[j].boneIndex2 = 0; if (boneWeights[j].weight3 > 0f) { if (usedBones.Contains(bones[boneWeights[j].boneIndex3])) boneWeights[j].boneIndex3 = usedBones.IndexOf(bones[boneWeights[j].boneIndex3]); else { usedBones.Add(bones[boneWeights[j].boneIndex3]); boneWeights[j].boneIndex3 = usedBones.IndexOf(bones[boneWeights[j].boneIndex3]); } //else } //if else boneWeights[j].boneIndex3 = 0; } //for usedBonesArray = usedBones.ToArray(); bindPoses = new Matrix4x4[usedBonesArray.Length]; for (int j = 0; j < usedBonesArray.Length; j++) bindPoses[j] = usedBones[j].worldToLocalMatrix * gameObject.transform.localToWorldMatrix; meshes[i].vertices = vertices; meshes[i].normals = normals; meshes[i].tangents = tangents; meshes[i].colors = colors; meshes[i].boneWeights = boneWeights; meshes[i].uv = uv; meshes[i].uv2 = uv2; meshes[i].uv3 = uv3; meshes[i].uv4 = uv4; meshes[i].triangles = triangles; meshes[i].bindposes = bindPoses; skinnedMeshRenderer.bones = usedBonesArray; skinnedMeshRenderer.sharedMaterial = materials[fmdlMeshInfo.materialInstanceIndex]; skinnedMeshRenderer.sharedMesh = meshes[i]; skinnedMeshRenderer.rootBone = mainObject.transform; foxModel.meshDefinitions[i].mesh = meshes[i]; foxModel.meshDefinitions[i].meshGroup = Array.Find(fmdl.fmdlMeshGroupEntries, x => x.firstMeshIndex <= i && x.firstMeshIndex + x.meshCount > i).meshGroupIndex; foxModel.meshDefinitions[i].alpha = (FoxMeshDefinition.Alpha)fmdlMeshInfo.alphaEnum; foxModel.meshDefinitions[i].shadow = (FoxMeshDefinition.Shadow)fmdlMeshInfo.shadowEnum; if (isGZFormat) name = fmdl.fmdlStrings[fmdl.fmdlMeshGroups[foxModel.meshDefinitions[i].meshGroup].nameIndex]; else name = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdl.fmdlMeshGroups[foxModel.meshDefinitions[i].meshGroup].nameIndex]); gameObject.name = $"{i} - {name}"; } //for } //Read
public GameObject GetDataFromFmdl(Fmdl fmdl) { Globals.ReadTexturePath(); meshes = new UnityMesh[fmdl.section0Block3Entries.Count]; GameObject fmdlGameObject = new GameObject(); fmdlGameObject.name = fmdl.name; GameObject[] subFmdlGameObjects = new GameObject[fmdl.objects.Count]; Transform[] bones; Matrix4x4[] bindPoses; Bounds[] bounds = new Bounds[fmdl.section0BlockDEntries.Count]; fmdlGameObject.AddComponent <FoxModel>().definitions = new FoxMeshDefinition[fmdl.objects.Count]; UnityMaterial[] materials = new UnityMaterial[fmdl.section0Block4Entries.Count]; if (fmdl.bonesIndex != -1) { bones = new Transform[fmdl.section0Block0Entries.Count]; bindPoses = new Matrix4x4[fmdl.section0Block0Entries.Count]; } //if else { bones = new Transform[0]; bindPoses = new Matrix4x4[0]; } //else for (int i = 0; i < fmdl.section0Block4Entries.Count; i++) { materials[i].material = new Material(Shader.Find("FoxShaders/Base")); //materials[i].material = new Material(Shader.Find("Legacy Shaders/Transparent/Cutout/Bumped Diffuse")); //materials[i].material = new Material(Shader.Find("Standard")); if (fmdl.stringsIndex != -1) { materials[i].material.name = fmdl.strings[fmdl.section0Block4Entries[i].stringId]; materials[i].materialName = fmdl.strings[fmdl.section0Block8Entries[fmdl.section0Block4Entries[i].materialId].stringId]; materials[i].materialType = fmdl.strings[fmdl.section0Block8Entries[fmdl.section0Block4Entries[i].materialId].typeId]; for (int j = fmdl.section0Block4Entries[i].firstTextureId; j < fmdl.section0Block4Entries[i].firstTextureId + fmdl.section0Block4Entries[i].numTextures; j++) { string textureName = ""; int extensionLocation; textureName = fmdl.strings[fmdl.section0Block6Entries[fmdl.section0Block7Entries[j].referenceId].pathId] + fmdl.strings[fmdl.section0Block6Entries[fmdl.section0Block7Entries[j].referenceId].stringId]; //materials[i].textureType = fmdl.strings[fmdl.section0Block7Entries[fmdl.section0Block4Entries[i].firstTextureId].stringId]; extensionLocation = textureName.IndexOf('.'); textureName = textureName.Substring(0, extensionLocation); if (File.Exists(Globals.texturePath + "\\" + textureName + ".dds")) { Texture2D texture = LoadTextureDXT(Globals.texturePath + "\\" + textureName + ".dds"); texture.name = textureName + ".dds"; if (fmdl.strings[fmdl.section0Block7Entries[j].stringId] == "Base_Tex_SRGB") { materials[i].material.mainTexture = texture; } else if (fmdl.strings[fmdl.section0Block7Entries[j].stringId] == "NormalMap_Tex_NRM") { materials[i].material.SetTexture("_BumpMap", texture); } else if (fmdl.strings[fmdl.section0Block7Entries[j].stringId] == "SpecularMap_Tex_LIN") { materials[i].material.SetTexture("_SRM", texture); } else if (fmdl.strings[fmdl.section0Block7Entries[j].stringId] == "Layer_Tex_SRGB") { materials[i].material.SetTexture("_LayerTex", texture); } else if (fmdl.strings[fmdl.section0Block7Entries[j].stringId] == "LayerMask_Tex_LIN") { materials[i].material.SetTexture("_LayerMask", texture); } //_MainTex = Diffuse. _BumpMap = Normal Map. _Color = Main Colour. _SpecColor = Specular Map. _Shininess. } //if else { UnityEngine.Debug.Log("Could not find: " + Globals.texturePath + "\\" + textureName + ".dds"); } //else } //for } //if else { materials[i].material.name = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block4Entries[i].stringId]); materials[i].materialName = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block8Entries[fmdl.section0Block4Entries[i].materialId].stringId]); materials[i].materialType = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block8Entries[fmdl.section0Block4Entries[i].materialId].typeId]); if (fmdl.texturePathsIndex != -1) { for (int j = fmdl.section0Block4Entries[i].firstTextureId; j < fmdl.section0Block4Entries[i].firstTextureId + fmdl.section0Block4Entries[i].numTextures; j++) { if (File.Exists(Globals.texturePath + "\\" + Hashing.TryGetPathName(fmdl.section0Block15Entries[fmdl.section0Block7Entries[j].referenceId]) + ".dds")) { Texture2D texture = LoadTextureDXT(Globals.texturePath + "\\" + Hashing.TryGetPathName(fmdl.section0Block15Entries[fmdl.section0Block7Entries[j].referenceId]) + ".dds"); texture.name = Hashing.TryGetPathName(fmdl.section0Block15Entries[fmdl.section0Block7Entries[j].referenceId]) + ".dds"; //materials[i].textureType = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[fmdl.section0Block4Entries[i].firstTextureId].stringId]); if (Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]) == "Base_Tex_SRGB") { materials[i].material.mainTexture = texture; } else if (Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]) == "NormalMap_Tex_NRM") { materials[i].material.SetTexture("_BumpMap", texture); } else if (Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]) == "SpecularMap_Tex_LIN") { materials[i].material.SetTexture("_SRM", texture); } else if (Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]) == "Layer_Tex_SRGB") { materials[i].material.SetTexture("_LayerTex", texture); } else if (Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]) == "LayerMask_Tex_LIN") { materials[i].material.SetTexture("_LayerMask", texture); } } //if else { UnityEngine.Debug.Log("Could not find: " + Globals.texturePath + "\\" + Hashing.TryGetPathName(fmdl.section0Block15Entries[fmdl.section0Block7Entries[j].referenceId]) + ".dds"); } //else } //for } //if } //else } //for for (int i = 0; i < bounds.Length; i++) { bounds[i].SetMinMax(new Vector3(fmdl.section0BlockDEntries[i].minZ, fmdl.section0BlockDEntries[i].minY, fmdl.section0BlockDEntries[i].minX), new Vector3(fmdl.section0BlockDEntries[i].maxZ, fmdl.section0BlockDEntries[i].maxY, fmdl.section0BlockDEntries[i].maxX)); } //for Transform rootBone = new GameObject("[Root]").transform; //From what I can tell, the real name is "". But it looks kinda dumb having "" as its name; so using "[Root]" as a placeholder seems better. rootBone.parent = fmdlGameObject.transform; { BoxCollider collider = rootBone.gameObject.AddComponent <BoxCollider>(); collider.center = rootBone.InverseTransformPoint(bounds[0].center); //Have to convert these to local positions. They're stored as world positions. collider.size = bounds[0].size; } //code block for (int i = 0; i < bones.Length; i++) { bones[i] = new GameObject().transform; bones[i].position = new Vector3(fmdl.section0Block0Entries[i].worldPositionZ, fmdl.section0Block0Entries[i].worldPositionY, fmdl.section0Block0Entries[i].worldPositionX); BoxCollider collider = bones[i].gameObject.AddComponent <BoxCollider>(); collider.center = bones[i].InverseTransformPoint(bounds[fmdl.section0Block0Entries[i].boundingBoxId].center); //Have to convert these to local positions. They're stored as world positions. collider.size = bounds[fmdl.section0Block0Entries[i].boundingBoxId].size; if (fmdl.stringsIndex != -1) { bones[i].name = fmdl.strings[fmdl.section0Block0Entries[i].stringId]; } else { bones[i].name = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block0Entries[i].stringId]); } if (fmdl.section0Block0Entries[i].parentId != 0xFFFF) { bones[i].parent = bones[fmdl.section0Block0Entries[i].parentId]; } else { bones[i].parent = rootBone; } } //for for (int i = 0; i < fmdl.objects.Count; i++) { int lod = 0; //Temporary solution. 0 loads the normal faces. 1 loads the first set of LOD faces. 2 loads the next set. Etc.... meshes[i].vertices = new Vector3[fmdl.objects[i].vertices.Length]; meshes[i].normals = new Vector3[fmdl.objects[i].additionalVertexData.Length]; meshes[i].tangents = new Vector4[fmdl.objects[i].additionalVertexData.Length]; meshes[i].colour = new Color[fmdl.objects[i].additionalVertexData.Length]; meshes[i].uv = new Vector2[fmdl.objects[i].additionalVertexData.Length]; meshes[i].uv2 = new Vector2[fmdl.objects[i].additionalVertexData.Length]; meshes[i].uv3 = new Vector2[fmdl.objects[i].additionalVertexData.Length]; meshes[i].uv4 = new Vector2[fmdl.objects[i].additionalVertexData.Length]; //meshes[i].faces = new int[fmdl.objects[i].faces.Length * 3]; meshes[i].faces = new int[fmdl.objects[i].lodFaces[lod].Length * 3]; meshes[i].boneWeights = new BoneWeight[fmdl.objects[i].additionalVertexData.Length]; //Position for (int j = 0; j < fmdl.objects[i].vertices.Length; j++) { meshes[i].vertices[j] = new Vector3(fmdl.objects[i].vertices[j].z, fmdl.objects[i].vertices[j].y, fmdl.objects[i].vertices[j].x); } //Normals, Bone Weights, Bone Group Ids and UVs for (int j = 0; j < fmdl.objects[i].additionalVertexData.Length; j++) { meshes[i].normals[j] = new Vector3(fmdl.objects[i].additionalVertexData[j].normalZ, fmdl.objects[i].additionalVertexData[j].normalY, fmdl.objects[i].additionalVertexData[j].normalX); meshes[i].tangents[j] = new Vector4(fmdl.objects[i].additionalVertexData[j].tangentZ, fmdl.objects[i].additionalVertexData[j].tangentY, fmdl.objects[i].additionalVertexData[j].tangentX, fmdl.objects[i].additionalVertexData[j].tangentW); meshes[i].colour[j] = new Color(fmdl.objects[i].additionalVertexData[j].colourR, fmdl.objects[i].additionalVertexData[j].colourG, fmdl.objects[i].additionalVertexData[j].colourB, fmdl.objects[i].additionalVertexData[j].colourA); if (fmdl.bonesIndex != -1) { meshes[i].boneWeights[j].weight0 = fmdl.objects[i].additionalVertexData[j].boneWeightX; meshes[i].boneWeights[j].weight1 = fmdl.objects[i].additionalVertexData[j].boneWeightY; meshes[i].boneWeights[j].weight2 = fmdl.objects[i].additionalVertexData[j].boneWeightZ; meshes[i].boneWeights[j].weight3 = fmdl.objects[i].additionalVertexData[j].boneWeightW; meshes[i].boneWeights[j].boneIndex0 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup0Id]; meshes[i].boneWeights[j].boneIndex1 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup1Id]; meshes[i].boneWeights[j].boneIndex2 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup2Id]; meshes[i].boneWeights[j].boneIndex3 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup3Id]; } //if meshes[i].uv[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].textureU, fmdl.objects[i].additionalVertexData[j].textureV); meshes[i].uv2[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].unknownU0, fmdl.objects[i].additionalVertexData[j].unknownV0); meshes[i].uv3[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].unknownU1, fmdl.objects[i].additionalVertexData[j].unknownV1); meshes[i].uv4[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].unknownU2, fmdl.objects[i].additionalVertexData[j].unknownV2); } //for //Faces /*for (int j = 0, h = 0; j < fmdl.objects[i].faces.Length; j++, h += 3) * { * meshes[i].faces[h] = fmdl.objects[i].faces[j].vertex1Id; * meshes[i].faces[h + 1] = fmdl.objects[i].faces[j].vertex2Id; * meshes[i].faces[h + 2] = fmdl.objects[i].faces[j].vertex3Id; * } //for*/ for (int j = 0, h = 0; j < fmdl.objects[i].lodFaces[lod].Length; j++, h += 3) { meshes[i].faces[h] = fmdl.objects[i].lodFaces[lod][j].vertex1Id; meshes[i].faces[h + 1] = fmdl.objects[i].lodFaces[lod][j].vertex2Id; meshes[i].faces[h + 2] = fmdl.objects[i].lodFaces[lod][j].vertex3Id; } //for //Render the mesh in Unity. subFmdlGameObjects[i] = new GameObject(); FoxMeshDefinition foxMeshDefinition = new FoxMeshDefinition(); //Get the mesh name. for (int j = 0; j < fmdl.section0Block2Entries.Count; j++) { if (i >= fmdl.section0Block2Entries[j].firstObjectId && i < fmdl.section0Block2Entries[j].firstObjectId + fmdl.section0Block2Entries[j].numObjects) { if (fmdl.stringsIndex != -1) { subFmdlGameObjects[i].name = i + " - " + fmdl.strings[fmdl.section0Block1Entries[fmdl.section0Block2Entries[j].meshGroupId].stringId]; foxMeshDefinition.meshGroup = fmdl.strings[fmdl.section0Block1Entries[fmdl.section0Block2Entries[j].meshGroupId].stringId]; } //if else { subFmdlGameObjects[i].name = i + " - " + Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block1Entries[fmdl.section0Block2Entries[j].meshGroupId].stringId]); foxMeshDefinition.meshGroup = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block1Entries[fmdl.section0Block2Entries[j].meshGroupId].stringId]); } //else break; } //if } //for subFmdlGameObjects[i].transform.parent = fmdlGameObject.transform; SkinnedMeshRenderer meshRenderer = subFmdlGameObjects[i].AddComponent <SkinnedMeshRenderer>(); meshRenderer.material = materials[fmdl.section0Block3Entries[i].materialInstanceId].material; foxMeshDefinition.material = materials[fmdl.section0Block3Entries[i].materialInstanceId].materialName; foxMeshDefinition.materialType = materials[fmdl.section0Block3Entries[i].materialInstanceId].materialType; Mesh mesh = new Mesh(); foxMeshDefinition.mesh = mesh; mesh.vertices = meshes[i].vertices; mesh.uv = meshes[i].uv; mesh.uv2 = meshes[i].uv2; mesh.uv3 = meshes[i].uv3; mesh.uv4 = meshes[i].uv4; mesh.normals = meshes[i].normals; mesh.tangents = meshes[i].tangents; mesh.triangles = meshes[i].faces; mesh.boneWeights = meshes[i].boneWeights; for (int j = 0; j < bones.Length; j++) { bindPoses[j] = bones[j].worldToLocalMatrix * subFmdlGameObjects[i].transform.localToWorldMatrix; } //for mesh.bindposes = bindPoses; meshRenderer.bones = bones; meshRenderer.sharedMesh = mesh; fmdlGameObject.GetComponent <FoxModel>().definitions[i] = foxMeshDefinition; subFmdlGameObjects[i].AddComponent <MeshCollider>(); } //for return(fmdlGameObject); } //GetDataFromFmdl