public static Model Load( string filePath, List <Materials.Material> mat_presets = null, TristripOption triopt = TristripOption.DoNotTriStrip, bool flipAxis = false, bool fixNormals = false, string additionalTexPath = null) { string extension = Path.GetExtension(filePath); Model output = null; if (extension == ".bmd" || extension == ".bdl") { using (FileStream str = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { EndianBinaryReader reader = new EndianBinaryReader(str, Endian.Big); output = new Model(reader, mat_presets); } } else { Assimp.AssimpContext cont = new Assimp.AssimpContext(); // AssImp adds dummy nodes for pivots from FBX, so we'll force them off cont.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); Assimp.PostProcessSteps postprocess = Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices; if (triopt == TristripOption.DoNotTriStrip) { // By not joining identical vertices, the Tri Strip algorithm we use cannot make tristrips, // effectively disabling tri stripping postprocess = Assimp.PostProcessSteps.Triangulate; } Assimp.Scene aiScene = cont.ImportFile(filePath, postprocess); output = new Model(aiScene, filePath, mat_presets, triopt, flipAxis, fixNormals, additionalTexPath); } return(output); }
public Model( Scene scene, string modelDirectory, List <Materials.Material> mat_presets = null, TristripOption triopt = TristripOption.DoNotTriStrip, bool flipAxis = false, bool fixNormals = false, string additionalTexPath = null) { Assimp.Node root = null; for (int i = 0; i < scene.RootNode.ChildCount; i++) { if (scene.RootNode.Children[i].Name.ToLowerInvariant() == "skeleton_root") { if (scene.RootNode.Children[i].ChildCount == 0) { throw new System.Exception("skeleton_root has no children! If you are making a rigged model, make sure skeleton_root contains the root of your skeleton."); } root = scene.RootNode.Children[i].Children[0]; break; } } foreach (Mesh mesh in scene.Meshes) { if (mesh.HasBones && root == null) { throw new System.Exception("Model uses bones but the skeleton root has not been found! Make sure your skeleton is inside a dummy object called 'skeleton_root'."); } } Matrix3x3 rotateXminus90 = Matrix3x3.FromRotationX((float)(-(1 / 2.0) * Math.PI)); Matrix3x3 rotateXplus90 = Matrix3x3.FromRotationX((float)((1 / 2.0) * Math.PI)); Matrix3x3 rotateYminus90 = Matrix3x3.FromRotationY((float)(-(1 / 2.0) * Math.PI)); Matrix3x3 rotateYplus90 = Matrix3x3.FromRotationY((float)((1 / 2.0) * Math.PI)); Matrix3x3 rotateZminus90 = Matrix3x3.FromRotationZ((float)(-(1 / 2.0) * Math.PI)); Matrix3x3 rotateZplus90 = Matrix3x3.FromRotationZ((float)((1 / 2.0) * Math.PI)); if (flipAxis) { Console.WriteLine("Rotating the model..."); int i = 0; Matrix4x4 rotate = Matrix4x4.FromRotationX((float)(-(1 / 2.0) * Math.PI)); //rotate = Matrix4x4.FromRotationZ((float)(-(1 / 2.0) * Math.PI)); Matrix4x4 rotateinv = rotate; //Matrix3x3 rotvec = rotateZplus90 * rotateXplus90; //Matrix3x3 rotvec = rotateYplus90*rotateYplus90 * rotateZplus90 * rotateZplus90* rotateXplus90* rotateXplus90; rotateinv.Inverse(); //rotate = Matrix4x4.FromRotationY((float)(-(1 / 2.0) * Math.PI)); //rotate = Matrix4x4.FromRotationZ((float)(-(1 / 2.0) * Math.PI)); Matrix4x4 rotateC = Matrix4x4.FromRotationX((float)(-(1 / 2.0) * Math.PI)); Matrix4x4 trans; if (root != null) { // Rotate rigged mesh foreach (Mesh mesh in scene.Meshes) { Console.WriteLine(mesh.Name); Console.WriteLine(String.Format("Does it have bones? {0}", mesh.HasBones)); Matrix3x3[] weightedmats = new Matrix3x3[mesh.Normals.Count]; foreach (Assimp.Bone bone in mesh.Bones) { bone.OffsetMatrix = rotateinv * bone.OffsetMatrix; /*Matrix3x3 invbind = bone.OffsetMatrix; * //bind.Inverse(); * //List<int> vertices = new List<VertexWeight>(); * * foreach (Assimp.VertexWeight weight in bone.VertexWeights) { * Matrix3x3 weightedcurrentmat = new Matrix3x3( * weight.Weight * invbind.A1, weight.Weight * invbind.A2, weight.Weight * invbind.A1, * weight.Weight * invbind.B1, weight.Weight * invbind.B2, weight.Weight * invbind.B3, * weight.Weight * invbind.C1, weight.Weight * invbind.C2, weight.Weight * invbind.C3); * * if (weightedmats[weight.VertexID] == null) { * weightedmats[weight.VertexID] = weightedcurrentmat; * } * else { * Matrix3x3 existingmat = weightedmats[weight.VertexID]; * weightedmats[weight.VertexID] = new Matrix3x3( * existingmat.A1 + invbind.A1, existingmat.A2 + invbind.A2, existingmat.A3 + invbind.A3, * existingmat.B1 + invbind.B1, existingmat.B2 + invbind.B2, existingmat.B3 + invbind.B3, * existingmat.C1 + invbind.C1, existingmat.C2 + invbind.C2, existingmat.C3 + invbind.C3); * } * }*/ //Matrix4x4 bindMat = bone.OffsetMatrix; //bindMat.Inverse(); //trans = /*bone.OffsetMatrix = root.Transform * bone.OffsetMatrix; * Matrix4x4 newtransform = root.Transform * rotate; * newtransform.Inverse(); * bone.OffsetMatrix = newtransform * bone.OffsetMatrix;*/ } for (i = 0; i < mesh.VertexCount; i++) { Vector3D vertex = mesh.Vertices[i]; vertex.Set(vertex.X, vertex.Z, -vertex.Y); mesh.Vertices[i] = vertex; } for (i = 0; i < mesh.Normals.Count; i++) { Vector3D norm = mesh.Normals[i]; norm.Set(norm.X, norm.Z, -norm.Y); //Matrix3x3 invbind = weightedmats[i]; //invbind.Inverse(); //norm = invbind * norm; mesh.Normals[i] = norm; } } } else { // Rotate static mesh foreach (Mesh mesh in scene.Meshes) { for (i = 0; i < mesh.VertexCount; i++) { Vector3D vertex = mesh.Vertices[i]; vertex.Set(vertex.X, vertex.Z, -vertex.Y); mesh.Vertices[i] = vertex; } for (i = 0; i < mesh.Normals.Count; i++) { Vector3D norm = mesh.Normals[i]; norm.Set(norm.X, norm.Z, -norm.Y); mesh.Normals[i] = norm; } } } if (root != null) { List <Assimp.Node> allnodes = new List <Assimp.Node>(); List <Assimp.Node> processnodes = new List <Assimp.Node>(); processnodes.Add(root); root.Transform = root.Transform * rotate; /*while (processnodes.Count > 0) { * Assimp.Node current = processnodes[0]; * processnodes.RemoveAt(0); * * current.Transform = current.Transform * rotate; * * foreach (Assimp.Node child in current.Children) { * processnodes.Add(child); * } * }*/ } } // On rigged models we attempt to fix normals for shading to work properly (when using materials) // That works by multiplying the normal for a vertex with the inverse bind matrices that have an effect on the vertex. // Seems to work semi-well, might need to look over this at a later point again though. Console.WriteLine(String.Format("fixNormals is {0}", fixNormals)); if (fixNormals && root != null) { Console.WriteLine("Fixing the normals on the rigged mesh..."); foreach (Mesh mesh in scene.Meshes) { List <Tuple <float, Matrix3x3> >[] weightedmats = new List <Tuple <float, Matrix3x3> > [mesh.Normals.Count];//new Matrix3x3[mesh.Normals.Count]; foreach (Assimp.Bone bone in mesh.Bones) { Matrix3x3 invbind = bone.OffsetMatrix; foreach (Assimp.VertexWeight weight in bone.VertexWeights) { if (weightedmats[weight.VertexID] == null) { weightedmats[weight.VertexID] = new List <Tuple <float, Matrix3x3> >(); } weightedmats[weight.VertexID].Add(Tuple.Create(weight.Weight, invbind)); /*Matrix3x3 weightedcurrentmat = new Matrix3x3( * weight.Weight * invbind.A1, weight.Weight * invbind.A2, weight.Weight * invbind.A1, * weight.Weight * invbind.B1, weight.Weight * invbind.B2, weight.Weight * invbind.B3, * weight.Weight * invbind.C1, weight.Weight * invbind.C2, weight.Weight * invbind.C3); * * if (weightedmats[weight.VertexID] == null) { * weightedmats[weight.VertexID] = weightedcurrentmat; * } * else { * Matrix3x3 existingmat = weightedmats[weight.VertexID]; * weightedmats[weight.VertexID] = new Matrix3x3( * existingmat.A1 + invbind.A1, existingmat.A2 + invbind.A2, existingmat.A3 + invbind.A3, * existingmat.B1 + invbind.B1, existingmat.B2 + invbind.B2, existingmat.B3 + invbind.B3, * existingmat.C1 + invbind.C1, existingmat.C2 + invbind.C2, existingmat.C3 + invbind.C3); * }*/ } } for (int i = 0; i < mesh.Normals.Count; i++) { if (weightedmats[i] == null) { continue; // means that index hasn't been weighted to so we can't do anything? } //weightedmats[i].Sort((x, y) => y.Item1.CompareTo(x.Item1)); Vector3D norm = mesh.Normals[i]; Matrix3x3 invbind = ScalarMultiply3x3(weightedmats[i][0].Item1, weightedmats[i][0].Item2); for (int j = 1; j < weightedmats[i].Count; j++) { invbind = AddMatrix3x3( invbind, ScalarMultiply3x3(weightedmats[i][j].Item1, weightedmats[i][j].Item2) ); } norm = invbind * norm; mesh.Normals[i] = norm; } } } // We check if the model mixes weighted and unweighted vertices. // If that is the case, we throw an exception here. If we don't, // an exception will be thrown later on that is less helpful to the user. if (true) { bool usesWeights = false; foreach (Mesh mesh in scene.Meshes) { bool[] weightedmats = new bool[mesh.VertexCount]; foreach (Assimp.Bone bone in mesh.Bones) { foreach (Assimp.VertexWeight weight in bone.VertexWeights) { weightedmats[weight.VertexID] = true; } } for (uint i = 0; i < mesh.VertexCount; i++) { if (weightedmats[i] == true) { usesWeights = true; } else if (usesWeights) { throw new System.Exception("Model has a mixture of weighted and unweighted vertices! Please weight all vertices to at least one bone."); } } } } VertexData = new VTX1(scene); Joints = new JNT1(scene, VertexData); Scenegraph = new INF1(scene, Joints); Textures = new TEX1(scene, Path.GetDirectoryName(modelDirectory)); SkinningEnvelopes = new EVP1(); SkinningEnvelopes.SetInverseBindMatrices(scene, Joints.FlatSkeleton); //SkinningEnvelopes.AddInverseBindMatrices(Joints.FlatSkeleton); PartialWeightData = new DRW1(scene, Joints.BoneNameIndices); Shapes = SHP1.Create(scene, Joints.BoneNameIndices, VertexData.Attributes, SkinningEnvelopes, PartialWeightData, triopt); Materials = new MAT3(scene, Textures, Shapes, mat_presets); if (additionalTexPath == null) { Materials.LoadAdditionalTextures(Textures, Path.GetDirectoryName(modelDirectory)); } else { Materials.LoadAdditionalTextures(Textures, additionalTexPath); } Materials.MapTextureNamesToIndices(Textures); foreach (Geometry.Shape shape in Shapes.Shapes) { packetCount += shape.Packets.Count; } vertexCount = VertexData.Attributes.Positions.Count; }
private void TriStripComboBox_SelectedIndexChanged(object sender, EventArgs e) => triopt = (TristripOption)Enum.Parse(typeof(TristripOption), TriStripComboBox.SelectedValue.ToString(), true);