private void SetMaterialColor(Material material, Assimp.Material assimpMat) { if (assimpMat.HasColorDiffuse) { material.SetParameter("DiffuseColor", ConvertColor(assimpMat.ColorDiffuse)); } }
public MAT3(Assimp.Scene scene, TEX1 textures, SHP1 shapes) { InitLists(); for (int i = 0; i < scene.MeshCount; i++) { Assimp.Material meshMat = scene.Materials[scene.Meshes[i].MaterialIndex]; Materials.Material bmdMaterial = new Material(); bool hasVtxColor0 = shapes.Shapes[i].AttributeData.CheckAttribute(GXVertexAttribute.Color0); int texIndex = -1; if (meshMat.HasTextureDiffuse) { string texName = Path.GetFileNameWithoutExtension(meshMat.TextureDiffuse.FilePath); texIndex = textures.Textures.IndexOf(textures[texName]); } bmdMaterial.SetUpTev(meshMat.HasTextureDiffuse, hasVtxColor0, texIndex); m_Materials.Add(bmdMaterial); m_RemapIndices.Add(i); m_MaterialNames.Add(meshMat.Name); } FillMaterialDataBlocks(); }
private void SetLitMaterialColors(Material material, Assimp.Material assimpMat) { if (assimpMat.HasColorAmbient) { material.SetParameter("MatAmbient", ConvertColorToVector3(assimpMat.ColorAmbient)); } if (assimpMat.HasColorDiffuse) { material.SetParameter("MatDiffuse", ConvertColorToVector3(assimpMat.ColorDiffuse)); } if (assimpMat.HasColorEmissive) { material.SetParameter("MatEmissive", ConvertColorToVector3(assimpMat.ColorEmissive)); } if (assimpMat.HasColorSpecular) { material.SetParameter("MatSpecular", ConvertColorToVector3(assimpMat.ColorSpecular)); } if (assimpMat.HasShininessStrength) { material.SetParameter("Shininess", assimpMat.ShininessStrength); } if (assimpMat.HasOpacity) { material.SetParameter("Alpha", assimpMat.Opacity); } }
private void exportToAssimp(object sender, EventArgs e) { Debug.WriteLine("Exporting to assimp"); if (RenderState.rootObject != null) { Assimp.AssimpContext ctx = new Assimp.AssimpContext(); Dictionary <int, int> meshImportStatus = new Dictionary <int, int>(); Assimp.Scene aScene = new Assimp.Scene(); Assimp.Node rootNode = RenderState.rootObject.assimpExport(ref aScene, ref meshImportStatus); aScene.RootNode = rootNode; //add a single material for now Assimp.Material aMat = new Assimp.Material(); aMat.Name = "testMaterial"; aScene.Materials.Add(aMat); Assimp.ExportFormatDescription[] supported_formats = ctx.GetSupportedExportFormats(); //Assimp.Scene blenderScene = ctx.ImportFile("SimpleSkin.gltf"); //ctx.ExportFile(blenderScene, "SimpleSkin.glb", "glb2"); try { ctx.ExportFile(aScene, "test.glb", "glb2"); //ctx.ExportFile(aScene, "test.fbx", "fbx"); } catch (Exception ex) { Console.WriteLine(ex.Message); } } }
public void FillScene(Assimp.Scene scene, TEX1 textures, string fileDir) { textures.DumpTextures(fileDir); foreach (Material mat in m_Materials) { Assimp.Material assMat = new Assimp.Material(); if (mat.TextureIndices[0] != -1) { int texIndex = mat.TextureIndices[0]; //texIndex = m_TexRemapBlock[texIndex]; string texPath = Path.Combine(fileDir, textures[texIndex].Name + ".png"); Assimp.TextureSlot tex = new Assimp.TextureSlot(texPath, Assimp.TextureType.Diffuse, 0, Assimp.TextureMapping.FromUV, 0, 1.0f, Assimp.TextureOperation.Add, textures[texIndex].WrapS.ToAssImpWrapMode(), textures[texIndex].WrapT.ToAssImpWrapMode(), 0); assMat.AddMaterialTexture(ref tex); } if (mat.MaterialColors[0] != null) { assMat.ColorDiffuse = mat.MaterialColors[0].Value.ToColor4D(); } if (mat.AmbientColors[0] != null) { assMat.ColorAmbient = mat.AmbientColors[0].Value.ToColor4D(); } scene.Materials.Add(assMat); } }
public static Onyx3D.DefaultMaterial ToOnyx3D(this Assimp.Material material) { Onyx3D.DefaultMaterial newMaterial = new Onyx3D.DefaultMaterial(); // TODO - Load the material; return(newMaterial); }
protected Assimp.Material CreateMaterial(Color diffuse, Color specular, Color ambient, string textureName, bool clampU, bool clampV, bool flipU, bool flipV, bool useAlpha) { var textureFilePath = textureName != null ? $"{textureName}.png" : null; var aiMaterial = new Assimp.Material { Name = FormatMaterialName(textureName, Scene.Materials.Count(x => x.TextureDiffuse.FilePath == textureFilePath)), ColorDiffuse = ToAssimp(diffuse), ColorSpecular = ToAssimp(specular), ColorAmbient = ToAssimp(ambient), Shininess = 0, ShininessStrength = 0, Reflectivity = 0, }; if (textureName != null) { aiMaterial.TextureDiffuse = new Assimp.TextureSlot { TextureType = Assimp.TextureType.Diffuse, FilePath = textureFilePath, WrapModeU = clampU ? Assimp.TextureWrapMode.Clamp : flipU ? Assimp.TextureWrapMode.Mirror : Assimp.TextureWrapMode.Wrap, WrapModeV = clampV ? Assimp.TextureWrapMode.Clamp : flipV ? Assimp.TextureWrapMode.Mirror : Assimp.TextureWrapMode.Wrap, }; if (useAlpha) { aiMaterial.TextureOpacity = new Assimp.TextureSlot { TextureType = Assimp.TextureType.Opacity, FilePath = textureFilePath, WrapModeU = clampU ? Assimp.TextureWrapMode.Clamp : flipU ? Assimp.TextureWrapMode.Mirror : Assimp.TextureWrapMode.Wrap, WrapModeV = clampV ? Assimp.TextureWrapMode.Clamp : flipV ? Assimp.TextureWrapMode.Mirror : Assimp.TextureWrapMode.Wrap, }; } } return(aiMaterial); }
private void SetMaterialTexture(Material material, Assimp.Material assimpMat) { Assimp.TextureSlot diffuseMap = assimpMat.GetTexture(Assimp.TextureType.Diffuse, 0); if (!String.IsNullOrEmpty(diffuseMap.FilePath)) { Texture diffuse; try { diffuse = m_content.LoadRelativeTo <Texture2D>(diffuseMap.FilePath, m_modelResource);// m_content.Load<Texture2D>(diffuseMap.FilePath); material.SetParameter("DiffuseMap", diffuse); } catch { // diffuse = m_content.Load<Texture2D>("notexture.tebo"); } } }
public Assimp.Scene ConvertToScene(Model model, Config config) { // Start building scene var aiScene = AssimpHelper.CreateDefaultScene(); // Convert materials for (var i = 0; i < model.Materials.Count; i++) { var material = model.Materials[i]; var aiMaterial = new Assimp.Material { Name = FormatMaterialName(material, i) }; if (material.TextureId != null) { aiMaterial.TextureDiffuse = new Assimp.TextureSlot { TextureType = Assimp.TextureType.Diffuse, FilePath = Path.Combine("textures", FormatTextureName(material.TextureId.Value)) }; } aiScene.Materials.Add(aiMaterial); } // Convert nodes var aiNodeLookup = new Dictionary <Node, Assimp.Node>(); for (var i = 0; i < model.Nodes.Count; i++) { var node = model.Nodes[i]; var aiNode = new Assimp.Node(FormatNodeName(node, i), node.Parent != null ? aiNodeLookup[node.Parent] : aiScene.RootNode); aiNodeLookup[node] = aiNode; aiNode.Transform = node.Transform.ToAssimp(); if (node.Geometry != null) { ConvertMeshList(node.Geometry.Meshes, node, i, model.Nodes, aiScene, aiNode); if (node.Geometry.TranslucentMeshes != null) { ConvertMeshList(node.Geometry.TranslucentMeshes, node, i, model.Nodes, aiScene, aiNode); } } aiNode.Parent.Children.Add(aiNode); } return(aiScene); }
public RwMaterialListNode(RwNode parent, Assimp.Material material) : base(RwNodeId.RwMaterialListNode, parent) { mMaterials = new List <RwMaterial>(); string textureName = null; if (material.HasTextureDiffuse) { textureName = Path.GetFileNameWithoutExtension(material.TextureDiffuse.FilePath); } mMaterials.Add(new RwMaterial(material.Name, textureName, this)); mStructNode = new RwMaterialListStructNode(this); }
internal Texture2D Load(Assimp.Material mat) { var tex = mat.TextureDiffuse; if (string.IsNullOrEmpty(tex.FilePath)) { return(null); } if (Path.IsPathRooted(tex.FilePath)) { Debug.LogError("Skipping loading texture from: " + tex.FilePath); return(null); } Texture2D tex1; if (textures == null) { textures = new Dictionary <string, Texture2D>(); } if (textures.TryGetValue(tex.FilePath, out tex1)) { return(tex1); } try { int tex_index; if (tex.FilePath.StartsWith("*") && tex.FilePath.Length > 1 && int.TryParse(tex.FilePath.Substring(1), out tex_index)) { tex1 = BuildTextureFromInternal(tex_index); } else { tex1 = BuildTextureFromExternal(tex.FilePath); } } catch (Exception e) { Debug.LogException(e); tex1 = null; } textures[tex.FilePath] = tex1; return(tex1); }
private void SetMaterialRenderStates(Material material, Assimp.Material assimpMat) { if (assimpMat.HasTwoSided && assimpMat.HasWireFrame) { // material.SetRenderState(RasterizerState.CullNoneWireframe); } else if (assimpMat.HasWireFrame) { if (m_wireframeOneSidedRS == null) { m_wireframeOneSidedRS = new RasterizerState(); m_wireframeOneSidedRS.Fill = FillMode.WireFrame; m_wireframeOneSidedRS.BindRenderState(); } // material.SetRenderState(m_wireframeOneSidedRS); } else if (assimpMat.HasTwoSided) { if (m_twoSidedRS == null) { m_twoSidedRS = new RasterizerState(); m_twoSidedRS.Cull = CullMode.None; m_twoSidedRS.BindRenderState(); } // material.SetRenderState(m_twoSidedRS); } if (assimpMat.HasBlendMode) { if (assimpMat.BlendMode == Assimp.BlendMode.Additive) { // material.SetRenderState(BlendState.AdditiveBlend); } else { // material.SetRenderState(BlendState.AlphaBlendNonPremultiplied); } } }
private TextureProvider[] InitTextures(Assimp.Scene aiScene, string filename) { var textureProviders = new TextureProvider[aiScene.MaterialCount]; // Extract the directory part from the file name string directory = new FileInfo(filename).DirectoryName; // Initialize the materials for (uint i = 0; i < aiScene.MaterialCount; i++) { Assimp.Material material = aiScene.Materials[i]; if (material.GetTextureCount(Assimp.TextureType.Diffuse) > 0) { Assimp.TextureSlot slot = material.GetTexture(Assimp.TextureType.Diffuse, 0); string fullname = Path.Combine(directory, slot.FilePath); var provider = new TextureProvider(fullname); textureProviders[i] = provider; } } return(textureProviders); }
public MAT3(Assimp.Scene scene, TEX1 textures) { InitLists(); foreach (Assimp.Mesh mesh in scene.Meshes) { Assimp.Material meshMat = scene.Materials[mesh.MaterialIndex]; Materials.Material bmdMaterial = new Material(); if (meshMat.HasTextureDiffuse) { bmdMaterial.AddTexGen(TexGenType.Matrix2x4, TexGenSrc.TexCoord0, Materials.Enums.TexMatrix.Identity); bmdMaterial.AddTexMatrix(TexGenType.Matrix3x4, 0, OpenTK.Vector3.Zero, OpenTK.Vector2.One, 0, OpenTK.Vector2.Zero, OpenTK.Matrix4.Identity); string texName = System.IO.Path.GetFileNameWithoutExtension(meshMat.TextureDiffuse.FilePath); bmdMaterial.AddTexIndex(textures.Textures.IndexOf(textures[texName])); bmdMaterial.AddTevStage(SetUpTevStageParametersForTexture()); } } FillMaterialDataBlocks(); }
private void SetNormalMapMaterialTextures(Material material, Assimp.Material assimpMat) { Assimp.TextureSlot diffuseMap = assimpMat.GetTexture(Assimp.TextureType.Diffuse, 0); Assimp.TextureSlot normalMap = assimpMat.GetTexture(Assimp.TextureType.Normals, 0); Assimp.TextureSlot specularMap = assimpMat.GetTexture(Assimp.TextureType.Specular, 0); if (!String.IsNullOrEmpty(diffuseMap.FilePath)) { Texture diffuse; try { diffuse = m_content.LoadRelativeTo <Texture2D>(diffuseMap.FilePath, m_modelResource); //m_content.Load<Texture2D>(diffuseMap.FilePath); material.SetParameter("DiffuseMap", diffuse); } catch { // diffuse = m_content.Load<Texture2D>("notexture.tebo"); } } if (!String.IsNullOrEmpty(normalMap.FilePath)) { try { Texture normal = m_content.LoadRelativeTo <Texture2D>(normalMap.FilePath, m_modelResource); //m_content.Load<Texture2D>(normalMap.FilePath); material.SetParameter("NormalMap", normal); } catch { //Default normal map? } } if (!String.IsNullOrEmpty(specularMap.FilePath)) { try { Texture specular = m_content.LoadRelativeTo <Texture2D>(specularMap.FilePath, m_modelResource);//m_content.Load<Texture2D>(specularMap.FilePath); material.SetParameter("SpecularMap", specular); } catch { //Default specular map? } } }
public void ExportCollada(string filepath) { var aiScene = AssimpHelper.CreateDefaultScene(); foreach (var geometry in Geometries) { for (var meshIndex = 0; meshIndex < geometry.Meshes.Count; meshIndex++) { var aiMeshNode = new Assimp.Node(geometry.Meshes.Count > 1 ? $"{geometry.Name}_mesh_{meshIndex}" : geometry.Name, aiScene.RootNode); aiScene.RootNode.Children.Add(aiMeshNode); var mesh = geometry.Meshes[meshIndex]; var aiMesh = new Assimp.Mesh(); var aiMaterial = new Assimp.Material { Name = mesh.Material.Name, //ColorDiffuse = AssimpHelper.ToAssimp( mesh.Material.Diffuse ), //ColorSpecular = AssimpHelper.ToAssimp( mesh.Material.Specular ), //ColorAmbient = AssimpHelper.ToAssimp( mesh.Material.Ambient ), Shininess = 0, ShininessStrength = 0, Reflectivity = 0, TextureDiffuse = new Assimp.TextureSlot { TextureType = Assimp.TextureType.Diffuse, FilePath = mesh.Material.TextureName, WrapModeU = Assimp.TextureWrapMode.Wrap, WrapModeV = Assimp.TextureWrapMode.Wrap, } }; aiMesh.MaterialIndex = aiScene.MaterialCount; aiScene.Materials.Add(aiMaterial); foreach (var vertex in mesh.Vertices) { aiMesh.Vertices.Add(AssimpHelper.ToAssimp(vertex.Position)); aiMesh.Normals.Add(AssimpHelper.ToAssimp(vertex.Normal)); aiMesh.VertexColorChannels[0].Add(AssimpHelper.ToAssimp(vertex.Color)); aiMesh.TextureCoordinateChannels[0].Add(AssimpHelper.ToAssimp(vertex.UV)); } for (int i = 0; i < mesh.Indices.Length; i += 3) { var aiFace = new Assimp.Face(); for (int j = 0; j < 3; j++) { aiFace.Indices.Add(mesh.Indices[i + j]); } aiMesh.Faces.Add(aiFace); } aiMeshNode.MeshIndices.Add(aiScene.MeshCount); aiScene.Meshes.Add(aiMesh); } } AssimpHelper.ExportCollada(aiScene, filepath); }
Material ConvertMaterial(string path, Assimp.Material aiMaterial, bool hasTangent) { Shader shader = null; BlendFlags blendType = BlendFlags.Solid; if (hasTangent) { if (aiMaterial.HasTextureOpacity) { blendType = BlendFlags.AlphaTest; shader = Resources.Instance.Load <Shader>("Shaders/LitAlphaTest.shader"); } else if (aiMaterial.Opacity < 1) { blendType = BlendFlags.AlphaBlend; shader = Resources.Instance.Load <Shader>("Shaders/LitParticle.shader"); } else { shader = Resources.Instance.Load <Shader>("Shaders/LitSolid.shader"); } } else { shader = Resources.Instance.Load <Shader>("Shaders/Basic.shader"); } Material material = new Material(shader); material.Name = aiMaterial.Name; material.BlendType = blendType; if (aiMaterial.HasTextureDiffuse) { string texPath = FileUtil.CombinePath(path, aiMaterial.TextureDiffuse.FilePath); Texture tex = Resources.Instance.Load <Texture>(texPath); if (tex != null) { material.SetTexture("DiffMap", tex); } else { int idx = texPath.LastIndexOfAny(new[] { '\\', '/' }); if (idx != -1) { texPath = texPath.Substring(idx + 1); } tex = Resources.Instance.Load <Texture>(texPath.Replace(".ktx", "_bc3_unorm.ktx")); if (tex != null) { material.SetTexture("DiffMap", tex); } } } else { if (aiMaterial.HasColorDiffuse) { Color c = new Color(aiMaterial.ColorDiffuse[0], aiMaterial.ColorDiffuse[1], aiMaterial.ColorDiffuse[2], aiMaterial.ColorDiffuse[3] * aiMaterial.Opacity); material.SetTexture("DiffMap", Texture.CreateByColor(c)); material.SetShaderParameter("diffuse", c); } else { material.SetTexture("DiffMap", Texture.White); } } if (aiMaterial.HasTextureNormal) { string texPath = FileUtil.CombinePath(path, aiMaterial.TextureNormal.FilePath); Texture tex = Resources.Instance.Load <Texture>(texPath); if (tex != null) { material.SetTexture("NormalMap", tex); } else { tex = Resources.Instance.Load <Texture>(texPath.Replace(".ktx", "_bc3_unorm.ktx")); if (tex != null) { material.SetTexture("NormalMap", tex); } } } else { material.SetTexture("NormalMap", Texture.Blue); } if (aiMaterial.HasTextureSpecular) { string texPath = FileUtil.CombinePath(path, aiMaterial.TextureSpecular.FilePath); Texture tex = Resources.Instance.Load <Texture>(texPath); if (tex != null) { material.SetTexture("SpecMap", tex); } else { tex = Resources.Instance.Load <Texture>(texPath.Replace(".ktx", "_bc3_unorm.ktx")); if (tex != null) { material.SetTexture("SpecMap", tex); } } } else { if (aiMaterial.HasColorSpecular) { Color c = new Color(aiMaterial.ColorSpecular[0], aiMaterial.ColorSpecular[1], aiMaterial.ColorSpecular[2], aiMaterial.Shininess / 255.0f); material.SetTexture("SpecMap", Texture.CreateByColor(c)); material.SetShaderParameter("specular", c); } else { material.SetTexture("SpecMap", Texture.Black); } } return(material); }
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); }
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 void ParseMaterials(Assimp.Scene scene) { Assimp.Material[] materials = scene.Materials; //Should always have the default material at least m_materials = new Material[materials.Length]; bool hasNormals = false; bool hasTangentBasis = false; bool hasTexCoords = false; bool hasVertexColors = false; //TODO: Incorporate user-defined materials for (int i = 0; i < materials.Length; i++) { Assimp.Material material = materials[i]; Material mat; hasNormals = false; hasTangentBasis = false; hasTexCoords = false; hasVertexColors = false; foreach (MeshMaterialInfo info in m_meshMatInfo) { if (info.MaterialIndex == i) { if (info.HasNormals) { hasNormals = true; } if (info.HasTangentBasis) { hasTangentBasis = true; } if (info.HasTexCoords) { hasTexCoords = true; } if (info.HasVertexColors) { hasVertexColors = true; } } } if (hasNormals && m_loaderParams.PreferLitMaterials) { if (hasTexCoords && hasTangentBasis) { if (hasVertexColors) { mat = m_content.Load <Material>("NormalMapVertColor.tem").Clone(); } else { mat = m_content.Load <Material>("NormalMap.tem").Clone(); } SetNormalMapMaterialTextures(mat, material); //Normal map textures + diffuse } else { if (hasTexCoords) { if (hasVertexColors) { mat = m_content.Load <Material>("LitBasicVertColorTexture.tem"); } else { mat = m_content.Load <Material>("LitBasicTexture.tem").Clone(); } SetMaterialTexture(mat, material); //Difuse texture } else { if (hasVertexColors) { mat = m_content.Load <Material>("LitBasicVertColor.tem").Clone(); } else { mat = m_content.Load <Material>("LitBasicColor.tem").Clone(); } } } SetLitMaterialColors(mat, material); //Common lit color parameters } else { if (hasTexCoords) { if (hasVertexColors) { mat = m_content.Load <Material>("BasicVertColorTexture.tem"); } else { mat = m_content.Load <Material>("BasicTexture.tem").Clone(); } SetMaterialTexture(mat, material); //Difuse texture } else { if (hasVertexColors) { mat = m_content.Load <Material>("BasicVertColor.tem").Clone(); } else { mat = m_content.Load <Material>("BasicColor.tem").Clone(); } } SetMaterialColor(mat, material); //Common unlit color parameters } SetMaterialRenderStates(mat, material); if (material.HasName) { mat.Name = material.Name; } m_materials[i] = mat; } }
internal static Mesh3D LoadFromFileSUB(Device device, Assimp.Scene pScene, InputElement[] ieLayout, List <SceneObject> meshArr) { string sourceTextures = ConfigurationSettings.AppSettings["SourceTextures"]; int iVBufferSize = 0; int iIBufferSize = 0; foreach (SceneObject so in meshArr) { iVBufferSize += (int)so.pMesh.VertexCount; iIBufferSize += (int)so.pMesh.FaceCount * 3; } MeshInputElements10.sNormalMesh[] tVertex = new MeshInputElements10.sNormalMesh[iVBufferSize]; //short[] tIndex = new short[iIBufferSize]; uint[] tIndex = new uint[iIBufferSize]; MeshAttributeRange[] tAttibutes = new MeshAttributeRange[meshArr.Count]; MeshNode[] nodes = new MeshNode[meshArr.Count]; string[] tTextures = new string[meshArr.Count]; // Monitor global poisition in the vertex, index and attribute buffers. int iAttribute = 0; int iBVertex = 0; int iBIndex = 0; int prevVertCount = 0; foreach (SceneObject so in meshArr) { MeshNode n = new MeshNode(); n.attributeId = iAttribute; n.nodeName = so.nodeName; n.parentNodeName = so.parentNodeName; n.transform = toDXMat(so.transform); nodes[iAttribute] = n; MeshAttributeRange pAttrib = new MeshAttributeRange(); pAttrib.Id = iAttribute; pAttrib.VertexStart = iBVertex; pAttrib.FaceStart = iBIndex / 3; Assimp.Material mat = pScene.Materials[so.pMesh.MaterialIndex]; if (mat.GetTextureCount(Assimp.TextureType.Diffuse) > 0) { string inputFilePath = mat.GetTexture(Assimp.TextureType.Diffuse, 0).FilePath.Replace("\\\\", "\\"); string inputFileName = Path.GetFileName(inputFilePath); string ext = Path.GetExtension(inputFileName); string subFolder = inputFilePath.Replace(sourceTextures, "").Split('\\')[1]; string diffOutFile = subFolder + "\\" + inputFileName.Replace(ext, ".dds"); tTextures[iAttribute] = diffOutFile; } // Copy verticies. int iMeshVerts = (int)so.pMesh.VertexCount; for (int iVertex = 0; iVertex < iMeshVerts; ++iVertex) { tVertex[iVertex + iBVertex] = getVert(so, iVertex); } // Increment the vertex count by the number of verticies we just looped over. iBVertex += iMeshVerts; // Copy indicies. int iMeshFaces = (int)so.pMesh.FaceCount; for (int iFace = 0; iFace < iMeshFaces; ++iFace) { uint[] tIndices = so.pMesh.Faces[iFace].Indices; //tIndex[iBIndex++] = Convert.ToInt16(tIndices[0] + (iAttribute == 0 ? 0 : prevVertCount)); //tIndex[iBIndex++] = Convert.ToInt16(tIndices[1] + (iAttribute == 0 ? 0 : prevVertCount)); //tIndex[iBIndex++] = Convert.ToInt16(tIndices[2] + (iAttribute == 0 ? 0 : prevVertCount)); tIndex[iBIndex++] = Convert.ToUInt32(tIndices[0] + (iAttribute == 0 ? 0 : prevVertCount)); tIndex[iBIndex++] = Convert.ToUInt32(tIndices[1] + (iAttribute == 0 ? 0 : prevVertCount)); tIndex[iBIndex++] = Convert.ToUInt32(tIndices[2] + (iAttribute == 0 ? 0 : prevVertCount)); } // Increment the face count by the number of faces we just looped over. prevVertCount += iMeshVerts; pAttrib.FaceCount = iMeshFaces; pAttrib.VertexCount = iMeshVerts; tAttibutes[iAttribute] = pAttrib; iAttribute++; } Mesh3D gm = new Mesh3D(); Mesh output = new Mesh(device, ieLayout, ieLayout[0].SemanticName, iVBufferSize, iIBufferSize / 3, MeshFlags.Has32BitIndices); output.SetAttributeTable(tAttibutes); DataStream verts = new DataStream(iVBufferSize * Marshal.SizeOf(typeof(MeshInputElements10.sNormalMesh)), true, true); //DataStream indicies = new DataStream(iIBufferSize * Marshal.SizeOf(typeof(short)), true, true); DataStream indicies = new DataStream(iIBufferSize * Marshal.SizeOf(typeof(uint)), true, true); verts.WriteRange(tVertex); indicies.WriteRange(tIndex); verts.Position = 0; indicies.Position = 0; output.SetVertexData(0, verts); output.SetIndexData(indicies, iIBufferSize); output.Commit(); verts.Dispose(); indicies.Dispose(); gm.attrTable = tAttibutes; gm.meshObj = output; gm.NumAttributes = meshArr.Count; gm.materials = tTextures; gm.nodes = nodes; if (pScene.HasAnimations) { gm.animations = new List <Mesh3DAnimation>(); foreach (Assimp.Animation a in pScene.Animations) { Mesh3DAnimation anim = new Mesh3DAnimation(); anim.animName = a.Name; anim.duration = a.DurationInTicks; anim.channels = new AnimationChannel[a.NodeAnimationChannelCount]; int x = 0; foreach (Assimp.NodeAnimationChannel c in a.NodeAnimationChannels) { if (c == null) { continue; } AnimationChannel ac = new AnimationChannel(); ac.nodeName = c.NodeName; ac.animKeys = new AnimationKey[c.RotationKeyCount]; for (int i = 0; i < c.PositionKeys.Length; i++) { double time = 0; SceneObject sObj = meshArr[0]; foreach (SceneObject so in meshArr) { if (so.nodeName == c.NodeName) { sObj = so; break; } } time = c.PositionKeys[i].Time; Matrix mat = toDXMat(sObj.transform); Vector3 rotationCenter = new Vector3(mat.M41, mat.M42, mat.M43); mat.Invert(); Vector3 pos = Vector3.TransformCoordinate(toDX(c.PositionKeys[i].Value), mat); Matrix matAnim = Matrix.Transformation(Vector3.Zero, Quaternion.Identity, new Vector3(1, 1, 1), rotationCenter, toDX(c.RotationKeys[i].Value), pos); AnimationKey ak = new AnimationKey(); ak.animMat = matAnim; ak.time = time; ac.animKeys[i] = ak; } anim.channels[x++] = ac; } gm.animations.Add(anim); } } return(gm); }
public void ExportToDae(string path) { var atomicSectors = new List <RwAtomicSector>(); void RecursivelyFindAtomicSectors(RwNode node) { if (node.Id == RwNodeId.RwAtomicSector) { atomicSectors.Add(( RwAtomicSector )node); } foreach (var child in node.Children) { RecursivelyFindAtomicSectors(child); } } RecursivelyFindAtomicSectors(this); if (atomicSectors.Count == 0) { return; } var aiScene = new Assimp.Scene(); for (var i = 0; i < Materials.Count; i++) { var material = Materials[i]; 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{i}"; if (material.IsTextured) { aiMaterial.Name = material.TextureReferenceNode.Name; } aiMaterial.ShadingMode = Assimp.ShadingMode.Phong; aiScene.Materials.Add(aiMaterial); } for (var i = 0; i < atomicSectors.Count; i++) { var atomicSector = atomicSectors[i]; var header = atomicSector.Header; if (header.VertexCount == 0) { continue; } foreach (var materialGroup in header.Triangles.GroupBy(x => x.MatId)) { var materialId = materialGroup.Key; var aiMesh = new Assimp.Mesh($"AtomicSector{i}_Material{materialId}", Assimp.PrimitiveType.Triangle); aiMesh.MaterialIndex = materialId; foreach (var triangle in materialGroup) { var pos1 = header.Positions[triangle.A]; var pos2 = header.Positions[triangle.B]; var pos3 = header.Positions[triangle.C]; aiMesh.Vertices.Add(new Assimp.Vector3D(pos1.X, pos1.Y, pos1.Z)); aiMesh.Vertices.Add(new Assimp.Vector3D(pos2.X, pos2.Y, pos2.Z)); aiMesh.Vertices.Add(new Assimp.Vector3D(pos3.X, pos3.Y, pos3.Z)); if (header.TextureCoordinateChannels != null && header.TextureCoordinateChannels.Length > 0) { var tex1 = header.TextureCoordinateChannels[0][triangle.A]; var tex2 = header.TextureCoordinateChannels[0][triangle.B]; var tex3 = header.TextureCoordinateChannels[0][triangle.C]; aiMesh.TextureCoordinateChannels[0].Add(new Assimp.Vector3D(tex1.X, 1f - tex1.Y, 0)); aiMesh.TextureCoordinateChannels[0].Add(new Assimp.Vector3D(tex2.X, 1f - tex2.Y, 0)); aiMesh.TextureCoordinateChannels[0].Add(new Assimp.Vector3D(tex3.X, 1f - tex3.Y, 0)); } if (header.Colors != null && header.Colors.Length > 0) { var color1 = header.Colors[triangle.A]; var color2 = header.Colors[triangle.B]; var color3 = header.Colors[triangle.C]; aiMesh.VertexColorChannels[0].Add(new Assimp.Color4D((float)color1.R / 255f, ( float )color1.G / 255f, ( float )color1.B / 255f, ( float )color1.A / 255f)); aiMesh.VertexColorChannels[0].Add(new Assimp.Color4D(( float )color2.R / 255f, ( float )color2.G / 255f, ( float )color2.B / 255f, ( float )color2.A / 255f)); aiMesh.VertexColorChannels[0].Add(new Assimp.Color4D(( float )color3.R / 255f, ( float )color3.G / 255f, ( float )color3.B / 255f, ( float )color3.A / 255f)); } } for (int j = 0; j < aiMesh.VertexCount; j += 3) { aiMesh.Faces.Add(new Assimp.Face(new[] { j, j + 1, j + 2 })); } aiScene.Meshes.Add(aiMesh); } } aiScene.RootNode = new Assimp.Node("RootNode"); aiScene.RootNode.MeshIndices.AddRange(Enumerable.Range(0, aiScene.Meshes.Count)); var aiContext = new Assimp.AssimpContext(); aiContext.ExportFile(aiScene, path, "collada", Assimp.PostProcessSteps.GenerateSmoothNormals | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.ImproveCacheLocality); }
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 Assimp.Scene CreateAssimpScene(this IGeometryModel model, Assimp.AssimpContext context, string formatId) { var scale = ModelViewerPlugin.Settings.GeometryScale; //either Assimp or collada has issues when there is a name conflict const string bonePrefix = "~"; const string geomPrefix = "-"; const string scenPrefix = "$"; var scene = new Assimp.Scene(); scene.RootNode = new Assimp.Node($"{scenPrefix}{model.Name}"); //Assimp is Y-up in inches by default - this forces it to export as Z-up in meters scene.RootNode.Transform = (CoordinateSystem.HaloCEX * ModelViewerPlugin.Settings.AssimpScale).ToAssimp4x4(); #region Nodes var allNodes = new List <Assimp.Node>(); foreach (var node in model.Nodes) { var result = new Assimp.Node($"{bonePrefix}{node.Name}"); var q = new System.Numerics.Quaternion(node.Rotation.X, node.Rotation.Y, node.Rotation.Z, node.Rotation.W); var mat = System.Numerics.Matrix4x4.CreateFromQuaternion(q); mat.Translation = new System.Numerics.Vector3(node.Position.X * scale, node.Position.Y * scale, node.Position.Z * scale); result.Transform = mat.ToAssimp4x4(); allNodes.Add(result); } for (int i = 0; i < model.Nodes.Count; i++) { var node = model.Nodes[i]; if (node.ParentIndex >= 0) { allNodes[node.ParentIndex].Children.Add(allNodes[i]); } else { scene.RootNode.Children.Add(allNodes[i]); } } #endregion var meshLookup = new List <int>(); #region Meshes for (int i = 0; i < model.Meshes.Count; i++) { var geom = model.Meshes[i]; if (geom.Submeshes.Count == 0) { meshLookup.Add(-1); continue; } meshLookup.Add(scene.MeshCount); foreach (var sub in geom.Submeshes) { var m = new Assimp.Mesh($"mesh{i:D3}"); var indices = geom.Indicies.Skip(sub.IndexStart).Take(sub.IndexLength); var minIndex = indices.Min(); var maxIndex = indices.Max(); var vertCount = maxIndex - minIndex + 1; if (geom.IndexFormat == IndexFormat.TriangleStrip) { indices = indices.Unstrip(); } indices = indices.Select(x => x - minIndex); var vertices = geom.Vertices.Skip(minIndex).Take(vertCount); if (geom.BoundsIndex >= 0) { vertices = vertices.Select(v => (IVertex) new CompressedVertex(v, model.Bounds[geom.BoundsIndex.Value])); } int vIndex = -1; var boneLookup = new Dictionary <int, Assimp.Bone>(); foreach (var v in vertices) { vIndex++; if (v.Position.Count > 0) { m.Vertices.Add(v.Position[0].ToAssimp3D(scale)); //some Halo shaders use position W as the colour alpha - add it to a colour channel to preserve it //also assimp appears to have issues exporting obj when a colour channel exists so only do this for collada if (formatId == "collada" && v.Color.Count == 0 && !float.IsNaN(v.Position[0].W)) { m.VertexColorChannels[0].Add(new Assimp.Color4D { R = v.Position[0].W }); } } if (v.Normal.Count > 0) { m.Normals.Add(v.Normal[0].ToAssimp3D()); } if (v.TexCoords.Count > 0) { m.TextureCoordinateChannels[0].Add(v.TexCoords[0].ToAssimpUV()); } if (geom.VertexWeights == VertexWeights.None && !geom.NodeIndex.HasValue) { continue; } #region Vertex Weights var weights = new List <Tuple <int, float> >(4); if (geom.NodeIndex.HasValue) { weights.Add(Tuple.Create <int, float>(geom.NodeIndex.Value, 1)); } else if (geom.VertexWeights == VertexWeights.Skinned) { var ind = v.BlendIndices[0]; var wt = v.BlendWeight[0]; if (wt.X > 0) { weights.Add(Tuple.Create((int)ind.X, wt.X)); } if (wt.Y > 0) { weights.Add(Tuple.Create((int)ind.Y, wt.Y)); } if (wt.Z > 0) { weights.Add(Tuple.Create((int)ind.Z, wt.Z)); } if (wt.W > 0) { weights.Add(Tuple.Create((int)ind.W, wt.W)); } } foreach (var val in weights) { Assimp.Bone b; if (boneLookup.ContainsKey(val.Item1)) { b = boneLookup[val.Item1]; } else { var t = model.Nodes[val.Item1].OffsetTransform; t.M41 *= scale; t.M42 *= scale; t.M43 *= scale; b = new Assimp.Bone { Name = bonePrefix + model.Nodes[val.Item1].Name, OffsetMatrix = t.ToAssimp4x4() }; m.Bones.Add(b); boneLookup.Add(val.Item1, b); } b.VertexWeights.Add(new Assimp.VertexWeight(vIndex, val.Item2)); } #endregion } m.SetIndices(indices.ToArray(), 3); m.MaterialIndex = sub.MaterialIndex; scene.Meshes.Add(m); } } #endregion #region Regions foreach (var reg in model.Regions) { var regNode = new Assimp.Node($"{geomPrefix}{reg.Name}"); foreach (var perm in reg.Permutations) { var meshStart = meshLookup[perm.MeshIndex]; if (meshStart < 0) { continue; } var permNode = new Assimp.Node($"{geomPrefix}{perm.Name}"); if (perm.TransformScale != 1 || !perm.Transform.IsIdentity) { permNode.Transform = Assimp.Matrix4x4.FromScaling(new Assimp.Vector3D(perm.TransformScale)) * perm.Transform.ToAssimp4x4(scale); } var meshCount = Enumerable.Range(perm.MeshIndex, perm.MeshCount).Sum(i => model.Meshes[i].Submeshes.Count); permNode.MeshIndices.AddRange(Enumerable.Range(meshStart, meshCount)); regNode.Children.Add(permNode); } if (regNode.ChildCount > 0) { scene.RootNode.Children.Add(regNode); } } #endregion #region Materials foreach (var mat in model.Materials) { var m = new Assimp.Material { Name = mat?.Name ?? "unused" }; //prevent max from making every material super shiny m.ColorEmissive = m.ColorReflective = m.ColorSpecular = new Assimp.Color4D(0, 0, 0, 1); m.ColorDiffuse = m.ColorTransparent = new Assimp.Color4D(1); //max only seems to care about diffuse var dif = mat?.Submaterials.FirstOrDefault(s => s.Usage == MaterialUsage.Diffuse); if (dif != null) { var suffix = dif.Bitmap.SubmapCount > 1 ? "[0]" : string.Empty; var filePath = $"{dif.Bitmap.Name}{suffix}.{ModelViewerPlugin.Settings.MaterialExtension}"; //collada spec says it requires URI formatting, and Assimp doesn't do it for us //for some reason "new Uri(filePath, UriKind.Relative)" doesnt change the slashes, have to use absolute uri if (formatId == FormatId.Collada) { filePath = new Uri("X:\\", UriKind.Absolute).MakeRelativeUri(new Uri(System.IO.Path.Combine("X:\\", filePath))).ToString(); } m.TextureDiffuse = new Assimp.TextureSlot { BlendFactor = 1, FilePath = filePath, TextureType = Assimp.TextureType.Diffuse }; } scene.Materials.Add(m); } #endregion return(scene); }
public MaterialBinding(Shader shader, ResourceManager resourceManager, Assimp.Material material) { if (shader == null) { throw new ArgumentNullException(nameof(shader)); } if (resourceManager == null) { throw new ArgumentNullException(nameof(resourceManager)); } resource = material ?? throw new ArgumentNullException(nameof(material)); bind = EmptyAction; if (resource.HasBumpScaling) { BindUniform(ref bind, shader, ShaderConstants.BumpScaling, resource.BumpScaling); } if (resource.HasColorAmbient) { BindUniform(ref bind, shader, ShaderConstants.ColorAmbient, material.ColorAmbient); } if (resource.HasColorDiffuse) { BindUniform(ref bind, shader, ShaderConstants.ColorDiffuse, material.ColorDiffuse); } if (resource.HasColorEmissive) { BindUniform(ref bind, shader, ShaderConstants.ColorEmissive, material.ColorEmissive); } if (resource.HasColorReflective) { BindUniform(ref bind, shader, ShaderConstants.ColorReflective, material.ColorReflective); } if (resource.HasColorSpecular) { BindUniform(ref bind, shader, ShaderConstants.ColorSpecular, material.ColorSpecular); } if (resource.HasColorTransparent) { BindUniform(ref bind, shader, ShaderConstants.ColorTransparent, material.ColorTransparent); } if (resource.HasOpacity) { BindUniform(ref bind, shader, ShaderConstants.Opacity, material.Opacity); } if (resource.HasReflectivity) { BindUniform(ref bind, shader, ShaderConstants.Reflectivity, material.Reflectivity); } if (resource.HasShininess) { BindUniform(ref bind, shader, ShaderConstants.Shininess, material.Shininess); } if (resource.HasShininessStrength) { BindUniform(ref bind, shader, ShaderConstants.ShininessStrength, material.ShininessStrength); } var textures = resource.GetAllMaterialTextures(); for (int i = 0; i < textures.Length; i++) { BindUniform(ref bind, shader, textures[i], i, resourceManager); } }
public static Assimp.Scene ToAssimpScene(RWScene scene) { Assimp.Scene aiScene = new Assimp.Scene(); int drawCallIdx = 0; int materialIdx = 0; int totalSplitIdx = 0; List<int> meshStartIndices = new List<int>(); foreach (RWDrawCall drawCall in scene.DrawCalls) { meshStartIndices.Add(totalSplitIdx); var mesh = scene.Meshes[drawCall.MeshIndex]; var node = scene.Nodes[drawCall.NodeIndex]; int splitIdx = 0; foreach (RWMeshMaterialSplit split in mesh.MaterialSplitData.MaterialSplits) { Assimp.Mesh aiMesh = new Assimp.Mesh(Assimp.PrimitiveType.Triangle); aiMesh.Name = string.Format("DrawCall{0}_Split{1}", drawCallIdx.ToString("00"), splitIdx.ToString("00")); aiMesh.MaterialIndex = split.MaterialIndex + materialIdx; // get split indices int[] indices = split.Indices; if (mesh.MaterialSplitData.PrimitiveType == RWPrimitiveType.TriangleStrip) indices = MeshUtilities.ToTriangleList(indices, true); // pos & nrm for (int i = 0; i < indices.Length; i++) { if (mesh.HasVertices) { var vert = Vector3.Transform(mesh.Vertices[indices[i]], node.WorldTransform); aiMesh.Vertices.Add(vert.ToAssimpVector3D()); } if (mesh.HasNormals) { var nrm = Vector3.TransformNormal(mesh.Normals[indices[i]], node.WorldTransform); aiMesh.Normals.Add(nrm.ToAssimpVector3D()); } } // tex coords if (mesh.HasTexCoords) { for (int i = 0; i < mesh.TextureCoordinateChannelCount; i++) { List<Assimp.Vector3D> texCoordChannel = new List<Assimp.Vector3D>(); for (int j = 0; j < indices.Length; j++) { texCoordChannel.Add(mesh.TextureCoordinateChannels[i][indices[j]].ToAssimpVector3D(0)); } aiMesh.TextureCoordinateChannels[i] = texCoordChannel; } } // colors if (mesh.HasColors) { List<Assimp.Color4D> vertColorChannel = new List<Assimp.Color4D>(); for (int i = 0; i < indices.Length; i++) { var color = mesh.Colors[indices[i]]; vertColorChannel.Add(new Assimp.Color4D(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f)); } aiMesh.VertexColorChannels[0] = vertColorChannel; } // generate temporary face indices int[] tempIndices = new int[aiMesh.VertexCount]; for (int i = 0; i < aiMesh.VertexCount; i++) tempIndices[i] = i; aiMesh.SetIndices(tempIndices, 3); // add the mesh to the list aiScene.Meshes.Add(aiMesh); splitIdx++; } totalSplitIdx += splitIdx; foreach (RWMaterial mat in mesh.Materials) { Assimp.Material aiMaterial = new Assimp.Material(); aiMaterial.AddProperty(new Assimp.MaterialProperty(Assimp.Unmanaged.AiMatKeys.NAME, "Material" + (materialIdx++).ToString("00"))); if (mat.IsTextured) { aiMaterial.AddProperty(new Assimp.MaterialProperty(Assimp.Unmanaged.AiMatKeys.TEXTURE_BASE, mat.TextureReference.ReferencedTextureName + ".png", Assimp.TextureType.Diffuse, 0)); } aiScene.Materials.Add(aiMaterial); } drawCallIdx++; } // store node lookup Dictionary<RWSceneNode, Assimp.Node> nodeLookup = new Dictionary<RWSceneNode, Assimp.Node>(); // first create the root node var rootNode = new Assimp.Node("SceneRoot"); rootNode.Transform = scene.Nodes[0].Transform.ToAssimpMatrix4x4(); nodeLookup.Add(scene.Nodes[0], rootNode); for (int i = 1; i < scene.Nodes.Count - 1; i++) { var node = scene.Nodes[i]; string name = node.BoneMetadata.BoneNameID.ToString(); var aiNode = new Assimp.Node(name); aiNode.Transform = node.Transform.ToAssimpMatrix4x4(); // get the associated meshes for this node var drawCalls = scene.DrawCalls.FindAll(dc => dc.NodeIndex == i); foreach (var drawCall in drawCalls) { for (int j = 0; j < scene.Meshes[drawCall.MeshIndex].MaterialCount; j++) { aiNode.MeshIndices.Add(meshStartIndices[scene.DrawCalls.IndexOf(drawCall)] + j); } } nodeLookup[node.Parent].Children.Add(aiNode); nodeLookup.Add(node, aiNode); } aiScene.RootNode = rootNode; return aiScene; }