public static void AssimpPRMConvert(string initialFilePath, string finalFilePath) { Assimp.AssimpContext context = new Assimp.AssimpContext(); context.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); Assimp.Scene aiScene = context.ImportFile(initialFilePath, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.FlipUVs); PRMModel prm = new PRMModel(); int totalVerts = 0; //Iterate through and combine meshes. PRMs can only have a single mesh IterateAiNodesPRM(prm, ref totalVerts, aiScene, aiScene.RootNode, Matrix4x4.Transpose(GetMat4FromAssimpMat4(aiScene.RootNode.Transform))); AquaUtil.WritePRMToFile(prm, finalFilePath, 4); }
private static void IterateAiNodesPRM(PRMModel prm, ref int totalVerts, Assimp.Scene aiScene, Assimp.Node node, Matrix4x4 parentTfm) { Matrix4x4 nodeMat = Matrix4x4.Transpose(GetMat4FromAssimpMat4(node.Transform)); nodeMat = Matrix4x4.Multiply(nodeMat, parentTfm); foreach (int meshId in node.MeshIndices) { var mesh = aiScene.Meshes[meshId]; AddAiMeshToPRM(prm, ref totalVerts, mesh, nodeMat); } foreach (var childNode in node.Children) { IterateAiNodesPRM(prm, ref totalVerts, aiScene, childNode, nodeMat); } }
public static Assimp.Scene AssimpPRMExport(string filePath, PRMModel prm) { Assimp.Scene aiScene = new Assimp.Scene(); //Create an array to hold references to these since Assimp lacks a way to grab these by order or id //We don't need the nodo count in this since they can't be parents Assimp.Node[] boneArray = new Assimp.Node[2]; //Set up root node var aiRootNode = new Assimp.Node("RootNode", null); aiRootNode.Transform = Assimp.Matrix4x4.Identity; boneArray[0] = aiRootNode; aiScene.RootNode = aiRootNode; //Set up single child node var aiNode = new Assimp.Node(Path.GetFileNameWithoutExtension(filePath) + "_node", aiRootNode); //Use inverse bind matrix as base //Get local transform aiNode.Transform = aiRootNode.Transform; aiRootNode.Children.Add(aiNode); boneArray[1] = aiNode; //Mesh string aiMeshName = Path.GetFileNameWithoutExtension(filePath); var aiMesh = new Assimp.Mesh(aiMeshName, Assimp.PrimitiveType.Triangle); //Vertex face data - PSO2 Actually doesn't do this, it just has per vertex data so we can just map a vertice's data to each face using it //It may actually be possible to add this to the previous loop, but my reference didn't so I'm doing it in a separate loop for safety //Reference: https://github.com/TGEnigma/Amicitia/blob/master/Source/AmicitiaLibrary/Graphics/RenderWare/RWClumpNode.cs for (int vertId = 0; vertId < prm.vertices.Count; vertId++) { var prmVert = prm.vertices[vertId]; var pos = prmVert.pos * 100; aiMesh.Vertices.Add(new Assimp.Vector3D(pos.X, pos.Y, pos.Z)); var nrm = prmVert.normal; aiMesh.Normals.Add(new Assimp.Vector3D(nrm.X, nrm.Y, nrm.Z)); //Vert colors are bgra var rawClr = prmVert.color; var clr = new Assimp.Color4D(clrToFloat(rawClr[2]), clrToFloat(rawClr[1]), clrToFloat(rawClr[0]), clrToFloat(rawClr[3])); aiMesh.VertexColorChannels[0].Add(clr); var uv1 = prmVert.uv1; var aiUV1 = new Assimp.Vector3D(uv1.X, uv1.Y, 0f); aiMesh.TextureCoordinateChannels[0].Add(aiUV1); var uv2 = prmVert.uv2; var aiUV2 = new Assimp.Vector3D(uv2.X, uv2.Y, 0f); aiMesh.TextureCoordinateChannels[1].Add(aiUV2); } //Handle rigid meshes { var aiBone = new Assimp.Bone(); var aqnBone = boneArray[0]; // Name aiBone.Name = aiNode.Name; // VertexWeights for (int i = 0; i < aiMesh.Vertices.Count; i++) { var aiVertexWeight = new Assimp.VertexWeight(i, 1f); aiBone.VertexWeights.Add(aiVertexWeight); } aiBone.OffsetMatrix = Assimp.Matrix4x4.Identity; aiMesh.Bones.Add(aiBone); } //Faces foreach (var face in prm.faces) { aiMesh.Faces.Add(new Assimp.Face(new int[] { (int)face.X, (int)face.Y, (int)face.Z })); } //Material Assimp.Material mate = new Assimp.Material(); mate.ColorDiffuse = new Assimp.Color4D(1, 1, 1, 1); mate.Name = aiMeshName + "_material"; mate.ShadingMode = Assimp.ShadingMode.Phong; var meshNodeName = Path.GetFileNameWithoutExtension(filePath); // Add mesh to meshes aiScene.Meshes.Add(aiMesh); // Add material to materials aiScene.Materials.Add(mate); // MaterialIndex aiMesh.MaterialIndex = aiScene.Materials.Count - 1; // Set up mesh node and add this mesh's index to it (This tells assimp to export it as a mesh for various formats) var meshNode = new Assimp.Node(meshNodeName, aiScene.RootNode); meshNode.Transform = Assimp.Matrix4x4.Identity; aiScene.RootNode.Children.Add(meshNode); meshNode.MeshIndices.Add(aiScene.Meshes.Count - 1); return(aiScene); }
private static void AddAiMeshToPRM(PRMModel prm, ref int totalVerts, Assimp.Mesh aiMesh, Matrix4x4 nodeMat) { //Convert vertices for (int vertId = 0; vertId < aiMesh.VertexCount; vertId++) { PRMModel.PRMVert vert = new PRMModel.PRMVert(); var aiPos = aiMesh.Vertices[vertId]; var newPos = (new Vector3(aiPos.X, aiPos.Y, aiPos.Z)); vert.pos = Vector3.Transform(newPos, nodeMat) / 100; if (aiMesh.HasVertexColors(0)) { var aiColor = aiMesh.VertexColorChannels[0][vertId]; vert.color = new byte[] { (byte)(aiColor.B * 255), (byte)(aiColor.G * 255), (byte)(aiColor.R * 255), (byte)(aiColor.A * 255) }; } else { vert.color = new byte[4]; } if (aiMesh.HasNormals) { var aiNorm = aiMesh.Normals[vertId]; var normal = new Vector3(aiNorm.X, aiNorm.Y, aiNorm.Z); vert.normal = Vector3.TransformNormal(normal, nodeMat); } else { vert.normal = new Vector3(); } if (aiMesh.HasTextureCoords(0)) { var aiUV1 = aiMesh.TextureCoordinateChannels[0][vertId]; vert.uv1 = new Vector2(aiUV1.X, aiUV1.Y); } else { vert.uv1 = new Vector2(); } if (aiMesh.HasTextureCoords(1)) { var aiUV2 = aiMesh.TextureCoordinateChannels[1][vertId]; vert.uv2 = new Vector2(aiUV2.X, aiUV2.Y); } else { vert.uv2 = new Vector2(); } prm.vertices.Add(vert); } //Convert Faces foreach (var aiFace in aiMesh.Faces) { prm.faces.Add(new Vector3(aiFace.Indices[0] + totalVerts, aiFace.Indices[1] + totalVerts, aiFace.Indices[2] + totalVerts)); } //Keep count up to date for next potential loop totalVerts = prm.vertices.Count; }