private void ReplaceAction(object sender, EventArgs args) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "Supported Formats|*.dae;*.fbx;*.json;|" + "FBX |*.fbx|" + "DAE |*.dae|" + "JSON |*.json|" + "All files(*.*)|*.*"; if (ofd.ShowDialog() == DialogResult.OK) { string ext = Utils.GetExtension(ofd.FileName); if (ext == ".json") { var model = JsonConvert.DeserializeObject <Model>( System.IO.File.ReadAllText(ofd.FileName)); ReloadModel(model); Model.UpdateVertexData(true); } else { AssimpData assimp = new AssimpData(); bool IsLoaded = assimp.LoadFile(ofd.FileName); if (!IsLoaded) { return; } GFLXModelImporter dialog = new GFLXModelImporter(); dialog.LoadMeshes(assimp.objects, assimp.materials, Model.GenericMaterials, Model.GenericMeshes); if (dialog.ShowDialog() == DialogResult.OK) { ImportModel(dialog, assimp.materials, assimp.objects, assimp.skeleton); } } } LoadEditor <STPropertyGrid>(); }
private void ImportModel(GFLXModelImporter importer, List <STGenericMaterial> importedMaterials, List <STGenericObject> importedMeshes, STSkeleton skeleton) { Model.Model.Groups.Clear(); Model.Model.Meshes.Clear(); List <string> textures = Model.Textures.ToList(); foreach (var mat in importedMaterials) { } var meshes = GeneratePolygonGroups(importedMeshes, importedMaterials, textures, importer.Settings); //Once mesh groups are merged search for bone nodes //The bone section is basically a node tree //Which contains nodes for meshes //We need to remove the original and replace with new ones //Then index these in our mesh groups if (importer.ImportNewBones) { //Clear the original bones and nodes Model.Skeleton.bones.Clear(); Model.Model.Bones.Clear(); List <int> SkinningIndices = new List <int>(); foreach (var genericBone in skeleton.bones) { var scale = genericBone.Scale; var trans = genericBone.Position; var rot = genericBone.EulerRotation; Bone bone = new Bone(); bone.Name = genericBone.Text; bone.BoneType = 0; bone.Parent = genericBone.parentIndex; bone.Zero = 0; bone.Visible = false; bone.Scale = new GFMDLStructs.Vector3(scale.X, scale.Y, scale.Z); bone.Rotation = new GFMDLStructs.Vector3(rot.X, rot.Y, rot.Z); bone.Translation = new GFMDLStructs.Vector3(trans.X, trans.Y, trans.Z); bone.RadiusStart = new GFMDLStructs.Vector3(0, 0, 0); bone.RadiusEnd = new GFMDLStructs.Vector3(0, 0, 0); Model.Model.Bones.Add(bone); } } int originIndex = int.MaxValue; //Go through each bone and remove the original mesh node List <STBone> bonesToRemove = new List <STBone>(); for (int i = 0; i < Model.Skeleton.bones.Count; i++) { //Reset bone as rigid var node = (GFLXBone)Model.Skeleton.bones[i]; node.Bone.RigidCheck = new BoneRigidData() { Unknown1 = 0 }; if (node.Bone.BoneType == 1) { node.Bone.BoneType = 0; } int index = Model.Skeleton.bones.IndexOf(node); if (node.Text == "Origin") { originIndex = index; } //Check if the bone is rigged to any meshes and use skinning for (int m = 0; m < meshes.Count; m++) { if (meshes[m].vertices.Any(x => x.boneNames.Contains(node.Text))) { node.Bone.BoneType = 1; node.Bone.RigidCheck = null; } } if (Model.GenericMeshes.Any(x => x.Text == node.Text)) { bonesToRemove.Add(node); Model.Model.Bones.Remove(node.Bone); } /* if (Model.Model.CollisionGroups?.Count != 0) * { * var collisionGroups = Model.Model.CollisionGroups; * for (int c = 0; c < collisionGroups.Count; c++) * { * if (collisionGroups[c].BoneIndex == i) * { * * } * } * }*/ } foreach (var bone in bonesToRemove) { Model.Skeleton.bones.Remove(bone); } bonesToRemove.Clear(); Model.Model.CollisionGroups = new List <CollisionGroup>(); List <int> skinningIndices = Model.GenerateSkinningIndices(); //Set an empty bone with rigging if there is no rigging if (importer.Settings.MeshSettings.Any(x => x.HasBoneIndices) && skinningIndices.Count == 0) { var node = (GFLXBone)Model.Skeleton.bones[0]; node.Bone.RigidCheck = null; node.Bone.BoneType = 1; skinningIndices.Add(0); } List <string> unmappedBones = new List <string>(); foreach (var mesh in meshes) { var setting = importer.Settings.MeshSettings[meshes.IndexOf(mesh)]; for (int i = 0; i < mesh.vertices.Count; i++) { if (setting.SetNormalsToColorChannel2) { mesh.vertices[i].col2 = new OpenTK.Vector4( mesh.vertices[i].nrm.X * 0.5f + 0.5f, mesh.vertices[i].nrm.Y * 0.5f + 0.5f, mesh.vertices[i].nrm.Z * 0.5f + 0.5f, 1); } //Single bind if no bones are mapped but setting is enabled if (setting.HasBoneIndices && mesh.vertices[i].boneNames.Count == 0) { mesh.vertices[i].boneIds.Add(skinningIndices.FirstOrDefault()); mesh.vertices[i].boneWeights.Add(1); } if (importer.RotationY != 0) { var transform = OpenTK.Matrix4.CreateRotationX(OpenTK.MathHelper.DegreesToRadians(importer.RotationY)); mesh.vertices[i].pos = OpenTK.Vector3.TransformPosition(mesh.vertices[i].pos, transform); mesh.vertices[i].nrm = OpenTK.Vector3.TransformPosition(mesh.vertices[i].nrm, transform); } if (importer.Settings.FlipUVsVertical) { mesh.vertices[i].uv0 = new Vector2(0, 1) - mesh.vertices[i].uv0; mesh.vertices[i].uv1 = new Vector2(0, 1) - mesh.vertices[i].uv1; mesh.vertices[i].uv2 = new Vector2(0, 1) - mesh.vertices[i].uv2; } if (importer.Settings.OptmizeZeroWeights) { float[] weightsA = new float[4]; int MaxWeight = 255; for (int j = 0; j < 4; j++) { if (mesh.vertices[i].boneWeights.Count < j + 1) { weightsA[j] = 0; MaxWeight = 0; } else { int weight = (int)(mesh.vertices[i].boneWeights[j] * 255); if (mesh.vertices[i].boneWeights.Count == j + 1) { weight = MaxWeight; } if (weight >= MaxWeight) { weight = MaxWeight; MaxWeight = 0; } else { MaxWeight -= weight; } weightsA[j] = weight / 255f; } } mesh.vertices[i].boneWeights = weightsA.ToList(); } for (int j = 0; j < mesh.vertices[i].boneNames?.Count; j++) { string boneName = mesh.vertices[i].boneNames[j]; int boneIndex = Model.Model.Bones.IndexOf(Model.Model.Bones.Where(p => p.Name == boneName).FirstOrDefault()); if (boneIndex != -1 && skinningIndices.IndexOf(boneIndex) != -1) { mesh.vertices[i].boneIds.Add(boneIndex); } else { if (!unmappedBones.Contains(boneName)) { unmappedBones.Add(boneName); } } } } } //Adjust materials if necessary if (importer.Settings.ResetUVTransform) { foreach (var mat in Model.GenericMaterials) { foreach (var param in mat.ValueParams) { if (param.Key.Contains("UVScale")) { param.Value.Value = 1; } if (param.Key.Contains("UVTranslate")) { param.Value.Value = 0; } if (param.Key.Contains("ColorBaseU")) { param.Value.Value = 0; } if (param.Key.Contains("ColorBaseV")) { param.Value.Value = 0; } } } } //Now add brand new mesh nodes foreach (var mesh in meshes) { int index = meshes.IndexOf(mesh); var setting = importer.Settings.MeshSettings[index]; Bone bone = new Bone(); bone.Name = mesh.ObjectName; bone.BoneType = 0; bone.Parent = 0; bone.Zero = 0; bone.Visible = false; bone.Scale = new GFMDLStructs.Vector3(1, 1, 1); bone.Rotation = new GFMDLStructs.Vector3(0, 0, 0); bone.Translation = new GFMDLStructs.Vector3(0, 0, 0); bone.RadiusStart = new GFMDLStructs.Vector3(0, 0, 0); bone.RadiusEnd = new GFMDLStructs.Vector3(0, 0, 0); // bone.RigidCheck = new BoneRigidData(); Model.Model.Bones.Add(bone); int NodeIndex = Model.Model.Bones.IndexOf(bone); //Now create the associated group var group = new Group(); group.Bounding = Model.GenerateBoundingBox(mesh); group.BoneIndex = (uint)NodeIndex; group.MeshIndex = (uint)index; group.Layer = 0; Model.Model.Groups.Add(group); //Now create our mesh data var meshData = new Mesh(); Model.Model.Meshes.Add(meshData); if (setting.HasTangents || setting.HasBitangents) { try { mesh.CalculateTangentBitangent(false); } catch { } } //Add attributes based on settings IList <MeshAttribute> attributes = new List <MeshAttribute>(); attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.Position, BufferFormat = (uint)setting.PositionFormat, ElementCount = 3, }); if (setting.HasNormals) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.Normal, BufferFormat = (uint)setting.NormalFormat, ElementCount = 4, }); } if (setting.HasTangents) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.Tangents, BufferFormat = (uint)setting.TangentsFormat, ElementCount = 4, }); } if (setting.HasTexCoord1) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.UV1, BufferFormat = (uint)setting.TexCoord1Format, ElementCount = 2, }); } if (setting.HasTexCoord2) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.UV2, BufferFormat = (uint)setting.TexCoord2Format, ElementCount = 2, }); } if (setting.HasTexCoord3) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.UV3, BufferFormat = (uint)setting.TexCoord3Format, ElementCount = 2, }); } if (setting.HasTexCoord4) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.UV4, BufferFormat = (uint)setting.TexCoord4Format, ElementCount = 2, }); } if (setting.HasColor1) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.Color1, BufferFormat = (uint)setting.Color1Format, ElementCount = 4, }); } if (setting.HasColor2) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.Color2, BufferFormat = (uint)setting.Color2Format, ElementCount = 4, }); } if (setting.HasBoneIndices) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.BoneID, BufferFormat = (uint)setting.BoneIndexFormat, ElementCount = 4, }); } if (setting.HasWeights) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.BoneWeight, BufferFormat = (uint)setting.BoneWeightFormat, ElementCount = 4, }); } if (setting.HasBitangents) { attributes.Add(new MeshAttribute() { VertexType = (uint)VertexType.Bitangent, BufferFormat = (uint)setting.BitangentnFormat, ElementCount = 4, }); } meshData.Attributes = attributes; meshData.SetData(GFLXMeshBufferHelper.CreateVertexDataBuffer(mesh, skinningIndices, attributes)); //Lastly add the polygon groups foreach (var poly in mesh.PolygonGroups) { List <ushort> faces = new List <ushort>(); for (int f = 0; f < poly.faces.Count; f++) { faces.Add((ushort)poly.faces[f]); } if (poly.MaterialIndex < 0) { poly.MaterialIndex = 0; } meshData.Polygons = new List <MeshPolygon>(); meshData.Polygons.Add(new MeshPolygon() { MaterialIndex = (uint)poly.MaterialIndex, Faces = faces, }); } } if (unmappedBones.Count > 0) { STErrorDialog.Show($"{unmappedBones.Count} bone(s) are not present in the boneset and are unmapped!", "GFBMDL Importer", string.Join("\n", unmappedBones.ToArray())); } Console.WriteLine($""); //Generate bounding box Model.GenerateBoundingBox(); ReloadModel(Model.Model); Model.UpdateVertexData(true); }