// Helper method to lookup nonlocal textures from another bnd static Texture2D FindTexture(string path, DarkSoulsTools.GameType gameType) { string gamePath = DarkSoulsTools.GameFolder(gameType); // Map texture reference if (path.Contains(@"\map\")) { var splits = path.Split('\\'); var mapid = splits[splits.Length - 3]; var asset = AssetDatabase.LoadAssetAtPath <Texture2D>($@"Assets/{gamePath}/{mapid}/{Path.GetFileNameWithoutExtension(path)}.dds"); if (asset == null) { // Attempt to load UDSFM texture asset = AssetDatabase.LoadAssetAtPath <Texture2D>($@"Assets/{gamePath}/UDSFMMapTextures/{Path.GetFileNameWithoutExtension(path)}.dds"); } return(asset); } // Chr texture reference else if (path.Contains(@"\chr\")) { var splits = path.Split('\\'); var chrid = splits[splits.Length - 3]; var asset = AssetDatabase.LoadAssetAtPath <Texture2D>($@"Assets/{gamePath}/Chr/{chrid}/{Path.GetFileNameWithoutExtension(path)}.dds"); if (asset == null) { // Attempt to load shared chr textures asset = AssetDatabase.LoadAssetAtPath <Texture2D>($@"Assets/{gamePath}/Chr/sharedTextures/{Path.GetFileNameWithoutExtension(path)}.dds"); } return(asset); } // Obj texture reference else if (path.Contains(@"\obj\")) { var splits = path.Split('\\'); var objid = splits[splits.Length - 3]; var asset = AssetDatabase.LoadAssetAtPath <Texture2D>($@"Assets/{gamePath}/Obj/{objid}/{Path.GetFileNameWithoutExtension(path)}.dds"); if (asset == null) { // Attempt to load shared chr textures asset = AssetDatabase.LoadAssetAtPath <Texture2D>($@"Assets/{gamePath}/Obj/sharedTextures/{Path.GetFileNameWithoutExtension(path)}.dds"); } return(asset); } // Parts texture reference else if (path.Contains(@"\parts\")) { var asset = AssetDatabase.LoadAssetAtPath <Texture2D>($@"Assets/{gamePath}/Parts/textures/{Path.GetFileNameWithoutExtension(path)}.dds"); return(asset); } return(null); }
static public void ImportFlver(FLVER flver, FLVERAssetLink assetLink, DarkSoulsTools.GameType gameType, string assetName, string texturePath = null, bool mapflver = false) { Material[] materials = new Material[flver.Materials.Count]; string gamePath = DarkSoulsTools.GameFolder(gameType); if (!AssetDatabase.IsValidFolder(assetName)) { AssetDatabase.CreateFolder(Path.GetDirectoryName(assetName + ".blah"), Path.GetFileNameWithoutExtension(assetName + ".blah")); } Shader shader = AssetDatabase.LoadAssetAtPath <Shader>("Assets/dstools/Shaders/FLVERShader.shadergraph"); Shader shaderObj = AssetDatabase.LoadAssetAtPath <Shader>("Assets/dstools/Shaders/ObjFLVERShader.shadergraph"); Shader shaderDiff = AssetDatabase.LoadAssetAtPath <Shader>("Assets/dstools/Shaders/FLVERShaderDiffuse.shadergraph"); var t = 0; foreach (var m in flver.Materials) { //string name = m.Name; //if (name == null || name == "") //{ string name = Path.GetFileNameWithoutExtension(assetName) + $@"_{t}"; //} //bool normalquery = (m.Textures.Where(x => ((x.Type.ToUpper() == "G_BUMPMAPTEXTURE") || (x.Type.ToUpper() == "G_BUMPMAP"))).Count() >= 1); bool normalquery = false; Texture2D albedo = null; Texture2D specular = null; Texture2D normal = null; bool IsMapTexture = mapflver; var MTD = AssetDatabase.LoadAssetAtPath <MTDAssetLink>($@"Assets/{gamePath}/MTD/{Path.GetFileNameWithoutExtension(m.MTD)}.asset"); if (texturePath != null) { foreach (var matParam in m.Textures) { var paramNameCheck = matParam.Type.ToUpper(); if (paramNameCheck == "G_DIFFUSETEXTURE" || paramNameCheck == "G_DIFFUSE" || paramNameCheck.Contains("ALBEDO")) { var texPath = matParam.Path; if (texPath == "") { texPath = MTD.Textures.Find(x => (x.Name == matParam.Type)).TexturePath; if (texPath == "") { continue; } } if (albedo == null) { albedo = AssetDatabase.LoadAssetAtPath <Texture2D>($@"{texturePath}/{Path.GetFileNameWithoutExtension(texPath)}.dds"); if (albedo == null) { albedo = FindTexture(texPath, gameType); } } } if (paramNameCheck == "G_SPECULARTEXTURE" || paramNameCheck == "G_SPECULAR") { specular = AssetDatabase.LoadAssetAtPath <Texture2D>($@"{texturePath}/{Path.GetFileNameWithoutExtension(matParam.Path)}.dds"); if (specular == null) { specular = FindTexture(matParam.Path, gameType); } } if (paramNameCheck == "G_BUMPMAPTEXTURE" || paramNameCheck == "G_BUMPMAP" || paramNameCheck.Contains("NORMAL")) { var texPath = matParam.Path; if (texPath == "") { texPath = MTD.Textures.Find(x => (x.Name == matParam.Type)).TexturePath; if (texPath == "") { continue; } } if (normal == null) { normal = AssetDatabase.LoadAssetAtPath <Texture2D>($@"{texturePath}/{Path.GetFileNameWithoutExtension(texPath)}.dds"); if (normal == null) { normal = FindTexture(texPath, gameType); } } normalquery = true; } } } Material mat; /*if (IsMapTexture && specular != null) * { * mat = new Material(shader); * mat.SetTexture("_Albedo", albedo); * mat.SetTexture("_Specular", specular); * mat.SetTexture("_Normal", normal); * } * else */ if (!normalquery) { mat = new Material(shaderDiff); mat.SetTexture("_MainTex", albedo); } else { mat = new Material(shaderObj); mat.SetTexture("_MainTex", albedo); mat.SetTexture("_Specular", specular); mat.SetTexture("_BumpMap", normal); } mat.name = name; materials[t] = mat; t++; AssetDatabase.CreateAsset(mat, assetName + "/" + name + ".mat"); } GameObject root = new GameObject(Path.GetFileNameWithoutExtension(assetName)); GameObject meshesObj = new GameObject("Meshes"); GameObject bonesObj = new GameObject("Bones"); meshesObj.transform.parent = root.transform; bonesObj.transform.parent = root.transform; // import the skeleton Transform[] bones = new Transform[flver.Bones.Count]; Matrix4x4[] bindPoses = new Matrix4x4[flver.Bones.Count]; for (int i = 0; i < flver.Bones.Count; i++) { var fbone = flver.Bones[i]; bones[i] = new GameObject(fbone.Name).transform; EulerToTransform(new Vector3(fbone.Rotation.X, fbone.Rotation.Y, fbone.Rotation.Z), bones[i]); bones[i].localPosition = new Vector3(fbone.Translation.X, fbone.Translation.Y, fbone.Translation.Z); bones[i].localScale = new Vector3(fbone.Scale.X, fbone.Scale.Y, fbone.Scale.Z); //SetBoneWorldTransform(bones[i], flver.Bones.ToArray(), i); //bindPoses[i] = bones[i].worldToLocalMatrix * root.transform.localToWorldMatrix; } // Skeleton parenting for (int i = 0; i < flver.Bones.Count; i++) { var fbone = flver.Bones[i]; if (fbone.ParentIndex == -1) { //bones[i].parent = root.transform; bones[i].SetParent(bonesObj.transform, false); bindPoses[i] = bones[i].worldToLocalMatrix * root.transform.localToWorldMatrix; } else { //bones[i].parent = bones[fbone.ParentIndex]; bones[i].SetParent(bones[fbone.ParentIndex], false); bindPoses[i] = bones[i].worldToLocalMatrix * root.transform.localToWorldMatrix; } } // Import the meshes int index = 0; foreach (var m in flver.Meshes) { var mesh = new Mesh(); var verts = new List <Vector3>(); var normals = new List <Vector3>(); var tangents = new List <Vector4>(); var boneweights = new List <BoneWeight>(); var smcount = 0; bool usestangents = false; int uvcount = m.Vertices[0].UVs.Count; List <Vector2>[] uvs = new List <Vector2> [uvcount]; List <Material> matList = new List <Material>(); // Add the mesh to the asset link FLVERAssetLink.SubmeshInfo info = new FLVERAssetLink.SubmeshInfo(); info.Name = flver.Materials[m.MaterialIndex].Name; var MTD = AssetDatabase.LoadAssetAtPath <MTDAssetLink>($@"Assets/{gamePath}/MTD/{Path.GetFileNameWithoutExtension(flver.Materials[m.MaterialIndex].MTD)}.asset"); info.Mtd = MTD; assetLink.Submeshes.Add(info); int lightmapUVIndex = 1; // Use MTD to get lightmap uv index if (gameType != DarkSoulsTools.GameType.Sekiro) { if (MTD != null) { lightmapUVIndex = (MTD.LightmapUVIndex != -1) ? MTD.LightmapUVIndex : 1; if (lightmapUVIndex >= uvs.Length) { lightmapUVIndex = 1; } } else { // Do a hardcoded lookup of a material's lightmap UV index from a shitty table :fatcat: if (MaterialLightmapUVIndex.ContainsKey(Path.GetFileNameWithoutExtension(flver.Materials[m.MaterialIndex].MTD))) { lightmapUVIndex = MaterialLightmapUVIndex[Path.GetFileNameWithoutExtension(flver.Materials[m.MaterialIndex].MTD)]; } } } for (int i = 0; i < uvs.Length; i++) { uvs[i] = new List <Vector2>(); } bool isSkinned = false; foreach (var v in m.Vertices) { verts.Add(new Vector3(v.Positions[0].X, v.Positions[0].Y, v.Positions[0].Z)); normals.Add(new Vector3(v.Normals[0].X, v.Normals[0].Y, v.Normals[0].Z)); if (v.Tangents.Count > 0) { tangents.Add(new Vector4(v.Tangents[0].X, v.Tangents[0].Y, v.Tangents[0].Z, v.Tangents[0].W)); usestangents = true; } else { tangents.Add(new Vector4(0, 0, 0, 1)); } for (int i = 0; i < uvs.Length; i++) { // Swap lightmap uvs with uv index 1 because lmao unity if (i == 1) { uvs[i].Add(new Vector2(v.UVs[lightmapUVIndex].X, 1.0f - v.UVs[lightmapUVIndex].Y)); } else if (i == lightmapUVIndex) { uvs[i].Add(new Vector2(v.UVs[1].X, 1.0f - v.UVs[1].Y)); } else { uvs[i].Add(new Vector2(v.UVs[i].X, 1.0f - v.UVs[i].Y)); } } if (v.BoneWeights != null && v.BoneWeights.Count() > 0) { isSkinned = true; var weight = new BoneWeight(); if (m.Unk1 == 0) { weight.boneIndex0 = v.BoneIndices[0]; weight.boneIndex1 = v.BoneIndices[1]; weight.boneIndex2 = v.BoneIndices[2]; weight.boneIndex3 = v.BoneIndices[3]; } else { weight.boneIndex0 = m.BoneIndices[v.BoneIndices[0]]; weight.boneIndex1 = m.BoneIndices[v.BoneIndices[1]]; weight.boneIndex2 = m.BoneIndices[v.BoneIndices[2]]; weight.boneIndex3 = m.BoneIndices[v.BoneIndices[3]]; } if (v.BoneWeights[0] < 0.0) { weight.weight0 = 1.0f; } else { weight.weight0 = v.BoneWeights[0]; } weight.weight1 = v.BoneWeights[1]; weight.weight2 = v.BoneWeights[2]; weight.weight3 = v.BoneWeights[3]; boneweights.Add(weight); } else { boneweights.Add(new BoneWeight()); } } foreach (var fs in m.FaceSets) { if (fs.Vertices.Count() > 0 && fs.Flags == FLVER.FaceSet.FSFlags.None) { matList.Add(materials[m.MaterialIndex]); smcount++; } } mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; mesh.subMeshCount = smcount; mesh.SetVertices(verts); mesh.SetNormals(normals); if (usestangents) { mesh.SetTangents(tangents); } if (isSkinned) { mesh.boneWeights = boneweights.ToArray(); mesh.bindposes = bindPoses; } for (int i = 0; i < uvs.Length; i++) { mesh.SetUVs(i, uvs[i]); } var submesh = 0; foreach (var fs in m.FaceSets) { if (fs.Vertices.Count() == 0) { continue; } if (fs.Flags != FLVER.FaceSet.FSFlags.None) { continue; } mesh.SetTriangles(fs.GetFacesArray(), submesh, true, 0); submesh++; } mesh.RecalculateBounds(); // Setup a game object asset GameObject obj = new GameObject(Path.GetFileNameWithoutExtension(assetName) + $@"_{index}"); if (isSkinned) { obj.AddComponent <SkinnedMeshRenderer>(); obj.GetComponent <SkinnedMeshRenderer>().materials = matList.ToArray(); obj.GetComponent <SkinnedMeshRenderer>().bones = bones; obj.GetComponent <SkinnedMeshRenderer>().sharedMesh = mesh; } else { obj.AddComponent <MeshRenderer>(); obj.GetComponent <MeshRenderer>().materials = matList.ToArray(); obj.AddComponent <MeshFilter>(); obj.GetComponent <MeshFilter>().mesh = mesh; } obj.AddComponent <FlverSubmesh>(); obj.GetComponent <FlverSubmesh>().Link = assetLink; obj.GetComponent <FlverSubmesh>().SubmeshIdx = index; obj.transform.parent = meshesObj.transform; AssetDatabase.CreateAsset(mesh, assetName + $@"/{Path.GetFileNameWithoutExtension(assetName)}_{index}.mesh"); index++; } // If there's no meshes, create an empty one to bind the skeleton to so that Maya works // when you export the skeleton (like with c0000). if (flver.Meshes.Count == 0) { var mesh = new Mesh(); var verts = new List <Vector3>(); var normals = new List <Vector3>(); var tangents = new List <Vector4>(); var boneweights = new List <BoneWeight>(); for (var i = 0; i < 3; i++) { verts.Add(new Vector3(0.0f, 0.0f, 0.0f)); normals.Add(new Vector3(0.0f, 1.0f, 0.0f)); tangents.Add(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); var weight = new BoneWeight(); weight.boneIndex0 = 0; weight.weight0 = 1.0f; boneweights.Add(weight); } mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; mesh.subMeshCount = 1; mesh.SetVertices(verts); mesh.SetNormals(normals); mesh.SetTangents(tangents); mesh.boneWeights = boneweights.ToArray(); mesh.bindposes = bindPoses; mesh.SetTriangles(new int [] { 0, 1, 2 }, 0); GameObject obj = new GameObject(Path.GetFileNameWithoutExtension(assetName) + $@"_{index}"); obj.AddComponent <SkinnedMeshRenderer>(); obj.GetComponent <SkinnedMeshRenderer>().bones = bones; obj.GetComponent <SkinnedMeshRenderer>().sharedMesh = mesh; obj.transform.parent = meshesObj.transform; AssetDatabase.CreateAsset(mesh, assetName + $@"/{Path.GetFileNameWithoutExtension(assetName)}_{index}.mesh"); } root.AddComponent <FlverMesh>(); root.GetComponent <FlverMesh>().Link = assetLink; AssetDatabase.CreateAsset(assetLink, assetName + ".asset"); AssetDatabase.SaveAssets(); PrefabUtility.SaveAsPrefabAsset(root, assetName + ".prefab"); Object.DestroyImmediate(root); }