public Model(FLVER flver) { Submeshes = new List <FlverSubmeshRenderer>(); var subBoundsPoints = new List <Vector3>(); foreach (var submesh in flver.Meshes) { var smm = new FlverSubmeshRenderer(flver, submesh); Submeshes.Add(smm); subBoundsPoints.Add(smm.Bounds.Min); subBoundsPoints.Add(smm.Bounds.Max); } //DEBUG// //Console.WriteLine($"{flver.Meshes[0].DefaultBoneIndex}"); //Console.WriteLine(); //Console.WriteLine(); //foreach (var mat in flver.Materials) //{ // Console.WriteLine($"{mat.Name}: {mat.MTD}"); //} ///////// if (Submeshes.Count == 0) { Bounds = new BoundingBox(); IsVisible = false; } else { Bounds = BoundingBox.CreateFromPoints(subBoundsPoints); } }
private void RegisterFLVER(int ffxid, FLVER flver) { if (!FFXs.ContainsKey(ffxid)) { FFXs.Add(ffxid, new FFXData()); } FFXs[ffxid].Model = flver; }
public Model(FLVER flver) { Type = ModelType.ModelTypeFlver; Submeshes = new List <FlverSubmeshRenderer>(); var subBoundsPoints = new List <Vector3>(); foreach (var submesh in flver.Meshes) { // Blacklist some materials that don't have good shaders and just make the viewer look like a mess var mtd = InterrootLoader.GetMTD(Path.GetFileName(flver.Materials[submesh.MaterialIndex].MTD)); if (mtd != null) { if (mtd.ShaderPath.Contains("FRPG_Water_Env")) { continue; } if (mtd.ShaderPath.Contains("FRPG_Water_Reflect.spx")) { continue; } } var smm = new FlverSubmeshRenderer(this, flver, submesh); Submeshes.Add(smm); subBoundsPoints.Add(smm.Bounds.Min); subBoundsPoints.Add(smm.Bounds.Max); } //DEBUG// //Console.WriteLine($"{flver.Meshes[0].DefaultBoneIndex}"); //Console.WriteLine(); //Console.WriteLine(); //foreach (var mat in flver.Materials) //{ // Console.WriteLine($"{mat.Name}: {mat.MTD}"); //} ///////// if (Submeshes.Count == 0) { Bounds = new BoundingBox(); IsVisible = false; } else { Bounds = BoundingBox.CreateFromPoints(subBoundsPoints); } }
private void SetBoneBoundingBox(FLVER f, FlverBone b) { var bb = GetBoundingBox(GetVerticesParentedToBone(f, b).Select(v => (Vector3)v.Position).ToList()); if (bb.Max.LengthSquared() != 0 || bb.Min.LengthSquared() != 0) { var matrix = GetParentBoneMatrix(b); b.BoundingBoxMin = Vector3.Transform(bb.Min, Matrix.Invert(matrix)); b.BoundingBoxMax = Vector3.Transform(bb.Max, Matrix.Invert(matrix)); } else { b.BoundingBoxMin = null; b.BoundingBoxMax = null; } }
private List <FlverVertex> GetVerticesParentedToBone(FLVER f, FlverBone b) { var result = new List <FlverVertex>(); foreach (var sm in f.Submeshes) { foreach (var v in sm.Vertices) { var bones = v.BoneIndices.GetBones(); if (bones.Contains(b)) { result.Add(v); } } } return(result); }
public void FixAllBoundingBoxes(FLVER f) { foreach (var b in f.Bones) { SetBoneBoundingBox(f, b); if (b.Name == "Dummy") { b.Name = "dymmy"; } else if (b.Name == "SFX") { b.Name = "SFX用"; } } var submeshBBs = new List <BoundingBox>(); foreach (var sm in f.Submeshes) { var bb = GetBoundingBox(sm.Vertices.Select(v => (Vector3)v.Position).ToList()); if (bb.Max.LengthSquared() != 0 || bb.Min.LengthSquared() != 0) { submeshBBs.Add(bb); } } if (submeshBBs.Count > 0) { var finalBB = submeshBBs[0]; for (int i = 1; i < submeshBBs.Count; i++) { finalBB = BoundingBox.CreateMerged(finalBB, submeshBBs[i]); } f.Header.BoundingBoxMin = finalBB.Min; f.Header.BoundingBoxMax = finalBB.Max; } else { f.Header.BoundingBoxMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); f.Header.BoundingBoxMax = new Vector3(float.MinValue, float.MinValue, float.MinValue); } }
static public void ImportFlver(DarkSoulsTools.GameType gameType, string path, string assetName, string texturePath = null) { FLVER flver; FLVERAssetLink link = ScriptableObject.CreateInstance <FLVERAssetLink>(); if (path.Contains(".mapbnd")) { BND4 bnd = BND4.Read(path); link.Type = FLVERAssetLink.ContainerType.Mapbnd; link.ArchivePath = path; link.FlverPath = bnd.Files[0].Name; flver = FLVER.Read(bnd.Files[0].Bytes); } else { link.Type = FLVERAssetLink.ContainerType.None; link.FlverPath = path; flver = FLVER.Read(path); } ImportFlver(flver, link, gameType, assetName, texturePath); }
void LoadFLVER(string path, FLVER f) { ClearCurrentShit(); FlverPath = path; Flver = f; CurrentMaterialIndex = -1; CurrentGXItemList.Clear(); CurrentMaterial = null; CurrentMapList = null; ListViewFlverMaterials.Items.Clear(); int i = 0; foreach (var m in f.Materials) { ListViewFlverMaterials.Items.Add(new Label() { Content = $"[{i++}] {m.Name}" }); } TabGXItems.IsEnabled = (Flver.Header.Version >= 0x20010); SetIsEverythingDisabled(true); }
static void ExportModel(MenuCommand menuCommand) { if (Selection.activeObject == null) { return; } var assetPath = AssetDatabase.GetAssetPath(Selection.activeObject); if (!assetPath.ToUpper().EndsWith(".FBX")) { EditorUtility.DisplayDialog("Invalid asset", "Please select an fbx asset", "Ok"); } // Load the FBX as a prefab //GameObject obj = PrefabUtility.LoadPrefabContents(assetPath); GameObject obj = AssetDatabase.LoadAssetAtPath <GameObject>(assetPath); // Go through everything and strip the prefixes fbx exporters love to add Stack <GameObject> gameObjects = new Stack <GameObject>(); GameObject bonesRoot = null; GameObject meshesRoot = null; gameObjects.Push(obj); while (gameObjects.Count > 0) { var o = gameObjects.Pop(); o.name = o.name.Split(':').Last(); if (o.name == "Bones") { bonesRoot = o; } if (o.name == "Meshes") { meshesRoot = o; } for (int i = 0; i < o.transform.childCount; i++) { gameObjects.Push(o.transform.GetChild(i).gameObject); } } // Load the source c0000 and target flvers /*var sourceBnd = BND4.Read($@"{DarkSoulsTools.Interroot}\chr\c0000.chrbnd.dcx"); * var sourceFlver = FLVER.Read(sourceBnd.Files.Where(x => x.Name.ToUpper().EndsWith(".FLVER")).First().Bytes); * var targetBnd = BND4.Read($@"{DarkSoulsTools.Interroot}\parts\lg_m_9000.partsbnd.dcx"); * var targetFlver = FLVER.Read(targetBnd.Files.Where(x => x.Name.ToUpper().EndsWith(".FLVER")).First().Bytes);*/ var sourceBnd = BND4.Read($@"{DarkSoulsTools.Interroot}\chr\c4033.chrbnd.dcx"); var sourceFlver = FLVER.Read(sourceBnd.Files.Where(x => x.Name.ToUpper().EndsWith(".FLVER")).First().Bytes); var targetBnd = BND4.Read($@"{DarkSoulsTools.Interroot}\chr\c4033.chrbnd.dcx"); var targetFlver = FLVER.Read(targetBnd.Files.Where(x => x.Name.ToUpper().EndsWith(".FLVER")).First().Bytes); // Build a bone reindexing table Dictionary <string, int> SourceBoneTable = new Dictionary <string, int>(); for (int i = 0; i < sourceFlver.Bones.Count; i++) { if (!SourceBoneTable.ContainsKey(sourceFlver.Bones[i].Name)) { SourceBoneTable.Add(sourceFlver.Bones[i].Name, i); } } if (meshesRoot == null) { throw new Exception("Could not find Meshes group for this FBX"); } if (bonesRoot == null) { throw new Exception("Could not find Bones group for this FBX"); } //sourceFlver.Bones.Add(targetFlver.Bones[29]); var templateMesh = targetFlver.Meshes.First(); targetFlver.Bones = sourceFlver.Bones; targetFlver.Meshes.Clear(); //targetFlver.SekiroUnk = sourceFlver.SekiroUnk; for (var meshIdx = 0; meshIdx < meshesRoot.transform.childCount; meshIdx++) { // Get the mesh object var meshObj = meshesRoot.transform.GetChild(meshIdx).gameObject; // Get the skin and mesh var meshSkin = meshObj.GetComponent <SkinnedMeshRenderer>(); var bones = meshSkin.bones; var mesh = meshSkin.sharedMesh; // Remap table to recover source bone indices var boneRemap = new int[bones.Length]; for (int i = 0; i < bones.Length; i++) { var name = bones[i].gameObject.name; if (SourceBoneTable.ContainsKey(name)) { boneRemap[i] = SourceBoneTable[name]; } else { boneRemap[i] = 0; } } // Build the submesh's bone table HashSet <int> usedBones = new HashSet <int>(); foreach (var weight in mesh.boneWeights) { if (weight.boneIndex0 >= 0) { usedBones.Add(boneRemap[weight.boneIndex0]); } if (weight.boneIndex1 >= 0) { usedBones.Add(boneRemap[weight.boneIndex1]); } if (weight.boneIndex2 >= 0) { usedBones.Add(boneRemap[weight.boneIndex2]); } if (weight.boneIndex3 >= 0) { usedBones.Add(boneRemap[weight.boneIndex3]); } } // Bad hack for (int i = 0; i < targetFlver.Bones.Count(); i++) { usedBones.Add(i); } var submeshBones = usedBones.OrderBy(x => x).ToArray(); var meshToSubmeshBone = new Dictionary <int, int>(); for (int i = 0; i < submeshBones.Count(); i++) { meshToSubmeshBone.Add(submeshBones[i], i); } // Finally port the mesh to the target //var fmesh = targetFlver.Meshes[0]; var fmesh = new FLVER.Mesh(templateMesh); fmesh.BoneIndices = sourceFlver.Meshes[0].BoneIndices; //submeshBones.ToList(); var min = mesh.bounds.min; var max = mesh.bounds.max; //fmesh.BoundingBoxMax = sourceFlver.Header.BoundingBoxMax; //fmesh.BoundingBoxMin = new System.Numerics.Vector3(max.x*100, max.y*100, max.z*100); //fmesh.BoundingBoxMin = sourceFlver.Header.BoundingBoxMin; //fmesh.MaterialIndex = 0; //targetFlver.Header.BoundingBoxMin = sourceFlver.Header.BoundingBoxMin; //targetFlver.Header.BoundingBoxMax = sourceFlver.Header.BoundingBoxMax; /*foreach (var b in usedBones) * { * targetFlver.Bones[b].Unk3C = 8; * }*/ foreach (var b in targetFlver.Bones) { if (b.Unk3C == 2) { b.Unk3C = 8; } } //targetFlver.Bones[140].Unk3C = 4; //targetFlver.Bones[140].Name = "LG_M_9000"; // Port vertices fmesh.Vertices.Clear(); fmesh.Vertices.Capacity = mesh.vertexCount; var mverts = mesh.vertices; var mnorms = mesh.normals; var mtangs = mesh.tangents; var muvs = mesh.uv; var mbones = mesh.boneWeights; for (int i = 0; i < mesh.vertexCount; i++) { var vert = new FLVER.Vertex(); var pos = mverts[i]; vert.Positions.Add(new System.Numerics.Vector3(pos.x, pos.y, pos.z)); var normal = mnorms[i]; vert.Normals.Add(new System.Numerics.Vector4(-normal.x, -normal.y, -normal.z, -1.0f)); var tangent = mtangs[i]; vert.Tangents.Add(new System.Numerics.Vector4(-tangent.x, -tangent.y, -tangent.z, -tangent.w)); vert.Tangents.Add(new System.Numerics.Vector4(-tangent.x, -tangent.y, -tangent.z, -tangent.w)); var color = new Color32(0xFF, 0xFF, 0x00, 0xFF); //mesh.colors32[i]; vert.Colors.Add(new FLVER.Vertex.Color(color.a, color.r, color.g, color.b)); /*vert.UVs.Add(new System.Numerics.Vector3(0.0f, 0.0f, 0.0f)); * vert.UVs.Add(new System.Numerics.Vector3(0.0f, 0.0f, 0.0f)); * vert.UVs.Add(new System.Numerics.Vector3(0.0f, 0.0f, 0.0f)); * vert.UVs.Add(new System.Numerics.Vector3(0.0f, 0.0f, 0.0f));*/ var uv = muvs[i]; vert.UVs.Add(new System.Numerics.Vector3(uv.x, 1.0f - uv.y, 0.0f)); vert.UVs.Add(new System.Numerics.Vector3(uv.x, 1.0f - uv.y, 0.0f)); vert.UVs.Add(new System.Numerics.Vector3(uv.x, 1.0f - uv.y, 0.0f)); vert.UVs.Add(new System.Numerics.Vector3(uv.x, 1.0f - uv.y, 0.0f)); vert.BoneIndices = new int[4]; vert.BoneWeights = new float[4]; var bone = mbones[i]; //vert.Tangents.Add(new System.Numerics.Vector4(bone.weight0, bone.weight1, bone.weight2, bone.weight3)); vert.BoneWeights[0] = bone.weight0; vert.BoneWeights[1] = bone.weight1; vert.BoneWeights[2] = bone.weight2; vert.BoneWeights[3] = bone.weight3; vert.BoneIndices[0] = meshToSubmeshBone[boneRemap[bone.boneIndex0]]; vert.BoneIndices[1] = meshToSubmeshBone[boneRemap[bone.boneIndex1]]; vert.BoneIndices[2] = meshToSubmeshBone[boneRemap[bone.boneIndex2]]; vert.BoneIndices[3] = meshToSubmeshBone[boneRemap[bone.boneIndex3]]; for (int b = 0; b < 3; b++) { if (vert.BoneIndices[b] == -1) { vert.BoneIndices[b] = 0; } } fmesh.Vertices.Add(vert); } // Port faceset var fset = new FLVER.FaceSet(fmesh.FaceSets[0]); var tris = new uint[mesh.triangles.Count()]; var mtris = mesh.triangles; for (int i = 0; i < tris.Count(); i++) { tris[i] = ((uint)mtris[i]); } fset.Vertices = tris; fset.CullBackfaces = false; fset.TriangleStrip = false; fmesh.FaceSets.Clear(); var fset2 = new FLVER.FaceSet(FLVER.FaceSet.FSFlags.LodLevel1, false, false, fset.Unk06, fset.Unk07, fset.IndexSize, fset.Vertices); var fset3 = new FLVER.FaceSet(FLVER.FaceSet.FSFlags.LodLevel2, false, false, fset.Unk06, fset.Unk07, fset.IndexSize, fset.Vertices); var fset4 = new FLVER.FaceSet(FLVER.FaceSet.FSFlags.Unk80000000, false, false, fset.Unk06, fset.Unk07, fset.IndexSize, fset.Vertices); fmesh.FaceSets.Add(fset); fmesh.FaceSets.Add(fset2); fmesh.FaceSets.Add(fset3); fmesh.FaceSets.Add(fset4); fmesh.MaterialIndex = meshIdx; //fmesh.MaterialIndex = 0; targetFlver.Meshes.Add(fmesh); //targetFlver.BufferLayouts } //targetFlver.Materials[0].MTD = $@"M[ARSN].mtd"; targetFlver.Materials[0].MTD = "C[ARSN].mtd"; targetFlver.Materials[0].Textures[0].Type = "g_DiffuseTexture"; targetFlver.Materials[0].Textures[0].Path = "c5020_shrek_a.dds"; targetFlver.Materials[0].Textures[1].Path = ""; targetFlver.Materials[0].Textures[2].Path = ""; targetFlver.Materials[0].Textures[3].Type = "g_BumpmapTexture"; targetFlver.Materials[0].Textures[3].Path = "SYSTEX_DummyNormal.tga"; targetFlver.Materials.Add(new FLVER.Material("shrek2", "C[ARSN].mtd", targetFlver.Materials[0].Flags, targetFlver.Materials[0].GXBytes)); targetFlver.Materials[1].MTD = "C[ARSN].mtd"; targetFlver.Materials[1].Textures.Add(new FLVER.Texture(targetFlver.Materials[0].Textures[0])); targetFlver.Materials[1].Textures.Add(new FLVER.Texture(targetFlver.Materials[0].Textures[1])); targetFlver.Materials[1].Textures.Add(new FLVER.Texture(targetFlver.Materials[0].Textures[2])); targetFlver.Materials[1].Textures.Add(new FLVER.Texture(targetFlver.Materials[0].Textures[3])); targetFlver.Materials[1].Textures[0].Type = "g_DiffuseTexture"; targetFlver.Materials[1].Textures[0].Path = "c5020_shrekshirt_a.dds"; targetFlver.Materials[1].Textures[1].Path = ""; targetFlver.Materials[1].Textures[2].Path = ""; targetFlver.Materials[1].Textures[3].Type = "g_BumpmapTexture"; targetFlver.Materials[1].Textures[3].Path = "SYSTEX_DummyNormal.tga"; // Finally save targetBnd.Files.Where(x => x.Name.ToUpper().EndsWith(".FLVER")).First().Bytes = targetFlver.Write(); //targetBnd.Write($@"{DarkSoulsTools.ModProjectDirectory}\parts\lg_m_9000.partsbnd.dcx", DCX.Type.SekiroDFLT); targetBnd.Write($@"{DarkSoulsTools.ModProjectDirectory}\chr\c4033.chrbnd.dcx", DCX.Type.DarkSouls3); }
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); }
public void SolveOrientation(FLVER flver, bool solveBones) { foreach (var flverMesh in flver.Submeshes) { for (int i = 0; i < flverMesh.Vertices.Count; i++) { var m = Matrix.Identity * Matrix.CreateRotationY(Importer.SceneRotation.Y) * Matrix.CreateRotationZ(Importer.SceneRotation.Z) * Matrix.CreateRotationX(Importer.SceneRotation.X) ; flverMesh.Vertices[i].Position = Vector3.Transform(flverMesh.Vertices[i].Position, m); flverMesh.Vertices[i].Normal = Vector3.Normalize(Vector3.Transform((Vector3)flverMesh.Vertices[i].Normal, m)); var rotBitangentVec3 = Vector3.Transform((Vector3)flverMesh.Vertices[i].BiTangent, m); flverMesh.Vertices[i].BiTangent = new Vector4(rotBitangentVec3.X, rotBitangentVec3.Y, rotBitangentVec3.Z, flverMesh.Vertices[i].BiTangent.W); } } //Matrix GetBoneMatrix(FlverBone b) //{ // return Matrix.CreateScale(b.Scale) // * Matrix.CreateRotationX(b.EulerRadian.X) // * Matrix.CreateRotationZ(b.EulerRadian.Z) // * Matrix.CreateRotationY(b.EulerRadian.Y) // * Matrix.CreateTranslation(b.Translation) // ; //} //void ApplyBoneMatrix(FlverBone b, Matrix m) //{ // Matrix orig = GetBoneMatrix(b); // orig *= m; // b.Translation = orig.Translation; // b.Scale = orig.Scale; // b.EulerRadian = Util.GetFlverEulerFromQuaternion(orig.Rotation); //} //bool anyAdjusted = false; //do //{ //anyAdjusted = false; //foreach (var b in flver.Bones) //{ // b.EulerRadian = Vector3.Zero; // //if (b.ParentIndex == -1) // //{ // // b.EulerRadian = Vector3.Zero; // // //b.Scale = Vector3.One; // // //b.Translation = Vector3.Zero; // //} //} //ACTUALY WORKS: if (solveBones) { for (int b = 0; b < flver.Bones.Count; b++) { //flver.Bones[b].Scale = Vector3.One; //if (flver.Bones[b].Scale.X < 0) //{ // flver.Bones[b].Scale.X *= -1; // flver.Bones[b].EulerRadian.Y += MathHelper.Pi; // foreach (var dmy in flver.Dummies.Where(dm => dm.ParentBoneIndex == b)) // { // dmy.Position *= new Vector3(-1, 1, 1); // } //} //if (flver.Bones[b].Scale.Y < 0) //{ // flver.Bones[b].Scale.Y *= -1; // flver.Bones[b].EulerRadian.X += MathHelper.Pi; // foreach (var dmy in flver.Dummies.Where(dm => dm.ParentBoneIndex == b)) // { // dmy.Position *= new Vector3(1, -1, 1); // } //} //Do this only for parent bones, cuz child bones could be real bones like on a whip...? //if (Importer.OutputType == DSFBXOutputType.Weapon && flver.Bones[b].ParentIndex == -1) //{ // var oldBoneRotMatrix = Matrix.CreateRotationY(flver.Bones[b].EulerRadian.Y) // * Matrix.CreateRotationZ(flver.Bones[b].EulerRadian.Z) // * Matrix.CreateRotationX(flver.Bones[b].EulerRadian.X); // foreach (var dmy in flver.Dummies.Where(d => d.ParentBoneIndex == b)) // { // dmy.Position = Vector3.Transform(dmy.Position, Matrix.Invert(oldBoneRotMatrix) * Matrix.CreateRotationX(MathHelper.Pi)); // } // flver.Bones[b].EulerRadian = Vector3.Zero; // flver.Bones[b].Scale = Vector3.One; //} } } if (Importer.RotateNormalsBackward || Importer.ConvertNormalsAxis) { foreach (var sm in flver.Submeshes) { foreach (var vert in sm.Vertices) { if (vert.Normal != null) { if (Importer.ConvertNormalsAxis) { var x = vert.Normal.X; var y = vert.Normal.Y; var z = vert.Normal.Z; vert.Normal = new Vector3(x, -z, y); } if (Importer.RotateNormalsBackward) { vert.Normal = Vector3.Transform((Vector3)vert.Normal, Matrix.CreateRotationY(MathHelper.Pi)); } } } } } //foreach (var m in flver.Submeshes) //{ // foreach (var v in m.Vertices) // { // var norm = (Vector3)v.Normal; // var tan = (Vector3)v.BiTangent; // v.BiTangent = new Vector4(Vector3.Cross(norm, tan) * v.BiTangent.W, v.BiTangent.W); // } //} //} //while (anyAdjusted); //if (solveBones) //{ // foreach (var bone in flver.Bones.Where(b => b.ParentIndex == -1)) // { // var origMatrix = Matrix.CreateTranslation(bone.Translation) // * Matrix.CreateScale(bone.Scale); // var m = Matrix.CreateRotationZ(-MathHelper.PiOver2) // //* Matrix.CreateRotationX(MathHelper.Pi) // ; // if ((origMatrix * m).Decompose(out var scale, out _, out var trans)) // { // bone.Translation = trans; // bone.Scale = scale; // } // bone.EulerRadian.Z += -MathHelper.PiOver2; // //bone.EulerRadian.X += MathHelper.Pi; // } //} foreach (var dmy in flver.Dummies) { var m = Matrix.Identity; bool wasAnyRotationAppliedFatcat = false; if (Importer.SceneRotation.Y != 0) { m *= Matrix.CreateRotationY(Importer.SceneRotation.Y); wasAnyRotationAppliedFatcat = true; } if (Importer.SceneRotation.Z != 0) { m *= Matrix.CreateRotationZ(Importer.SceneRotation.Z); wasAnyRotationAppliedFatcat = true; } if (Importer.SceneRotation.X != 0) { m *= Matrix.CreateRotationX(Importer.SceneRotation.X); wasAnyRotationAppliedFatcat = true; } if (wasAnyRotationAppliedFatcat) { dmy.Position = Vector3.Transform(dmy.Position, m); } } }
public int SolveBone(FLVER flver, NodeContent fbx, NodeContent boneContent, int parentIndex) { var newBone = new FlverBone(flver); newBone.Name = boneContent.Name; //if (parentIndex == -1 && (boneContent.Name.ToUpper().StartsWith("DUMMY") || boneContent.Name.ToUpper().StartsWith("DYMMY"))) //{ // newBone.Name = "dymmy"; //} //else if (parentIndex == -1 && boneContent.Name.ToUpper().StartsWith("SFX")) //{ // newBone.Name = "SFX用"; //} FbxPipeline.Matrix boneTrans_Xna = boneContent.Transform;// * FbxPipeline.Matrix.CreateScale(Importer.FinalScaleMultiplier); //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationZ(-MathHelper.PiOver2); //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationY(-MathHelper.PiOver2); //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationY(MathHelper.Pi); //if (boneContent.Parent != null && boneContent.Parent != fbx) //{ // boneTrans_Xna *= FbxPipeline.Matrix.Invert(boneContent.Parent.AbsoluteTransform); // //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationZ(MathHelper.Pi); //} string parentName = boneContent.Parent?.Name; bool isMainRootBone = (parentName == null || parentName == "RootNode"); //bool isRegularChildBone = false; //var parentLevel1 = boneContent.Parent; //if (parentLevel1 != null) //{ // var parentLevel2 = parentLevel1.Parent; // if (parentLevel2 != null) // { // if (parentLevel2.Name.Trim().ToUpper() == "ROOT") // { // //boneTrans_Xna *= FbxPipeline.Matrix.Invert(boneContent.Parent.AbsoluteTransform); // //boneTrans_Xna = boneContent.AbsoluteTransform; // //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationX(MathHelper.PiOver2); // //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationY(MathHelper.PiOver2); // //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationZ(MathHelper.PiOver2); // //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationX(MathHelper.PiOver2); // //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationZ(MathHelper.PiOver2); // isRegularChildBone = true; // //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationX(-MathHelper.PiOver4); // } // } //} //if (isMainRootBone) //{ // boneTrans_Xna = boneContent.AbsoluteTransform; //} //if (isRegularChildBone) //{ // boneTrans_Xna = boneContent.AbsoluteTransform; //} //else if (isMainRootBone || boneContent.Name.ToUpper() == "ROOT") //{ // //boneTrans_Xna = FbxPipeline.Matrix.Identity; //} //if (boneContent.Name.ToUpper() == "ROOT" || isMainRootBone) //{ // boneTrans_Xna *= FbxPipeline.Matrix.CreateScale(1, 1, -1); //} //if (!isMainRootBone) //{ // boneTrans_Xna *= FbxPipeline.Matrix.Invert(boneContent.Parent.AbsoluteTransform); //} //boneTrans_Xna *= FbxPipeline.Matrix.Invert(boneContent.Parent.Transform); //Matrix boneTrans_MonoGame = new Matrix(boneTrans_Xna.M11, boneTrans_Xna.M12, boneTrans_Xna.M13, boneTrans_Xna.M14, // boneTrans_Xna.M21, boneTrans_Xna.M22, boneTrans_Xna.M23, boneTrans_Xna.M24, // boneTrans_Xna.M31, boneTrans_Xna.M32, boneTrans_Xna.M33, boneTrans_Xna.M34, // boneTrans_Xna.M41, boneTrans_Xna.M42, boneTrans_Xna.M43, boneTrans_Xna.M44); //boneTrans_MonoGame *= Matrix.CreateScale(Importer.FinalScaleMultiplier); //bool boneScaleWarning = false; //newBone.Scale = boneTrans_MonoGame.Scale;// / Importer.FinalScaleMultiplier; //if (isMainRootBone) //{ // newBone.Scale.Y *= -1; //} //newBone.Scale = new FlverVector3(Math.Abs(newBone.Scale.X), Math.Abs(newBone.Scale.Y), Math.Abs(newBone.Scale.Z)); //Quaternion q = Quaternion.CreateFromRotationMatrix(boneTrans_MonoGame); //boneTrans_Xna *= FbxPipeline.Matrix.CreateRotationY(MathHelper.Pi); if (boneTrans_Xna.Decompose(out FbxPipeline.Vector3 scale, out FbxPipeline.Quaternion rotation, out FbxPipeline.Vector3 translation)) { newBone.Scale = new Vector3(scale.X, scale.Y, scale.Z); newBone.EulerRadian = Util.GetFlverEulerFromQuaternion_Bone(new Quaternion(-rotation.X, rotation.Y, rotation.Z, -rotation.W)) * new Vector3(1, 1, 1); //newBone.EulerRadian.X = MathHelper.WrapAngle(newBone.EulerRadian.X + MathHelper.Pi); newBone.Translation = new Vector3(-translation.X, translation.Y, translation.Z) * Importer.FinalScaleMultiplier; } else { throw new Exception("FBX Bone Content Transform Matrix " + "-> Decompose(out Vector3 scale, " + "out Quaternion rotation, out Vector3 translation) " + ">>FAILED<<"); } newBone.BoundingBoxMax = Vector3.One * 0.1f; newBone.BoundingBoxMin = Vector3.One * -0.1f; //var extractedBoneEuler = Util.GetFlverEulerFromQuaternion_Bone(boneTrans_MonoGame.Rotation); //newBone.EulerRadian.X = MathHelper.WrapAngle(extractedBoneEuler.X + 0); //newBone.EulerRadian.Y = MathHelper.WrapAngle(extractedBoneEuler.Y + 0); //newBone.EulerRadian.Z = MathHelper.WrapAngle(extractedBoneEuler.Z + 0); //newBone.EulerRadian = new Vector3(newBone.EulerRadian.X, newBone.EulerRadian.Z, newBone.EulerRadian.Y); //var extractedBoneTrans = boneTrans_MonoGame.Translation * Importer.FinalScaleMultiplier; //newBone.Translation = new Vector3(extractedBoneTrans.X, extractedBoneTrans.Y, extractedBoneTrans.Z); //if (boneContent.Name.ToUpper() == "MASTER") //{ // //newBone.Translation *= new Vector3(1, -1, 1); // //newBone.EulerRadian.X = MathHelper.WrapAngle(newBone.EulerRadian.X + MathHelper.PiOver2); // //newBone.EulerRadian.Y = MathHelper.WrapAngle(newBone.EulerRadian.Y + MathHelper.PiOver2); // //newBone.EulerRadian.Z = MathHelper.WrapAngle(newBone.EulerRadian.Z + MathHelper.PiOver2); //} //else //{ //} //if (boneContent.Parent != null) //{ // newBone.Translation *= new Vector3(1, -1, 1); //} //newBone.Translation *= new Vector3(-1, 1, 1); //if (newBone.Scale.X < 0) //{ // newBone.Scale *= new Vector3(-1, 1, 1); // //newBone.EulerRadian *= new Vector3(1, -1, 1); // //newBone.Translation *= new Vector3(1, -1, -1); //} //newBone.EulerRadian = Util.GetEuler(boneTrans); //newBone.EulerRadian.Y -= MathHelper.PiOver2; if (newBone.Name.ToUpper().StartsWith("DUMMY") && newBone.Name.Contains("<") && newBone.Name.Contains(">")) { var dmy = new FlverDummy(flver); dmy.ParentBoneIndex = (short)parentIndex; //var dmyParentEuler = Util.GetEuler(boneContent.Parent.Transform); var parentBoneTrans = boneContent.Parent.AbsoluteTransform; Matrix parentBoneTrans_MonoGame = new Matrix(parentBoneTrans.M11, parentBoneTrans.M12, parentBoneTrans.M13, parentBoneTrans.M14, parentBoneTrans.M21, parentBoneTrans.M22, parentBoneTrans.M23, parentBoneTrans.M24, parentBoneTrans.M31, parentBoneTrans.M32, parentBoneTrans.M33, parentBoneTrans.M34, parentBoneTrans.M41, parentBoneTrans.M42, parentBoneTrans.M43, parentBoneTrans.M44); dmy.Position = Vector3.Transform(new Vector3(-boneContent.Transform.Translation.X, boneContent.Transform.Translation.Y, boneContent.Transform.Translation.Z)/*, * * //Matrix.CreateRotationY(dmyParentEuler.Y) * //* Matrix.CreateRotationZ(dmyParentEuler.Z) * //* Matrix.CreateRotationX(dmyParentEuler.X) * * )*/ * Importer.FinalScaleMultiplier , //Matrix.Invert(Matrix.CreateScale(parentBoneTrans_MonoGame.Scale.X, parentBoneTrans_MonoGame.Scale.Y, parentBoneTrans_MonoGame.Scale.Z)) Matrix.Identity ); var thisScale = new FbxPipeline.Vector3(newBone.Scale.X, newBone.Scale.Y, newBone.Scale.Z); var upPoint = FbxPipeline.Vector3.Normalize(boneContent.AbsoluteTransform.Forward) * 0.1f * thisScale; var forwardPoint = FbxPipeline.Vector3.Normalize(boneContent.AbsoluteTransform.Up) * 0.05f * thisScale; dmy.Row2 = new Vector3(upPoint.X, upPoint.Y, upPoint.Z); dmy.Row3 = new Vector3(forwardPoint.X, forwardPoint.Y, forwardPoint.Z); var dmyTypeID = int.Parse(Util.GetAngleBracketContents(boneContent.Name)); dmy.TypeID = (short)dmyTypeID; flver.Dummies.Add(dmy); foreach (var c in boneContent.Children) { if (c is NodeContent n) { Importer.PrintWarning($"Non-dummy node '{n.Name}' is parented " + $"to a dummy node ('{boneContent.Name}') and will be ignored " + $"due to Dark Souls engine limitations. To include the node, " + $"parent it to something that is not a dummy node."); } } return(-1); } //else if ((newBone.Name.StartsWith("[") && newBone.Name.EndsWith("]"))) //{ // newBone.Name = newBone.Name.Substring(1, newBone.Name.Length - 2); // newBone.IsNub = true; //} else if (newBone.Name.ToUpper().EndsWith("NUB")) { newBone.IsNub = true; } //float transX = boneContent.Transform.Translation.X; //float transY = boneContent.Transform.Translation.Y; //float transZ = boneContent.Transform.Translation.Z; //if (boneScaleWarning) //{ // Importer.PrintWarning($"Bone '{boneContent.Name}' has a scale of <{scale.X}, {scale.Y}, {scale.Z}>. " + // $"Any scale different than <1.0, 1.0, 1.0> might cause the game to " + // $"try to \"correct\" the scale and break something."); //} newBone.ParentIndex = (short)parentIndex; flver.Bones.Add(newBone); int myIndex = flver.Bones.Count - 1; var myChildrenIndices = new List <int>(); foreach (var childNode in boneContent.Children) { if (childNode is NodeContent childBone) { myChildrenIndices.Add(SolveBone(flver, fbx, childBone, myIndex)); } } if (myChildrenIndices.Count > 0) { newBone.FirstChildIndex = (short)myChildrenIndices[0]; for (int i = 0; i < myChildrenIndices.Count; i++) { if (myChildrenIndices[i] > -1) { var currentChild = flver.Bones[myChildrenIndices[i]]; if (i > 0) { currentChild.PreviousSiblingIndex = (short)myChildrenIndices[i - 1]; } else { currentChild.PreviousSiblingIndex = (short)-1; } if (i < myChildrenIndices.Count - 1) { currentChild.NextSiblingIndex = (short)myChildrenIndices[i + 1]; } else { currentChild.NextSiblingIndex = (short)-1; } } } } return(myIndex); }
public FlverSubmeshRenderer(Model parent, FLVER flvr, FLVER.Mesh mesh) { Parent = parent; var shortMaterialName = MiscUtil.GetFileNameWithoutDirectoryOrExtension(flvr.Materials[mesh.MaterialIndex].MTD); if (shortMaterialName.EndsWith("_Alp") || shortMaterialName.Contains("_Edge") || shortMaterialName.Contains("_Decal") || shortMaterialName.Contains("_Cloth") || shortMaterialName.Contains("_al") || shortMaterialName.Contains("BlendOpacity")) { DrawStep = GFXDrawStep.AlphaEdge; } else { DrawStep = GFXDrawStep.Opaque; } bool hasLightmap = false; foreach (var matParam in flvr.Materials[mesh.MaterialIndex].Textures) { var paramNameCheck = matParam.Type.ToUpper(); // DS3/BB if (paramNameCheck == "G_DIFFUSETEXTURE") { TexNameDiffuse = matParam.Path; } else if (paramNameCheck == "G_SPECULARTEXTURE") { TexNameSpecular = matParam.Path; } else if (paramNameCheck == "G_BUMPMAPTEXTURE") { TexNameNormal = matParam.Path; } else if (paramNameCheck == "G_DOLTEXTURE1") { TexNameDOL1 = matParam.Path; hasLightmap = true; } else if (paramNameCheck == "G_DOLTEXTURE2") { TexNameDOL2 = matParam.Path; } // DS1 params else if (paramNameCheck == "G_DIFFUSE") { TexNameDiffuse = matParam.Path; } else if (paramNameCheck == "G_SPECULAR") { TexNameSpecular = matParam.Path; } else if (paramNameCheck == "G_BUMPMAP") { TexNameNormal = matParam.Path; } else if (paramNameCheck == "G_LIGHTMAP") { TexNameDOL1 = matParam.Path; hasLightmap = true; } // Alternate material params that work as diffuse } // MTD lookup MTD mtd = InterrootLoader.GetMTD(flvr.Materials[mesh.MaterialIndex].MTD); var MeshVertices = new VertexPositionColorNormalTangentTexture[mesh.Vertices.Count]; for (int i = 0; i < mesh.Vertices.Count; i++) { var vert = mesh.Vertices[i]; MeshVertices[i] = new VertexPositionColorNormalTangentTexture(); MeshVertices[i].Position = new Vector3(vert.Position.X, vert.Position.Y, vert.Position.Z); if (vert.Normal != null && vert.Tangents != null && vert.Tangents.Count > 0) { MeshVertices[i].Normal = Vector3.Normalize(new Vector3(vert.Normal.X, vert.Normal.Y, vert.Normal.Z)); MeshVertices[i].Tangent = Vector3.Normalize(new Vector3(vert.Tangents[0].X, vert.Tangents[0].Y, vert.Tangents[0].Z)); MeshVertices[i].Binormal = Vector3.Cross(Vector3.Normalize(MeshVertices[i].Normal), Vector3.Normalize(MeshVertices[i].Tangent)) * vert.Tangents[0].W; } if (vert.UVs.Count > 0) { MeshVertices[i].TextureCoordinate = new Vector2(vert.UVs[0].X, vert.UVs[0].Y); if (vert.UVs.Count > 1 && hasLightmap) { if (mtd == null) { // Really stupid heuristic to determine light map UVs without reading mtd files or something if (vert.UVs.Count > 2 && flvr.Materials[mesh.MaterialIndex].Textures.Count > 11) { MeshVertices[i].TextureCoordinate2 = new Vector2(vert.UVs[2].X, vert.UVs[2].Y); } else { MeshVertices[i].TextureCoordinate2 = new Vector2(vert.UVs[1].X, vert.UVs[1].Y); } } else { // Better heuristic with MTDs int uvindex = mtd.Textures.Find(tex => tex.Type.ToUpper() == "G_LIGHTMAP" || tex.Type.ToUpper() == "G_DOLTEXTURE1").UVNumber; int uvoffset = 1; for (int j = 1; j < uvindex; j++) { if (!mtd.Textures.Any(t => (t.UVNumber == j))) { uvoffset++; } } uvindex -= uvoffset; if (vert.UVs.Count > uvindex) { MeshVertices[i].TextureCoordinate2 = new Vector2(vert.UVs[uvindex].X, vert.UVs[uvindex].Y); } else { MeshVertices[i].TextureCoordinate2 = new Vector2(vert.UVs[1].X, vert.UVs[1].Y); } } } else { MeshVertices[i].TextureCoordinate2 = Vector2.Zero; } } else { MeshVertices[i].TextureCoordinate = Vector2.Zero; MeshVertices[i].TextureCoordinate2 = Vector2.Zero; } } VertexCount = MeshVertices.Length; MeshFacesets = new List <FlverSubmeshRendererFaceSet>(); foreach (var faceset in mesh.FaceSets) { bool is32bit = faceset.IndexSize == 0x20; var newFaceSet = new FlverSubmeshRendererFaceSet() { BackfaceCulling = faceset.CullBackfaces, IsTriangleStrip = faceset.TriangleStrip, IndexBuffer = new IndexBuffer( GFX.Device, is32bit ? IndexElementSize.ThirtyTwoBits : IndexElementSize.SixteenBits, faceset.Vertices.Length, BufferUsage.WriteOnly), IndexCount = faceset.Vertices.Length, }; if (faceset.Flags == FLVER.FaceSet.FSFlags.LodLevel1) { newFaceSet.LOD = 1; HasNoLODs = false; } else if (faceset.Flags == FLVER.FaceSet.FSFlags.LodLevel2) { newFaceSet.LOD = 2; HasNoLODs = false; } if (is32bit) { newFaceSet.IndexBuffer.SetData(faceset.Vertices); } else { newFaceSet.IndexBuffer.SetData(faceset.Vertices.Select(x => (ushort)x).ToArray()); } MeshFacesets.Add(newFaceSet); } Bounds = BoundingBox.CreateFromPoints(MeshVertices.Select(x => x.Position)); VertBuffer = new VertexBuffer(GFX.Device, typeof(VertexPositionColorNormalTangentTexture), MeshVertices.Length, BufferUsage.WriteOnly); VertBuffer.SetData(MeshVertices); VertBufferBinding = new VertexBufferBinding(VertBuffer, 0, 0); TryToLoadTextures(); }
public static void ModelSwapModule() { System.Windows.Forms.OpenFileDialog openFileDialog1; openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); openFileDialog1.InitialDirectory = System.IO.Directory.GetCurrentDirectory(); openFileDialog1.Title = "Choose template seikiro model file."; //openFileDialog1.ShowDialog(); if (openFileDialog1.ShowDialog() == DialogResult.OK) { Console.WriteLine(openFileDialog1.FileName); //openFileDialog1. } else { return; } FLVER b = FLVER.Read(openFileDialog1.FileName); System.Windows.Forms.OpenFileDialog openFileDialog2 = new System.Windows.Forms.OpenFileDialog(); openFileDialog2.InitialDirectory = System.IO.Directory.GetCurrentDirectory(); openFileDialog2.Title = "Choose source DS/BB model file."; //openFileDialog1.ShowDialog(); if (openFileDialog2.ShowDialog() == DialogResult.OK) { Console.WriteLine(openFileDialog2.FileName); //openFileDialog1. } else { return; } FLVER src = FLVER.Read(openFileDialog2.FileName); Console.WriteLine(b.Header); Console.WriteLine("Seikiro unk is:" + b.SekiroUnk); Console.WriteLine("Material:"); foreach (FLVER.Material m in b.Materials) { Console.WriteLine(m.Name); } foreach (FLVER.Mesh m in b.Meshes) { Console.WriteLine("Mesh#" + m.MaterialIndex); } //* new //b.Header.BigEndian = src.Header.BigEndian; // //X: is not the sword axis!!! //Y: ++ means closer to the hand! //Unit: in meter(?) //For Moonlight sword -> threaded cane, Y+0.5f Form f = new Form(); Label l = new Label(); l.Text = "x,y,z offset? Y= weapon length axis,Y+=Closer to hand"; l.Size = new System.Drawing.Size(150, 15); l.Location = new System.Drawing.Point(10, 20); f.Controls.Add(l); TextBox t = new TextBox(); t.Size = new System.Drawing.Size(70, 15); t.Location = new System.Drawing.Point(10, 60); t.Text = "0"; f.Controls.Add(t); TextBox t2 = new TextBox(); t2.Size = new System.Drawing.Size(70, 15); t2.Location = new System.Drawing.Point(10, 100); t2.Text = "0"; f.Controls.Add(t2); TextBox t3 = new TextBox(); t3.Size = new System.Drawing.Size(70, 15); t3.Location = new System.Drawing.Point(10, 140); t3.Text = "0"; f.Controls.Add(t3); CheckBox cb1 = new CheckBox(); cb1.Size = new System.Drawing.Size(70, 15); cb1.Location = new System.Drawing.Point(10, 160); cb1.Text = "Copy Material"; f.Controls.Add(cb1); CheckBox cb2 = new CheckBox(); cb2.Size = new System.Drawing.Size(150, 15); cb2.Location = new System.Drawing.Point(10, 180); cb2.Text = "Copy Bones"; f.Controls.Add(cb2); CheckBox cb3 = new CheckBox(); cb3.Size = new System.Drawing.Size(150, 15); cb3.Location = new System.Drawing.Point(10, 200); cb3.Text = "Copy Dummy"; f.Controls.Add(cb3); CheckBox cb4 = new CheckBox(); cb4.Size = new System.Drawing.Size(350, 15); cb4.Location = new System.Drawing.Point(10, 220); cb4.Text = "All vertex weight to first bone"; f.Controls.Add(cb4); f.ShowDialog(); float x = float.Parse(t.Text); float y = float.Parse(t2.Text); float z = float.Parse(t3.Text); b.Meshes = src.Meshes; if (cb1.Checked) { b.Materials = src.Materials; } if (cb2.Checked) { b.Bones = src.Bones; } if (cb3.Checked) { b.Dummies = src.Dummies; } if (cb4.Checked) { for (int i = 0; i < b.Meshes.Count; i++) { b.Meshes[i].BoneIndices = new List <int>(); b.Meshes[i].BoneIndices.Add(0); b.Meshes[i].BoneIndices.Add(1); b.Meshes[i].DefaultBoneIndex = 1; foreach (FLVER.Vertex v in b.Meshes[i].Vertices) { for (int j = 0; j < v.Positions.Count; j++) { if (v.BoneWeights == null) { continue; } v.Positions[j] = new System.Numerics.Vector3(0, 0, 0); for (int k = 0; k < v.BoneWeights.Length; k++) { v.BoneWeights[k] = 0; v.BoneIndices[k] = 0; } v.BoneIndices[0] = 1; v.BoneWeights[0] = 1; } } //targetFlver.Meshes[i].Vertices = new List<FLVER.Vertex>(); } } foreach (FLVER.Mesh m in b.Meshes) { foreach (FLVER.Vertex v in m.Vertices) { for (int i = 0; i < v.Positions.Count; i++) { v.Positions[i] = new System.Numerics.Vector3(v.Positions[i].X + x, v.Positions[i].Y + y, v.Positions[i].Z + z); } } } b.Write(openFileDialog1.FileName + "n"); MessageBox.Show("Swap completed!", "Info"); //Console.WriteLine("End reading"); //Application.Exit(); }
/*public FlverSubmeshRenderer(FlverSubmesh f) * { * var shortMaterialName = MiscUtil.GetFileNameWithoutDirectoryOrExtension(f.Material.MTDName); * if (shortMaterialName.EndsWith("_Alp") || shortMaterialName.EndsWith("_Edge")) * { * DrawStep = GFXDrawStep.AlphaEdge; * } * else * { * DrawStep = GFXDrawStep.Opaque; * } * * foreach (var matParam in f.Material.Parameters) * { * if (matParam.Name.ToUpper() == "G_DIFFUSE") * TexNameDiffuse = matParam.Value; * else if (matParam.Name.ToUpper() == "G_SPECULAR") * TexNameSpecular = matParam.Value; * else if (matParam.Name.ToUpper() == "G_BUMPMAP") * TexNameNormal = matParam.Value; * } * * var MeshVertices = new VertexPositionColorNormalTangentTexture[f.Vertices.Count]; * for (int i = 0; i < f.Vertices.Count; i++) * { * var vert = f.Vertices[i]; * MeshVertices[i] = new VertexPositionColorNormalTangentTexture(); * * MeshVertices[i].Position = new Vector3(vert.Position.X, vert.Position.Y, vert.Position.Z); * * if (vert.Normal != null && vert.BiTangent != null) * { * MeshVertices[i].Normal = Vector3.Normalize(new Vector3(vert.Normal.X, vert.Normal.Y, vert.Normal.Z)); * MeshVertices[i].Tangent = Vector3.Normalize(new Vector3(vert.BiTangent.X, vert.BiTangent.Y, vert.BiTangent.Z)); * MeshVertices[i].Binormal = Vector3.Cross(Vector3.Normalize(MeshVertices[i].Normal), Vector3.Normalize(MeshVertices[i].Tangent)) * vert.BiTangent.W; * } * * if (vert.UVs.Count > 0) * { * MeshVertices[i].TextureCoordinate = vert.UVs[0]; * } * else * { * MeshVertices[i].TextureCoordinate = Vector2.Zero; * } * * // We set the mesh's vertex color to that of a selected mesh. * // The shader with lighting ignores this so it will only show * // up on the primitive shader, which is what is used to draw * // the currently highlighted map piece * MeshVertices[i].Color = Main.SELECTED_MESH_COLOR.ToVector4(); * } * * VertexCount = MeshVertices.Length; * * MeshFacesets = new List<FlverSubmeshRendererFaceSet>(); * * foreach (var faceset in f.FaceSets) * { * var newFaceSet = new FlverSubmeshRendererFaceSet() * { * BackfaceCulling = faceset.CullBackfaces, * IsTriangleStrip = faceset.IsTriangleStrip, * IndexBuffer = new IndexBuffer( * GFX.Device, * IndexElementSize.SixteenBits, * sizeof(short) * faceset.VertexIndices.Count, * BufferUsage.None), * IndexCount = faceset.VertexIndices.Count, * }; * * if (faceset.FlagsLOD1) * { * newFaceSet.LOD = (byte)1; * HasNoLODs = false; * } * else if (faceset.FlagsLOD2) * { * newFaceSet.LOD = (byte)2; * HasNoLODs = false; * } * * newFaceSet.IndexBuffer.SetData(faceset.VertexIndices * .Select(x => * { * if (x == ushort.MaxValue) * return (short)(-1); * else * return (short)x; * }) * .ToArray()); * MeshFacesets.Add(newFaceSet); * } * * Bounds = BoundingBox.CreateFromPoints(MeshVertices.Select(x => x.Position)); * * VertBuffer = new VertexBuffer(GFX.Device, * typeof(VertexPositionColorNormalTangentTexture), MeshVertices.Length, BufferUsage.WriteOnly); * VertBuffer.SetData(MeshVertices); * }*/ public FlverSubmeshRenderer(FLVER flvr, FLVER.Mesh mesh) { var shortMaterialName = MiscUtil.GetFileNameWithoutDirectoryOrExtension(flvr.Materials[mesh.MaterialIndex].MTD); if (shortMaterialName.EndsWith("_Alp") || shortMaterialName.Contains("_Edge") || shortMaterialName.Contains("_Decal") || shortMaterialName.Contains("_Cloth") || shortMaterialName.Contains("_al") || shortMaterialName.Contains("BlendOpacity")) { DrawStep = GFXDrawStep.AlphaEdge; } else { DrawStep = GFXDrawStep.Opaque; } foreach (var matParam in flvr.Materials[mesh.MaterialIndex].Params) { var paramNameCheck = matParam.Param.ToUpper(); // DS3/BB if (paramNameCheck == "G_DIFFUSETEXTURE") { TexNameDiffuse = matParam.Value; } else if (paramNameCheck == "G_SPECULARTEXTURE") { TexNameSpecular = matParam.Value; } else if (paramNameCheck == "G_BUMPMAPTEXTURE") { TexNameNormal = matParam.Value; } else if (paramNameCheck == "G_DOLTEXTURE1") { TexNameDOL1 = matParam.Value; } else if (paramNameCheck == "G_DOLTEXTURE2") { TexNameDOL2 = matParam.Value; } // DS1 params else if (paramNameCheck == "G_DIFFUSE") { TexNameDiffuse = matParam.Value; } else if (paramNameCheck == "G_SPECULAR") { TexNameSpecular = matParam.Value; } else if (paramNameCheck == "G_BUMPMAP") { TexNameNormal = matParam.Value; } } var MeshVertices = new VertexPositionColorNormalTangentTexture[mesh.VertexGroups[0].Vertices.Count]; for (int i = 0; i < mesh.VertexGroups[0].Vertices.Count; i++) { var vert = mesh.VertexGroups[0].Vertices[i]; MeshVertices[i] = new VertexPositionColorNormalTangentTexture(); MeshVertices[i].Position = new Vector3(vert.Position.X, vert.Position.Y, vert.Position.Z); if (vert.Normal != null && vert.Tangents != null && vert.Tangents.Count > 0) { MeshVertices[i].Normal = Vector3.Normalize(new Vector3(vert.Normal.X, vert.Normal.Y, vert.Normal.Z)); MeshVertices[i].Tangent = Vector3.Normalize(new Vector3(vert.Tangents[0].X, vert.Tangents[0].Y, vert.Tangents[0].Z)); MeshVertices[i].Binormal = Vector3.Cross(Vector3.Normalize(MeshVertices[i].Normal), Vector3.Normalize(MeshVertices[i].Tangent)) * vert.Tangents[0].W; } if (vert.UVs.Count > 0) { MeshVertices[i].TextureCoordinate = new Vector2(vert.UVs[0].X, vert.UVs[0].Y); if (vert.UVs.Count > 1) { MeshVertices[i].TextureCoordinate2 = new Vector2(vert.UVs[1].X, vert.UVs[1].Y); } else { MeshVertices[i].TextureCoordinate2 = Vector2.Zero; } } else { MeshVertices[i].TextureCoordinate = Vector2.Zero; MeshVertices[i].TextureCoordinate2 = Vector2.Zero; } } VertexCount = MeshVertices.Length; MeshFacesets = new List <FlverSubmeshRendererFaceSet>(); foreach (var faceset in mesh.FaceSets) { bool is32bit = (faceset.IndexSize == 0x20); var newFaceSet = new FlverSubmeshRendererFaceSet() { BackfaceCulling = faceset.CullBackfaces, IsTriangleStrip = faceset.TriangleStrip, IndexBuffer = new IndexBuffer( GFX.Device, is32bit ? IndexElementSize.ThirtyTwoBits : IndexElementSize.SixteenBits, faceset.Vertices.Length, BufferUsage.WriteOnly), IndexCount = faceset.Vertices.Length, }; if (faceset.Flags == FLVER.FaceSet.FSFlags.LodLevel1) { newFaceSet.LOD = (byte)1; HasNoLODs = false; } else if (faceset.Flags == FLVER.FaceSet.FSFlags.LodLevel2) { newFaceSet.LOD = (byte)2; HasNoLODs = false; } if (is32bit) { newFaceSet.IndexBuffer.SetData(faceset.Vertices); } else { newFaceSet.IndexBuffer.SetData(faceset.Vertices.Select(x => (ushort)x).ToArray()); } MeshFacesets.Add(newFaceSet); } Bounds = BoundingBox.CreateFromPoints(MeshVertices.Select(x => x.Position)); VertBuffer = new VertexBuffer(GFX.Device, typeof(VertexPositionColorNormalTangentTexture), MeshVertices.Length, BufferUsage.WriteOnly); VertBuffer.SetData(MeshVertices); TryToLoadTextures(); }