public override void OnInspectorGUI() { FlverSubmesh submesh = (FlverSubmesh)target; // Long check to see if generating lightmap UVs is safe if (submesh.Link != null) { if (submesh.Link.Submeshes.Count > submesh.SubmeshIdx) { if (submesh.Link.Submeshes[submesh.SubmeshIdx].Mtd != null) { if (submesh.Link.Submeshes[submesh.SubmeshIdx].Mtd.LightmapUVIndex != -1) { if (GUILayout.Button("Generate Lightmap UVs")) { submesh.Link.GenerateLightmapUVSForSubmesh(submesh.SubmeshIdx); } } } } } if (GUILayout.Button("Dump Normals")) { var dump = CreateInstance <NormalDump>(); var mesh = ((FlverSubmesh)target).gameObject.GetComponent <MeshFilter>().sharedMesh; dump.Normals = mesh.normals; AssetDatabase.CreateAsset(dump, "Assets/normaldump.asset"); } if (submesh.Link != null) { if (submesh.Link.Submeshes.Count > submesh.SubmeshIdx) { if (submesh.Link.Submeshes[submesh.SubmeshIdx].Mtd != null) { var sub = submesh.Link.Submeshes[submesh.SubmeshIdx]; GUILayout.Label($@"Material Name: {sub.Name}"); GUILayout.Label($@"MTD: {sub.Mtd}"); GUILayout.Label($@"Lightmap Index: {sub.Mtd.LightmapUVIndex}"); } } } }
public override void OnInspectorGUI() { FlverSubmesh submesh = (FlverSubmesh)target; // Long check to see if generating lightmap UVs is safe if (submesh.Link != null) { if (submesh.Link.Submeshes.Count > submesh.SubmeshIdx) { if (submesh.Link.Submeshes[submesh.SubmeshIdx].Mtd != null) { if (submesh.Link.Submeshes[submesh.SubmeshIdx].Mtd.LightmapUVIndex != -1) { if (GUILayout.Button("Generate Lightmap UVs")) { submesh.Link.GenerateLightmapUVSForSubmesh(submesh.SubmeshIdx); } } } } } }
private bool LoadInternalDeS(AccessLevel al, GameType type) { if (al == AccessLevel.AccessFull || al == AccessLevel.AccessGPUOptimizedOnly) { GPUMeshes = new FlverSubmesh[FlverDeS.Meshes.Count()]; GPUMaterials = new FlverMaterial[FlverDeS.Materials.Count()]; Bounds = new BoundingBox(); Bones = FlverDeS.Bones; for (int i = 0; i < FlverDeS.Materials.Count(); i++) { GPUMaterials[i] = new FlverMaterial(); ProcessMaterial(FlverDeS.Materials[i], GPUMaterials[i], type); } for (int i = 0; i < FlverDeS.Meshes.Count(); i++) { GPUMeshes[i] = new FlverSubmesh(); ProcessMesh(FlverDeS.Meshes[i], GPUMeshes[i]); if (i == 0) { Bounds = GPUMeshes[i].Bounds; } else { Bounds = BoundingBox.Combine(Bounds, GPUMeshes[i].Bounds); } } } if (al == AccessLevel.AccessGPUOptimizedOnly) { Flver = null; } //return false; return(true); }
unsafe private void ProcessMesh(FLVER2.Mesh mesh, FlverSubmesh dest) { var factory = Scene.Renderer.Factory; dest.Material = GPUMaterials[mesh.MaterialIndex]; //var MeshVertices = VerticesPool.Rent(mesh.VertexCount); var vSize = dest.Material.VertexSize; var meshVertices = Marshal.AllocHGlobal(mesh.VertexCount * (int)vSize); dest.PickingVertices = Marshal.AllocHGlobal(mesh.VertexCount * sizeof(Vector3)); var pvhandle = new Span <Vector3>(dest.PickingVertices.ToPointer(), mesh.VertexCount); if (dest.Material.LayoutType == MeshLayoutType.LayoutSky) { FillVerticesNormalOnly(mesh, pvhandle, meshVertices); } else if (dest.Material.LayoutType == MeshLayoutType.LayoutUV2) { FillVerticesUV2(mesh, pvhandle, meshVertices); } else { FillVerticesStandard(mesh, pvhandle, meshVertices); } dest.VertexCount = mesh.VertexCount; dest.MeshFacesets = new List <FlverSubmesh.FlverSubmeshFaceSet>(); var facesets = mesh.FaceSets; var fsUploadsPending = facesets.Count(); bool is32bit = Flver.Header.Version > 0x20005 && mesh.VertexCount > 65535; int indicesTotal = 0; ushort[] fs16 = null; int[] fs32 = null; foreach (var faceset in facesets) { indicesTotal += faceset.Indices.Length; } if (is32bit) { fs32 = new int[indicesTotal]; } else { fs16 = new ushort[indicesTotal]; } int idxoffset = 0; foreach (var faceset in facesets) { if (faceset.Indices.Length == 0) { continue; } //At this point they use 32-bit faceset vertex indices uint buffersize = (uint)faceset.IndicesCount * (is32bit ? 4u : 2u); var indices = faceset.TriangleStrip ? faceset.Triangulate(true).ToArray() : faceset.Indices.ToArray(); var newFaceSet = new FlverSubmesh.FlverSubmeshFaceSet() { BackfaceCulling = faceset.CullBackfaces, IsTriangleStrip = faceset.TriangleStrip, //IndexBuffer = factory.CreateBuffer(new BufferDescription(buffersize, BufferUsage.IndexBuffer)), IndexOffset = idxoffset, IndexCount = faceset.IndicesCount, Is32Bit = is32bit, PickingIndicesCount = indices.Length, //PickingIndices = Marshal.AllocHGlobal(indices.Length * 4), }; fixed(void *iptr = indices) { //Unsafe.CopyBlock(newFaceSet.PickingIndices.ToPointer(), iptr, (uint)indices.Length * 4); } if ((faceset.Flags & FLVER2.FaceSet.FSFlags.LodLevel1) > 0) { newFaceSet.LOD = 1; //HasNoLODs = false; newFaceSet.IsMotionBlur = false; } else if ((faceset.Flags & FLVER2.FaceSet.FSFlags.LodLevel2) > 0) { newFaceSet.LOD = 2; //HasNoLODs = false; newFaceSet.IsMotionBlur = false; } if ((faceset.Flags & FLVER2.FaceSet.FSFlags.MotionBlur) > 0) { newFaceSet.IsMotionBlur = true; } if (is32bit) { for (int i = 0; i < faceset.Indices.Length; i++) { if (faceset.Indices[i] == 0xFFFF && faceset.Indices[i] > mesh.Vertices.Length) { fs32[newFaceSet.IndexOffset + i] = -1; } else { fs32[newFaceSet.IndexOffset + i] = faceset.Indices[i]; } } } else { for (int i = 0; i < faceset.Indices.Length; i++) { if (faceset.Indices[i] == 0xFFFF && faceset.Indices[i] > mesh.Vertices.Length) { fs16[newFaceSet.IndexOffset + i] = 0xFFFF; } else { fs16[newFaceSet.IndexOffset + i] = (ushort)faceset.Indices[i]; } } } dest.MeshFacesets.Add(newFaceSet); idxoffset += faceset.Indices.Length; } dest.Bounds = BoundingBox.CreateFromPoints((Vector3 *)dest.PickingVertices.ToPointer(), dest.VertexCount, 12, Quaternion.Identity, Vector3.Zero, Vector3.One); uint vbuffersize = (uint)mesh.VertexCount * (uint)vSize; dest.GeomBuffer = Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, (uint)indicesTotal * (is32bit ? 4u : 2u), (int)vSize, 4, (h) => { h.FillVBuffer(meshVertices, vSize * (uint)mesh.VertexCount, () => { Marshal.FreeHGlobal(meshVertices); }); if (is32bit) { h.FillIBuffer(fs32); } else { h.FillIBuffer(fs16); } }); facesets = null; if (CaptureMaterialLayouts) { lock (_matLayoutLock) { if (!MaterialLayouts.ContainsKey(dest.Material.MaterialName)) { MaterialLayouts.Add(dest.Material.MaterialName, Flver.BufferLayouts[mesh.VertexBuffers[0].LayoutIndex]); } } } if (mesh.DefaultBoneIndex != -1 && mesh.DefaultBoneIndex < Bones.Count) { dest.LocalTransform = Utils.GetBoneObjectMatrix(Bones[mesh.DefaultBoneIndex], Bones); } Marshal.FreeHGlobal(dest.PickingVertices); }
unsafe private void ProcessMesh(FLVER0.Mesh mesh, FlverSubmesh dest) { var factory = Scene.Renderer.Factory; dest.Material = GPUMaterials[mesh.MaterialIndex]; //var MeshVertices = VerticesPool.Rent(mesh.VertexCount); var vSize = dest.Material.VertexSize; var meshVertices = Marshal.AllocHGlobal(mesh.Vertices.Count * (int)vSize); dest.PickingVertices = Marshal.AllocHGlobal(mesh.Vertices.Count * sizeof(Vector3)); var pvhandle = new Span <Vector3>(dest.PickingVertices.ToPointer(), mesh.Vertices.Count); if (dest.Material.LayoutType == MeshLayoutType.LayoutSky) { FillVerticesNormalOnly(mesh, pvhandle, meshVertices); } else if (dest.Material.LayoutType == MeshLayoutType.LayoutUV2) { FillVerticesUV2(mesh, pvhandle, meshVertices); } else { FillVerticesStandard(mesh, pvhandle, meshVertices); } dest.VertexCount = mesh.Vertices.Count; dest.MeshFacesets = new List <FlverSubmesh.FlverSubmeshFaceSet>(); bool is32bit = false;//FlverDeS.Version > 0x20005 && mesh.Vertices.Count > 65535; int indicesTotal = 0; ushort[] fs16 = null; int[] fs32 = null; int idxoffset = 0; if (mesh.VertexIndices.Count != 0) { var indices = mesh.Triangulate(FlverDeS.Version).ToArray(); uint buffersize = (uint)indices.Length * (is32bit ? 4u : 2u); indicesTotal = indices.Length; if (is32bit) { fs32 = new int[indicesTotal]; } else { fs16 = new ushort[indicesTotal]; } var newFaceSet = new FlverSubmesh.FlverSubmeshFaceSet() { BackfaceCulling = true, IsTriangleStrip = false, //IndexBuffer = factory.CreateBuffer(new BufferDescription(buffersize, BufferUsage.IndexBuffer)), IndexOffset = idxoffset, IndexCount = indices.Length, Is32Bit = is32bit, PickingIndicesCount = indices.Length, //PickingIndices = Marshal.AllocHGlobal(indices.Length * 4), }; fixed(void *iptr = indices) { //Unsafe.CopyBlock(newFaceSet.PickingIndices.ToPointer(), iptr, (uint)indices.Length * 4); } if (is32bit) { for (int i = 0; i < indices.Length; i++) { if (indices[i] == 0xFFFF && indices[i] > mesh.Vertices.Count) { fs32[newFaceSet.IndexOffset + i] = -1; } else { fs32[newFaceSet.IndexOffset + i] = indices[i]; } } } else { for (int i = 0; i < indices.Length; i++) { if (indices[i] == 0xFFFF && indices[i] > mesh.Vertices.Count) { fs16[newFaceSet.IndexOffset + i] = 0xFFFF; } else { fs16[newFaceSet.IndexOffset + i] = (ushort)indices[i]; } } } dest.MeshFacesets.Add(newFaceSet); } dest.Bounds = BoundingBox.CreateFromPoints((Vector3 *)dest.PickingVertices.ToPointer(), dest.VertexCount, 12, Quaternion.Identity, Vector3.Zero, Vector3.One); uint vbuffersize = (uint)mesh.Vertices.Count * (uint)vSize; dest.GeomBuffer = Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, (uint)indicesTotal * (is32bit ? 4u : 2u), (int)vSize, 4, (h) => { h.FillVBuffer(meshVertices, vSize * (uint)mesh.Vertices.Count, () => { Marshal.FreeHGlobal(meshVertices); }); if (is32bit) { h.FillIBuffer(fs32); } else { h.FillIBuffer(fs16); } }); if (CaptureMaterialLayouts) { lock (_matLayoutLock) { if (!MaterialLayouts.ContainsKey(dest.Material.MaterialName)) { MaterialLayouts.Add(dest.Material.MaterialName, Flver.BufferLayouts[mesh.LayoutIndex]); } } } }
public List <Vector4> SolveTangents(FlverSubmesh mesh, List <ushort> vertexIndices, List <Vector3> highQualityVertexNormals, List <Vector3> hqVertPositions, List <Vector2> hqVertUVs) { int triangleCount = vertexIndices.Count; int vertexCount = mesh.Vertices.Count; Vector3[] tan1 = new Vector3[vertexCount]; Vector3[] tan2 = new Vector3[vertexCount]; List <Vector4> tangentList = new List <Vector4>(); for (int a = 0; a < vertexIndices.Count; a += 3) { try { int i1 = vertexIndices[a]; int i2 = vertexIndices[a + 1]; int i3 = vertexIndices[a + 2]; if (i1 != i2 || i2 != i3) { Vector3 v1 = hqVertPositions[i1]; Vector3 v2 = hqVertPositions[i2]; Vector3 v3 = hqVertPositions[i3]; Vector2 w1 = new Vector2(hqVertUVs[i1].X, hqVertUVs[i1].Y); Vector2 w2 = new Vector2(hqVertUVs[i2].X, hqVertUVs[i2].Y); Vector2 w3 = new Vector2(hqVertUVs[i3].X, hqVertUVs[i3].Y); float x1 = v2.X - v1.X; float x2 = v3.X - v1.X; float y1 = v2.Y - v1.Y; float y2 = v3.Y - v1.Y; float z1 = v2.Z - v1.Z; float z2 = v3.Z - v1.Z; float s1 = w2.X - w1.X; float s2 = w3.X - w1.X; float t1 = w2.Y - w1.Y; float t2 = w3.Y - w1.Y; float r = 1.0f / (s1 * t2 - s2 * t1); Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); tan1[i1] += sdir; tan1[i2] += sdir; tan1[i3] += sdir; tan2[i1] += tdir; tan2[i2] += tdir; tan2[i3] += tdir; } } catch (Exception ex) { Importer.PrintError($"Exception encountered while solving mesh tangents:\n{ex}"); break; } } for (int i = 0; i < vertexCount; i++) { Vector3 n = highQualityVertexNormals[i]; Vector3 t = tan1[i]; float w = ((!(Vector3.Dot(Vector3.Cross(n, t), tan2[i]) < 0f)) ? 1 : (-1)); //mesh.Vertices[i].BiTangent = new Vector4(Vector3.Normalize((t - n * Vector3.Dot(n, t))), // (Vector3.Dot(Vector3.Cross(n, t), tan2[i]) < 0.0f) ? -1.0f : 1.0f); mesh.Vertices[i].BiTangent = new Vector4(Vector3.Normalize(t - n * Vector3.Dot(n, t)), w); tangentList.Add(new Vector4(Vector3.Normalize(t - n * Vector3.Dot(n, t)), w)); } return(tangentList); }
public static (int VertsFixed, int TotalSourceVerts) FixBodyPiece(FlverSubmesh mesh, string bodyPieceType, out string possibleError) { possibleError = null; if (!MaterialToEmbeddedFlverMap.ContainsKey(bodyPieceType)) { possibleError = "Invalid body piece type: '{bodyPieceType}' in material name of this body part. Below is a list of valid types:" + " -HD_M\n" + " -BD_M\n" + " -AM_M\n" + " -LG_M\n" + " -HD_F\n" + " -BD_F\n" + " -AM_F\n" + " -LG_F\n" + " -HD_M_Hollow\n" + " -BD_M_Hollow\n" + " -AM_M_Hollow\n" + " -LG_M_Hollow\n" + " -HD_F_Hollow\n" + " -BD_F_Hollow\n" + " -AM_F_Hollow\n" + " -LG_F_Hollow\n"; return(-1, -1); } var flverName = MaterialToEmbeddedFlverMap[bodyPieceType]; var flver = GetFlver(flverName); List <FlverVertex> possibleVertices = new List <FlverVertex>(); foreach (var v in flver.Submeshes[0].Vertices) { possibleVertices.Add(v); } int numberOfVertsFixed = 0; int totalVerts = possibleVertices.Count; foreach (var v in mesh.Vertices) { foreach (var possible in possibleVertices) { if (CheckIfVertexMatches(v, possible)) { v.Position = possible.Position; v.Normal = possible.Normal; v.BiTangent = possible.BiTangent; string targetBoneNameA = flver.GetBoneFromIndex(possible.BoneIndices.A)?.Name; string targetBoneNameB = flver.GetBoneFromIndex(possible.BoneIndices.B)?.Name; string targetBoneNameC = flver.GetBoneFromIndex(possible.BoneIndices.C)?.Name; string targetBoneNameD = flver.GetBoneFromIndex(possible.BoneIndices.D)?.Name; v.BoneIndices.A = mesh.FindOrAddBoneIndex(targetBoneNameA); v.BoneIndices.B = mesh.FindOrAddBoneIndex(targetBoneNameB); v.BoneIndices.C = mesh.FindOrAddBoneIndex(targetBoneNameC); v.BoneIndices.D = mesh.FindOrAddBoneIndex(targetBoneNameD); v.BoneWeights = possible.BoneWeights; numberOfVertsFixed++; possibleVertices.Remove(possible); } } } return(numberOfVertsFixed, totalVerts); }
public static (int VertsFixed, int TotalSourceVerts) FixBodyPiece(FlverSubmesh mesh, string bodyPieceType, out string possibleError) { possibleError = null; if (!MaterialToEmbeddedFlverMap.ContainsKey(bodyPieceType)) { possibleError = $"Invalid body piece type: '{bodyPieceType}' in material name of this body part. Below is a list of valid types:" + " -HD_M\n" + " -BD_M\n" + " -AM_M\n" + " -LG_M\n" + " -HD_F\n" + " -BD_F\n" + " -AM_F\n" + " -LG_F\n" + " -HD_M_Hollow\n" + " -BD_M_Hollow\n" + " -AM_M_Hollow\n" + " -LG_M_Hollow\n" + " -HD_F_Hollow\n" + " -BD_F_Hollow\n" + " -AM_F_Hollow\n" + " -LG_F_Hollow\n"; return(-1, -1); } var flverName = MaterialToEmbeddedFlverMap[bodyPieceType]; var flver = GetFlver(flverName); List <FlverVertex> possibleVertices = new List <FlverVertex>(); foreach (var v in flver.Submeshes[0].Vertices) { possibleVertices.Add(v); } int numberOfVertsFixed = 0; int totalVerts = possibleVertices.Count; //List<FlverVertex> possibleVertsCheckedOff = new List<FlverVertex>(); foreach (var v in mesh.Vertices) { //(FlverVertex Vert, float Dist) closestDistance = (null, float.MaxValue); FlverVertex closest = null; foreach (var possible in possibleVertices) { //float dist = ((Vector3)(possible.Position - v.Position)).LengthSquared(); //if (dist < closestDistance.Dist) // closestDistance = (possible, dist); if (CheckIfVertexMatches(v, possible)) { closest = possible; v.Position = closest.Position; v.Normal = closest.Normal; v.BiTangent = closest.BiTangent; string targetBoneNameA = closest.BoneIndices.A >= 0 ? flver.GetBoneFromIndex(flver.Submeshes[0].BoneIndices[closest.BoneIndices.A])?.Name : null; string targetBoneNameB = closest.BoneIndices.B >= 0 ? flver.GetBoneFromIndex(flver.Submeshes[0].BoneIndices[closest.BoneIndices.B])?.Name : null; string targetBoneNameC = closest.BoneIndices.C >= 0 ? flver.GetBoneFromIndex(flver.Submeshes[0].BoneIndices[closest.BoneIndices.C])?.Name : null; string targetBoneNameD = closest.BoneIndices.D >= 0 ? flver.GetBoneFromIndex(flver.Submeshes[0].BoneIndices[closest.BoneIndices.D])?.Name : null; v.BoneIndices.A = mesh.FindOrAddBoneIndex(targetBoneNameA); v.BoneIndices.B = mesh.FindOrAddBoneIndex(targetBoneNameB); v.BoneIndices.C = mesh.FindOrAddBoneIndex(targetBoneNameC); v.BoneIndices.D = mesh.FindOrAddBoneIndex(targetBoneNameD); v.BoneWeights = closest.BoneWeights; v.UVs = closest.UVs; numberOfVertsFixed++; } } //if (possibleVertsCheckedOff.Count > 0) //{ // foreach (var checkoff in possibleVertsCheckedOff) // possibleVertices.Remove(checkoff); // possibleVertsCheckedOff.Clear(); //} } return(numberOfVertsFixed, totalVerts); }