public static Color FromAssimp(Assimp.Color4D value) { return(new Color(( byte )(value.R * 255f), ( byte )(value.G * 255f), ( byte )(value.B * 255f), ( byte )(value.A * 255f))); }
static void BindUniform(ref Action bind, Shader shader, string name, Assimp.Color4D color) { var location = GL.GetUniformLocation(shader.Program, name); if (location >= 0) { bind += () => GL.Uniform4(location, color.R, color.G, color.B, color.A); } }
public static Color ToColor(this Assimp.Color4D color) { Color c; c.R = (byte)(color.R * 255); c.G = (byte)(color.G * 255); c.B = (byte)(color.B * 255); c.A = (byte)(color.A * 255); return(c); }
private Color[] ConvertColors(Assimp.Color4D[] colors) { Color[] data = new Color[colors.Length]; for (int i = 0; i < colors.Length; i++) { Assimp.Color4D color = colors[i]; data[i] = new Color(color.R, color.G, color.B, color.A); } return(data); }
internal static Color4 ToColor4(this Assimp.Color4D color) { Color4 c; c.Red = color.R; //(byte)(color.R * 255); c.Green = color.G; //(byte)(color.G * 255); c.Blue = color.B; //(byte)(color.B * 255); c.Alpha = color.A; //(byte)(color.A * 255); return(c); }
private static Color ConvertVertexColor(Assimp.Color4D clr, byte maxColorIntensity, byte maxAlpha) => new Color( (byte)Math.Min(255, clr.R * maxColorIntensity), (byte)Math.Min(255, clr.G * maxColorIntensity), (byte)Math.Min(255, clr.B * maxColorIntensity), (byte)Math.Min(255, clr.A * maxAlpha) );
private string colourToString(Assimp.Color4D colour) { return(colour.R.ToString() + "," + colour.G.ToString() + "," + colour.B.ToString() + "," + colour.A.ToString()); }
public void SetUpTev(bool hasTexture, bool hasVtxColor, int texIndex, string texName, Assimp.Material meshMat) { Flag = 1; // Set up channel control 0 to use vertex colors, if they're present if (hasVtxColor) { AddChannelControl(J3DColorChannelId.Color0, false, ColorSrc.Vertex, LightId.None, DiffuseFn.None, J3DAttenuationFn.None_0, ColorSrc.Register); AddChannelControl(J3DColorChannelId.Alpha0, false, ColorSrc.Vertex, LightId.None, DiffuseFn.None, J3DAttenuationFn.None_0, ColorSrc.Register); } else { AddChannelControl(J3DColorChannelId.Color0, false, ColorSrc.Register, LightId.None, DiffuseFn.Clamp, J3DAttenuationFn.Spec, ColorSrc.Register); AddChannelControl(J3DColorChannelId.Alpha0, false, ColorSrc.Register, LightId.None, DiffuseFn.Clamp, J3DAttenuationFn.Spec, ColorSrc.Register); } // These settings are common to all the configurations we can use TevStageParameters stageParams = new TevStageParameters { ColorInD = CombineColorInput.Zero, ColorOp = TevOp.Add, ColorBias = TevBias.Zero, ColorScale = TevScale.Scale_1, ColorClamp = true, ColorRegId = TevRegisterId.TevPrev, AlphaInD = CombineAlphaInput.Zero, AlphaOp = TevOp.Add, AlphaBias = TevBias.Zero, AlphaScale = TevScale.Scale_1, AlphaClamp = true, AlphaRegId = TevRegisterId.TevPrev }; if (hasTexture) { // Generate texture stuff AddTexGen(TexGenType.Matrix2x4, TexGenSrc.Tex0, Enums.TexMatrix.Identity); AddTexMatrix(TexGenType.Matrix3x4, 0, OpenTK.Vector3.Zero, OpenTK.Vector2.One, 0, OpenTK.Vector2.Zero, OpenTK.Matrix4.Identity); AddTevOrder(TexCoordId.TexCoord0, TexMapId.TexMap0, GXColorChannelId.Color0A0); AddTexIndex(texIndex); // Texture + Vertex Color if (hasVtxColor) { stageParams.ColorInA = CombineColorInput.Zero; stageParams.ColorInB = CombineColorInput.RasColor; stageParams.ColorInC = CombineColorInput.TexColor; stageParams.AlphaInA = CombineAlphaInput.Zero; stageParams.AlphaInB = CombineAlphaInput.RasAlpha; stageParams.AlphaInC = CombineAlphaInput.TexAlpha; } // Texture alone else { stageParams.ColorInA = CombineColorInput.TexColor; stageParams.ColorInB = CombineColorInput.Zero; stageParams.ColorInC = CombineColorInput.Zero; stageParams.AlphaInA = CombineAlphaInput.TexAlpha; stageParams.AlphaInB = CombineAlphaInput.Zero; stageParams.AlphaInC = CombineAlphaInput.Zero; } } // No texture! else { AddTevOrder(TexCoordId.Null, TexMapId.Null, GXColorChannelId.Color0A0); // No vertex colors either, so make sure there's a material color to use instead if (!hasVtxColor) { if (meshMat.HasColorDiffuse) // Use model's diffuse color { Assimp.Color4D color = meshMat.ColorDiffuse; MaterialColors[0] = new Color(color.R, color.G, color.B, color.A); } else // Otherwise default to white { MaterialColors[0] = new Color(1, 1, 1, 1); } AddChannelControl(J3DColorChannelId.Color0, false, ColorSrc.Register, LightId.None, DiffuseFn.None, J3DAttenuationFn.None_0, ColorSrc.Register); AddChannelControl(J3DColorChannelId.Alpha0, false, ColorSrc.Register, LightId.None, DiffuseFn.None, J3DAttenuationFn.None_0, ColorSrc.Register); } // Set up TEV to use the material color we just set stageParams.ColorInA = CombineColorInput.RasColor; stageParams.ColorInB = CombineColorInput.Zero; stageParams.ColorInC = CombineColorInput.Zero; stageParams.AlphaInA = CombineAlphaInput.RasAlpha; stageParams.AlphaInB = CombineAlphaInput.Zero; stageParams.AlphaInC = CombineAlphaInput.Zero; } AddTevStage(stageParams); }
public static Assimp.Scene ToAssimpScene(RwClumpNode clumpNode) { // Scene var aiScene = new Assimp.Scene(); // RootNode var rootFrame = clumpNode.FrameList[0]; var aiRootNode = new Assimp.Node("RootNode", null); aiRootNode.Transform = new Assimp.Matrix4x4(rootFrame.Transform.M11, rootFrame.Transform.M21, rootFrame.Transform.M31, rootFrame.Transform.M41, rootFrame.Transform.M12, rootFrame.Transform.M22, rootFrame.Transform.M32, rootFrame.Transform.M42, rootFrame.Transform.M13, rootFrame.Transform.M23, rootFrame.Transform.M33, rootFrame.Transform.M43, rootFrame.Transform.M14, rootFrame.Transform.M24, rootFrame.Transform.M34, rootFrame.Transform.M44); aiScene.RootNode = aiRootNode; for (int i = 1; i < clumpNode.FrameList.Count; i++) { var frame = clumpNode.FrameList[i]; var frameName = "_" + frame.HAnimFrameExtensionNode.NameId; Assimp.Node aiParentNode = null; if (frame.Parent != null) { string parentName = "RootNode"; if (frame.Parent.HasHAnimExtension) { parentName = "_" + frame.Parent.HAnimFrameExtensionNode.NameId; } aiParentNode = aiRootNode.FindNode(parentName); } var aiNode = new Assimp.Node(frameName, aiParentNode); aiNode.Transform = new Assimp.Matrix4x4(frame.Transform.M11, frame.Transform.M21, frame.Transform.M31, frame.Transform.M41, frame.Transform.M12, frame.Transform.M22, frame.Transform.M32, frame.Transform.M42, frame.Transform.M13, frame.Transform.M23, frame.Transform.M33, frame.Transform.M43, frame.Transform.M14, frame.Transform.M24, frame.Transform.M34, frame.Transform.M44); aiParentNode.Children.Add(aiNode); } // Meshes, Materials for (int atomicIndex = 0; atomicIndex < clumpNode.Atomics.Count; atomicIndex++) { var atomic = clumpNode.Atomics[atomicIndex]; var geometry = clumpNode.GeometryList[atomic.GeometryIndex]; var frame = clumpNode.FrameList[atomic.FrameIndex]; var aiNodeName = $"Atomic{atomicIndex}"; var aiNode = new Assimp.Node(aiNodeName, aiScene.RootNode); var frameWorldTransform = frame.WorldTransform; aiNode.Transform = new Assimp.Matrix4x4(frameWorldTransform.M11, frameWorldTransform.M21, frameWorldTransform.M31, frameWorldTransform.M41, frameWorldTransform.M12, frameWorldTransform.M22, frameWorldTransform.M32, frameWorldTransform.M42, frameWorldTransform.M13, frameWorldTransform.M23, frameWorldTransform.M33, frameWorldTransform.M43, frameWorldTransform.M14, frameWorldTransform.M24, frameWorldTransform.M34, frameWorldTransform.M44); aiScene.RootNode.Children.Add(aiNode); bool hasVertexWeights = geometry.SkinNode != null; for (int meshIndex = 0; meshIndex < geometry.MeshListNode.MaterialMeshes.Length; meshIndex++) { var mesh = geometry.MeshListNode.MaterialMeshes[meshIndex]; var aiMesh = new Assimp.Mesh($"Atomic{atomicIndex}_Geometry{atomic.GeometryIndex}_Mesh{meshIndex}", Assimp.PrimitiveType.Triangle); // get triangle list indices int[] indices; if (geometry.MeshListNode.PrimitiveType == RwPrimitiveType.TriangleList) { indices = mesh.Indices; } else { indices = MeshUtilities.ToTriangleList(mesh.Indices, false); } // Faces for (int i = 0; i < indices.Length; i += 3) { var faceIndices = new[] { i, i + 1, i + 2 }; var aiFace = new Assimp.Face(faceIndices); aiMesh.Faces.Add(aiFace); } // TextureCoordinateChannels, VertexColorChannels, Vertices, MaterialIndex, Normals for (int triIdx = 0; triIdx < indices.Length; triIdx += 3) { for (int triVertIdx = 0; triVertIdx < 3; triVertIdx++) { int vertexIndex = indices[triIdx + triVertIdx]; // TextureCoordinateChannels if (geometry.HasTextureCoordinates) { for (int channelIdx = 0; channelIdx < geometry.TextureCoordinateChannelCount; channelIdx++) { var textureCoordinate = geometry.TextureCoordinateChannels[channelIdx][vertexIndex]; var aiTextureCoordinate = new Assimp.Vector3D(textureCoordinate.X, textureCoordinate.Y, 0f); aiMesh.TextureCoordinateChannels[channelIdx].Add(aiTextureCoordinate); } } // VertexColorChannels if (geometry.HasColors) { var color = geometry.Colors[vertexIndex]; var aiColor = new Assimp.Color4D(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f); aiMesh.VertexColorChannels[0].Add(aiColor); } // Vertices if (geometry.HasVertices) { var vertex = geometry.Vertices[vertexIndex]; var aiVertex = new Assimp.Vector3D(vertex.X, vertex.Y, vertex.Z); aiMesh.Vertices.Add(aiVertex); } // Normals if (geometry.HasNormals) { var normal = geometry.Normals[vertexIndex]; var aiNormal = new Assimp.Vector3D(normal.X, normal.Y, normal.Z); aiMesh.Normals.Add(aiNormal); } } } // Bones if (hasVertexWeights) { var skinNode = geometry.SkinNode; var aiBoneMap = new Dictionary <int, Assimp.Bone>(); for (int i = 0; i < indices.Length; i++) { var vertexIndex = indices[i]; int realVertexIndex = i; for (int j = 0; j < 4; j++) { var boneIndex = skinNode.VertexBoneIndices[vertexIndex][j]; var boneWeight = skinNode.VertexBoneWeights[vertexIndex][j]; if (boneWeight == 0.0f) { continue; } if (!aiBoneMap.Keys.Contains(boneIndex)) { var aiBone = new Assimp.Bone(); var boneFrame = clumpNode.FrameList.GetFrameByHierarchyIndex(boneIndex); aiBone.Name = boneFrame.HasHAnimExtension ? "_" + boneFrame.HAnimFrameExtensionNode.NameId : "RootNode"; aiBone.VertexWeights.Add(new Assimp.VertexWeight(realVertexIndex, boneWeight)); Matrix4x4.Invert(frame.WorldTransform, out Matrix4x4 invertedFrameWorldTransform); Matrix4x4.Invert(boneFrame.WorldTransform * invertedFrameWorldTransform, out Matrix4x4 offsetMatrix); aiBone.OffsetMatrix = new Assimp.Matrix4x4(offsetMatrix.M11, offsetMatrix.M21, offsetMatrix.M31, offsetMatrix.M41, offsetMatrix.M12, offsetMatrix.M22, offsetMatrix.M32, offsetMatrix.M42, offsetMatrix.M13, offsetMatrix.M23, offsetMatrix.M33, offsetMatrix.M43, offsetMatrix.M14, offsetMatrix.M24, offsetMatrix.M34, offsetMatrix.M44); aiBoneMap[boneIndex] = aiBone; } if (!aiBoneMap[boneIndex].VertexWeights.Any(x => x.VertexID == realVertexIndex)) { aiBoneMap[boneIndex].VertexWeights.Add(new Assimp.VertexWeight(realVertexIndex, boneWeight)); } } } aiMesh.Bones.AddRange(aiBoneMap.Values); } else { var aiBone = new Assimp.Bone(); // Name aiBone.Name = frame.HasHAnimExtension ? "_" + frame.HAnimFrameExtensionNode.NameId : "RootNode"; // VertexWeights for (int i = 0; i < aiMesh.Vertices.Count; i++) { var aiVertexWeight = new Assimp.VertexWeight(i, 1f); aiBone.VertexWeights.Add(aiVertexWeight); } // OffsetMatrix /* * Matrix4x4.Invert( frame.WorldTransform, out Matrix4x4 offsetMatrix ); * aiBone.OffsetMatrix = new Assimp.Matrix4x4( offsetMatrix.M11, offsetMatrix.M21, offsetMatrix.M31, offsetMatrix.M41, * offsetMatrix.M12, offsetMatrix.M22, offsetMatrix.M32, offsetMatrix.M42, * offsetMatrix.M13, offsetMatrix.M23, offsetMatrix.M33, offsetMatrix.M43, * offsetMatrix.M14, offsetMatrix.M24, offsetMatrix.M34, offsetMatrix.M44 ); */ aiBone.OffsetMatrix = Assimp.Matrix4x4.Identity; aiMesh.Bones.Add(aiBone); } var material = geometry.Materials[mesh.MaterialIndex]; var aiMaterial = new Assimp.Material(); if (material.IsTextured) { // TextureDiffuse var texture = material.TextureReferenceNode; aiMaterial.TextureDiffuse = new Assimp.TextureSlot( texture.Name + ".png", Assimp.TextureType.Diffuse, 0, Assimp.TextureMapping.FromUV, 0, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); } // Name aiMaterial.Name = material.Name ?? $"Geometry{atomic.GeometryIndex}_Material{mesh.MaterialIndex}"; if (material.IsTextured && material.Name == null) { aiMaterial.Name = material.TextureReferenceNode.Name; } aiMaterial.ShadingMode = Assimp.ShadingMode.Phong; // Add mesh to meshes aiScene.Meshes.Add(aiMesh); // Add material to materials aiScene.Materials.Add(aiMaterial); // MaterialIndex aiMesh.MaterialIndex = aiScene.Materials.Count - 1; // Add mesh index to node aiNode.MeshIndices.Add(aiScene.Meshes.Count - 1); } } return(aiScene); }
public static XNAV4 ToXnaVector(this Assimp.Color4D v) { return(new XNAV4(v.R, v.G, v.B, v.A)); }
private Vector3 ConvertColorToVector3(Assimp.Color4D color) { return(new Vector3(color.R, color.G, color.B)); }
private Color ConvertColor(Assimp.Color4D color) { return(new Color(color.R, color.G, color.B, color.A)); }
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); }
public static Assimp.Scene AssimpExport(string filePath, AquaObject aqp, AquaNode aqn) { if (aqp is NGSAquaObject) { //NGS aqps will give lots of isolated vertices if we don't handle them //Since we're not actually altering the data so much as rearranging references, we can just do this aqp = aqp.Clone(); aqp.splitVSETPerMesh(); } 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[aqn.nodeList.Count]; //Set up root node var root = aqn.nodeList[0]; var aiRootNode = new Assimp.Node("RootNode", null); aiRootNode.Transform = Assimp.Matrix4x4.Identity; aiScene.RootNode = aiRootNode; //Assign bones for (int i = 0; i < aqn.nodeList.Count; i++) { var bn = aqn.nodeList[i]; Assimp.Node parentNode; var parentTfm = Matrix4x4.Identity; if (bn.parentId == -1) { parentNode = aiRootNode; } else { parentNode = boneArray[bn.parentId]; var pn = aqn.nodeList[bn.parentId]; parentTfm = new Matrix4x4(pn.m1.X, pn.m1.Y, pn.m1.Z, pn.m1.W, pn.m2.X, pn.m2.Y, pn.m2.Z, pn.m2.W, pn.m3.X, pn.m3.Y, pn.m3.Z, pn.m3.W, pn.m4.X * 100, pn.m4.Y * 100, pn.m4.Z * 100, pn.m4.W); } var aiNode = new Assimp.Node($"({i})" + bn.boneName.GetString(), parentNode); //Use inverse bind matrix as base var bnMat = new Matrix4x4(bn.m1.X, bn.m1.Y, bn.m1.Z, bn.m1.W, bn.m2.X, bn.m2.Y, bn.m2.Z, bn.m2.W, bn.m3.X, bn.m3.Y, bn.m3.Z, bn.m3.W, bn.m4.X * 100, bn.m4.Y * 100, bn.m4.Z * 100, bn.m4.W); Matrix4x4.Invert(bnMat, out bnMat); //Get local transform aiNode.Transform = GetAssimpMat4(bnMat * parentTfm); parentNode.Children.Add(aiNode); boneArray[i] = aiNode; } foreach (AquaNode.NODO bn in aqn.nodoList) { var parentNodo = boneArray[bn.parentId]; var aiNode = new Assimp.Node(bn.boneName.GetString(), parentNodo); //NODOs are a bit more primitive. We need to generate the matrix for these ones. var matrix = Assimp.Matrix4x4.Identity; var rotation = Assimp.Matrix4x4.FromRotationX(bn.eulRot.X) * Assimp.Matrix4x4.FromRotationY(bn.eulRot.Y) * Assimp.Matrix4x4.FromRotationZ(bn.eulRot.Z); matrix *= rotation; matrix *= Assimp.Matrix4x4.FromTranslation(new Assimp.Vector3D(bn.pos.X * 100, bn.pos.Y * 100, bn.pos.Z * 100)); aiNode.Transform = matrix; parentNodo.Children.Add(aiNode); } //Assign meshes and materials foreach (AquaObject.MESH msh in aqp.meshList) { var vtxl = aqp.vtxlList[msh.vsetIndex]; //Mesh var aiMeshName = string.Format("mesh[{4}]_{0}_{1}_{2}_{3}_mesh", msh.mateIndex, msh.rendIndex, msh.shadIndex, msh.tsetIndex, aiScene.Meshes.Count); bool hasVertexWeights = aqp.vtxlList[msh.vsetIndex].vertWeightIndices.Count > 0; 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 //UVs will have dummied data to ensure that if the game arbitrarily writes them, they will still be exported back in the same order for (int vertId = 0; vertId < vtxl.vertPositions.Count; vertId++) { if (vtxl.vertPositions.Count > 0) { var pos = vtxl.vertPositions[vertId] * 100; aiMesh.Vertices.Add(new Assimp.Vector3D(pos.X, pos.Y, pos.Z)); } if (vtxl.vertNormals.Count > 0) { var nrm = vtxl.vertNormals[vertId]; aiMesh.Normals.Add(new Assimp.Vector3D(nrm.X, nrm.Y, nrm.Z)); } if (vtxl.vertColors.Count > 0) { //Vert colors are bgra var rawClr = vtxl.vertColors[vertId]; var clr = new Assimp.Color4D(clrToFloat(rawClr[2]), clrToFloat(rawClr[1]), clrToFloat(rawClr[0]), clrToFloat(rawClr[3])); aiMesh.VertexColorChannels[0].Add(clr); } if (vtxl.vertColor2s.Count > 0) { //Vert colors are bgra var rawClr = vtxl.vertColor2s[vertId]; var clr = new Assimp.Color4D(clrToFloat(rawClr[2]), clrToFloat(rawClr[1]), clrToFloat(rawClr[0]), clrToFloat(rawClr[3])); aiMesh.VertexColorChannels[1].Add(clr); } if (vtxl.uv1List.Count > 0) { var textureCoordinate = vtxl.uv1List[vertId]; var aiTextureCoordinate = new Assimp.Vector3D(textureCoordinate.X, textureCoordinate.Y, 0f); aiMesh.TextureCoordinateChannels[0].Add(aiTextureCoordinate); } else { var aiTextureCoordinate = new Assimp.Vector3D(0, 0, 0f); aiMesh.TextureCoordinateChannels[0].Add(aiTextureCoordinate); } if (vtxl.uv2List.Count > 0) { var textureCoordinate = vtxl.uv2List[vertId]; var aiTextureCoordinate = new Assimp.Vector3D(textureCoordinate.X, textureCoordinate.Y, 0f); aiMesh.TextureCoordinateChannels[1].Add(aiTextureCoordinate); } else { var aiTextureCoordinate = new Assimp.Vector3D(0, 0, 0f); aiMesh.TextureCoordinateChannels[1].Add(aiTextureCoordinate); } if (vtxl.uv3List.Count > 0) { var textureCoordinate = vtxl.uv3List[vertId]; var aiTextureCoordinate = new Assimp.Vector3D(textureCoordinate.X, textureCoordinate.Y, 0f); aiMesh.TextureCoordinateChannels[2].Add(aiTextureCoordinate); } else { var aiTextureCoordinate = new Assimp.Vector3D(0, 0, 0f); aiMesh.TextureCoordinateChannels[2].Add(aiTextureCoordinate); } if (vtxl.uv4List.Count > 0) { var textureCoordinate = vtxl.uv4List[vertId]; var aiTextureCoordinate = new Assimp.Vector3D(textureCoordinate.X, textureCoordinate.Y, 0f); aiMesh.TextureCoordinateChannels[3].Add(aiTextureCoordinate); } else { var aiTextureCoordinate = new Assimp.Vector3D(0, 0, 0f); aiMesh.TextureCoordinateChannels[3].Add(aiTextureCoordinate); } if (vtxl.vert0x22.Count > 0) { var textureCoordinate = vtxl.vert0x22[vertId]; var aiTextureCoordinate = new Assimp.Vector3D(uvShortToFloat(textureCoordinate[0]), uvShortToFloat(textureCoordinate[1]), 0f); aiMesh.TextureCoordinateChannels[4].Add(aiTextureCoordinate); } else { var aiTextureCoordinate = new Assimp.Vector3D(0, 0, 0f); aiMesh.TextureCoordinateChannels[4].Add(aiTextureCoordinate); } if (vtxl.vert0x23.Count > 0) { var textureCoordinate = vtxl.vert0x23[vertId]; var aiTextureCoordinate = new Assimp.Vector3D(uvShortToFloat(textureCoordinate[0]), uvShortToFloat(textureCoordinate[1]), 0f); aiMesh.TextureCoordinateChannels[5].Add(aiTextureCoordinate); } else { var aiTextureCoordinate = new Assimp.Vector3D(0, 0, 0f); aiMesh.TextureCoordinateChannels[5].Add(aiTextureCoordinate); } if (vtxl.vert0x24.Count > 0) { var textureCoordinate = vtxl.vert0x24[vertId]; var aiTextureCoordinate = new Assimp.Vector3D(uvShortToFloat(textureCoordinate[0]), uvShortToFloat(textureCoordinate[1]), 0f); aiMesh.TextureCoordinateChannels[6].Add(aiTextureCoordinate); } else { var aiTextureCoordinate = new Assimp.Vector3D(0, 0, 0f); aiMesh.TextureCoordinateChannels[6].Add(aiTextureCoordinate); } if (vtxl.vert0x25.Count > 0) { var textureCoordinate = vtxl.vert0x25[vertId]; var aiTextureCoordinate = new Assimp.Vector3D(uvShortToFloat(textureCoordinate[0]), uvShortToFloat(textureCoordinate[1]), 0f); aiMesh.TextureCoordinateChannels[7].Add(aiTextureCoordinate); } else { var aiTextureCoordinate = new Assimp.Vector3D(0, 0, 0f); aiMesh.TextureCoordinateChannels[7].Add(aiTextureCoordinate); } } //Assimp Bones - Assimp likes to store vertex weights in bones and bones references in meshes if (hasVertexWeights) { //Get bone palette List <uint> bonePalette; if (aqp.objc.bonePaletteOffset > 0) { bonePalette = aqp.bonePalette; } else { bonePalette = new List <uint>(); for (int bn = 0; bn < vtxl.bonePalette.Count; bn++) { bonePalette.Add(vtxl.bonePalette[bn]); } } var aiBoneMap = new Dictionary <int, Assimp.Bone>(); //Iterate through vertices for (int vertId = 0; vertId < vtxl.vertWeightIndices.Count; vertId++) { var boneIndices = vtxl.vertWeightIndices[vertId]; var boneWeights = Vector4ToFloatArray(vtxl.vertWeights[vertId]); //Iterate through weights for (int wt = 0; wt < 4; wt++) { var boneIndex = boneIndices[wt]; var boneWeight = boneWeights[wt]; if (boneWeight == 0.0f) { continue; } if (!aiBoneMap.Keys.Contains(boneIndex)) { var aiBone = new Assimp.Bone(); var aqnBone = boneArray[bonePalette[boneIndex]]; var rawBone = aqn.nodeList[(int)bonePalette[boneIndex]]; aiBone.Name = $"({bonePalette[boneIndex]})" + rawBone.boneName.GetString(); aiBone.VertexWeights.Add(new Assimp.VertexWeight(vertId, boneWeight)); var invTransform = new Assimp.Matrix4x4(rawBone.m1.X, rawBone.m2.X, rawBone.m3.X, rawBone.m4.X, rawBone.m1.Y, rawBone.m2.Y, rawBone.m3.Y, rawBone.m4.Y, rawBone.m1.Z, rawBone.m2.Z, rawBone.m3.Z, rawBone.m4.Z, rawBone.m1.W, rawBone.m2.W, rawBone.m3.W, rawBone.m4.W); aiBone.OffsetMatrix = invTransform; aiBoneMap[boneIndex] = aiBone; } if (!aiBoneMap[boneIndex].VertexWeights.Any(x => x.VertexID == vertId)) { aiBoneMap[boneIndex].VertexWeights.Add(new Assimp.VertexWeight(vertId, boneWeight)); } } } //Add the bones to the mesh aiMesh.Bones.AddRange(aiBoneMap.Values); } else //Handle rigid meshes { var aiBone = new Assimp.Bone(); var aqnBone = boneArray[msh.baseMeshNodeId]; // Name aiBone.Name = aqnBone.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 aqp.strips[msh.vsetIndex].GetTriangles(true)) { aiMesh.Faces.Add(new Assimp.Face(new int[] { (int)face.X, (int)face.Y, (int)face.Z })); } //Material var mat = aqp.mateList[msh.mateIndex]; var shaderSet = AquaObjectMethods.GetShaderNames(aqp, msh.shadIndex); var textureSet = AquaObjectMethods.GetTexListNames(aqp, msh.tsetIndex); Assimp.Material mate = new Assimp.Material(); mate.ColorDiffuse = new Assimp.Color4D(mat.diffuseRGBA.X, mat.diffuseRGBA.Y, mat.diffuseRGBA.Z, mat.diffuseRGBA.W); if (mat.alphaType.GetString().Equals("add")) { mate.BlendMode = Assimp.BlendMode.Additive; } mate.Name = "|[]{}~`!@#$%^&*;:'\"?><,./(" + shaderSet[0] + "," + shaderSet[1] + ")" + "{" + mat.alphaType.GetString() + "}" + mat.matName.GetString(); //Set textures - PSO2 Texture slots are NOT consistent and depend entirely on the selected shader. As such, slots will be somewhat arbitrary after albedo/diffuse for (int i = 0; i < textureSet.Count; i++) { switch (i) { case 0: mate.TextureDiffuse = new Assimp.TextureSlot( textureSet[i], Assimp.TextureType.Diffuse, i, Assimp.TextureMapping.FromUV, aqp.tstaList[aqp.tsetList[msh.tsetIndex].tstaTexIDs[i]].modelUVSet, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); break; case 1: mate.TextureSpecular = new Assimp.TextureSlot( textureSet[i], Assimp.TextureType.Specular, i, Assimp.TextureMapping.FromUV, aqp.tstaList[aqp.tsetList[msh.tsetIndex].tstaTexIDs[i]].modelUVSet, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); break; case 2: mate.TextureNormal = new Assimp.TextureSlot( textureSet[i], Assimp.TextureType.Normals, i, Assimp.TextureMapping.FromUV, aqp.tstaList[aqp.tsetList[msh.tsetIndex].tstaTexIDs[i]].modelUVSet, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); break; case 3: mate.TextureLightMap = new Assimp.TextureSlot( textureSet[i], Assimp.TextureType.Lightmap, i, Assimp.TextureMapping.FromUV, aqp.tstaList[aqp.tsetList[msh.tsetIndex].tstaTexIDs[i]].modelUVSet, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); break; case 4: mate.TextureDisplacement = new Assimp.TextureSlot( textureSet[i], Assimp.TextureType.Displacement, i, Assimp.TextureMapping.FromUV, aqp.tstaList[aqp.tsetList[msh.tsetIndex].tstaTexIDs[i]].modelUVSet, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); break; case 5: mate.TextureOpacity = new Assimp.TextureSlot( textureSet[i], Assimp.TextureType.Opacity, i, Assimp.TextureMapping.FromUV, aqp.tstaList[aqp.tsetList[msh.tsetIndex].tstaTexIDs[i]].modelUVSet, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); break; case 6: mate.TextureHeight = new Assimp.TextureSlot( textureSet[i], Assimp.TextureType.Height, i, Assimp.TextureMapping.FromUV, aqp.tstaList[aqp.tsetList[msh.tsetIndex].tstaTexIDs[i]].modelUVSet, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); break; case 7: mate.TextureEmissive = new Assimp.TextureSlot( textureSet[i], Assimp.TextureType.Emissive, i, Assimp.TextureMapping.FromUV, aqp.tstaList[aqp.tsetList[msh.tsetIndex].tstaTexIDs[i]].modelUVSet, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); break; case 8: mate.TextureAmbient = new Assimp.TextureSlot( textureSet[i], Assimp.TextureType.Ambient, i, Assimp.TextureMapping.FromUV, aqp.tstaList[aqp.tsetList[msh.tsetIndex].tstaTexIDs[i]].modelUVSet, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); break; case 9: mate.TextureReflection = new Assimp.TextureSlot( textureSet[i], Assimp.TextureType.Reflection, i, Assimp.TextureMapping.FromUV, aqp.tstaList[aqp.tsetList[msh.tsetIndex].tstaTexIDs[i]].modelUVSet, 0, Assimp.TextureOperation.Add, Assimp.TextureWrapMode.Wrap, Assimp.TextureWrapMode.Wrap, 0); break; default: break; } } mate.ShadingMode = Assimp.ShadingMode.Phong; var meshNodeName = string.Format("mesh[{4}]_{0}_{1}_{2}_{3}#{4}#{5}", msh.mateIndex, msh.rendIndex, msh.shadIndex, msh.tsetIndex, aiScene.Meshes.Count, msh.baseMeshNodeId, msh.baseMeshDummyId); // 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); }