private void _initMesh(Assimp.Mesh mesh) { Assimp.Vector3D Zero3D = new Assimp.Vector3D(0f); if (mesh.PrimitiveType == Assimp.PrimitiveType.Triangle) { // Populate the vertex attribute vectors for (int i = 0; i < mesh.VertexCount; i++) { Assimp.Vector3D pos = mesh.Vertices[i]; Assimp.Vector3D normal = mesh.Normals[i]; Assimp.Vector3D uv = mesh.HasTextureCoords(0) ? mesh.TextureCoordinateChannels[0][i] : Zero3D; positions.Add(new Vector3f(pos.X, pos.Y, pos.Z)); normals.Add(new Vector3f(normal.X, normal.Y, normal.Z)); uvs.Add(new Vector2f(uv.X, uv.Y)); } // Populate the index buffer for (int i = 0; i < mesh.FaceCount; i++) { Assimp.Face face = mesh.Faces[i]; // TODO: Find a suitable way to draw vertices... // Now only support triangulated faces indices.Add(face.Indices[0]); indices.Add(face.Indices[1]); indices.Add(face.Indices[2]); } } }
public Model Load(AssetManager assetManager, RenderContext renderContext, Stream stream, string sourcePath) { Scene scene = Importer.ImportFile(sourcePath, PostProcessSteps.Triangulate | PostProcessSteps.FlipUVs); if (scene == null || scene.SceneFlags.HasFlag(SceneFlags.Incomplete) || scene.RootNode == null) { throw new Exception("Assimp Error."); } var meshes = new List <Mesh>(); string directory = Path.GetDirectoryName(sourcePath); Texture2D LoadFromTextureSlot(TextureSlot textureSlot, TextureType textureType) { var texture = assetManager.Load <Texture2D>(Path.Combine(directory, textureSlot.FilePath)); texture.SetInfoFromTextureSlot(renderContext, ref textureSlot); texture.SetMinFilter(renderContext, TextureMinFilter.NearestMipmapLinear); return(texture); } List <Texture2D> LoadMaterialTextures(AssimpMaterial material, TextureType textureType) { List <Texture2D> textures = new List <Texture2D>(); for (int i = 0; i < material.GetMaterialTextureCount(textureType); i++) { material.GetMaterialTexture(textureType, i, out var textureSlot); if (textureSlot.FilePath != null) { if (textureSlot.FilePath.Contains("*")) { throw new InvalidOperationException(); } var texture = assetManager.Load <Texture2D>(Path.Combine(directory, textureSlot.FilePath)); texture.SetInfoFromTextureSlot(renderContext, ref textureSlot); textures.Add(texture); } } return(textures); } Mesh ProcessMesh(AssimpMesh mesh, System.Numerics.Matrix4x4 transformMatrix) { VertexPositionNormalTexture[] vertices = new VertexPositionNormalTexture[mesh.VertexCount]; List <uint> indices = new List <uint>(); // Process vertices for (int i = 0; i < mesh.VertexCount; i++) { Vector3D position = mesh.Vertices[i]; vertices[i].Position = Unsafe.As <Vector3D, Vector3>(ref position); Vector3D normal = mesh.Normals[i]; vertices[i].Normal = Unsafe.As <Vector3D, Vector3>(ref normal); if (mesh.HasTextureCoords(0)) { Vector3D texCoord = mesh.TextureCoordinateChannels[0][i]; vertices[i].TexCoord = new Vector2(texCoord.X, 1 - texCoord.Y); } } // Process indices for (int i = 0; i < mesh.FaceCount; i++) { AssimpFace face = mesh.Faces[i]; for (int j = 0; j < face.IndexCount; j++) { indices.Add((uint)face.Indices[j]); } } Mesh.MeshTextureInfo textures = new Mesh.MeshTextureInfo(); // Process Material if (mesh.MaterialIndex >= 0) { AssimpMaterial material = scene.Materials[mesh.MaterialIndex]; var texturezzz = material.GetAllMaterialTextures(); texturezzz = texturezzz.Where(x => x.FilePath != null).ToArray(); if (material.HasTextureDiffuse) { textures.Diffuse = LoadFromTextureSlot(material.TextureDiffuse, TextureType.Diffuse); } if (material.HasTextureSpecular) { textures.Specular = LoadFromTextureSlot(material.TextureSpecular, TextureType.Specular); } if (material.HasTextureLightMap) { textures.MetallicRoughness = LoadFromTextureSlot(material.TextureLightMap, TextureType.Lightmap); } } return(new Mesh(renderContext, vertices, indices.ToArray(), textures, transformMatrix)); } void ProcessNode(Node node, System.Numerics.Matrix4x4 transform) { var t = node.Transform; var thisTransform = Unsafe.As <Matrix4x4, System.Numerics.Matrix4x4>(ref t); // Process all of the node's meshes for (int i = 0; i < node.MeshCount; i++) { AssimpMesh mesh = scene.Meshes[node.MeshIndices[i]]; meshes.Add(ProcessMesh(mesh, transform * thisTransform)); } // Recurse for (int i = 0; i < node.ChildCount; i++) { ProcessNode(node.Children[i], transform * thisTransform); } } ProcessNode(scene.RootNode, System.Numerics.Matrix4x4.Identity); return(new Model(meshes.ToArray())); }
private static Ai.Mesh CreateAiMeshFromSubMesh(SubMesh subMesh, Mesh mesh, Object obj, Ai.Scene aiScene, string name) { var aiMesh = new Ai.Mesh(name, Ai.PrimitiveType.Triangle); if (mesh.Positions != null) { aiMesh.Vertices.Capacity = mesh.Positions.Length; aiMesh.Vertices.AddRange(mesh.Positions.Select(x => x.ToAssimp())); } if (mesh.Normals != null) { aiMesh.Normals.Capacity = mesh.Normals.Length; aiMesh.Normals.AddRange(mesh.Normals.Select(x => x.ToAssimp())); } for (int i = 0; i < 4; i++) { var texCoords = mesh.GetTexCoordsChannel(i); if (texCoords == null) { continue; } aiMesh.TextureCoordinateChannels[i].Capacity = texCoords.Length; aiMesh.TextureCoordinateChannels[i].AddRange(texCoords.Select(x => new Ai.Vector3D(x.ToAssimp(), 0))); } for (int i = 0; i < 2; i++) { var colors = mesh.GetColorsChannel(i); if (colors == null) { continue; } aiMesh.VertexColorChannels[i].Capacity = colors.Length; aiMesh.VertexColorChannels[i].AddRange(colors.Select(x => x.ToAssimp())); } if (mesh.BoneWeights != null) { for (int i = 0; i < subMesh.BoneIndices.Length; i++) { ushort boneIndex = subMesh.BoneIndices[i]; var bone = obj.Skin.Bones[boneIndex]; var aiBone = new Ai.Bone(); aiBone.Name = bone.Name; aiBone.OffsetMatrix = bone.InverseBindPoseMatrix.ToAssimpTransposed(); for (int j = 0; j < mesh.BoneWeights.Length; j++) { var boneWeight = mesh.BoneWeights[j]; if (boneWeight.Index1 == i) { aiBone.VertexWeights.Add(new Ai.VertexWeight(j, boneWeight.Weight1)); } if (boneWeight.Index2 == i) { aiBone.VertexWeights.Add(new Ai.VertexWeight(j, boneWeight.Weight2)); } if (boneWeight.Index3 == i) { aiBone.VertexWeights.Add(new Ai.VertexWeight(j, boneWeight.Weight3)); } if (boneWeight.Index4 == i) { aiBone.VertexWeights.Add(new Ai.VertexWeight(j, boneWeight.Weight4)); } } aiMesh.Bones.Add(aiBone); } } var triangles = subMesh.GetTriangles(); aiMesh.Faces.Capacity = triangles.Count; aiMesh.Faces.AddRange(triangles.Select(x => { var aiFace = new Ai.Face(); aiFace.Indices.Capacity = 3; aiFace.Indices.Add(( int )x.A); aiFace.Indices.Add(( int )x.B); aiFace.Indices.Add(( int )x.C); return(aiFace); })); var material = obj.Materials[( int )subMesh.MaterialIndex]; int materialIndex = aiScene.Materials.FindIndex(x => x.Name == material.Name + "+" + obj.Name); if (materialIndex == -1) { materialIndex = aiScene.Materials.FindIndex(x => x.Name == material.Name); } aiMesh.MaterialIndex = materialIndex; return(aiMesh); }
private static Ai.Node ConvertAiNodeFromMesh(Mesh mesh, Ai.Scene aiScene, bool appendTags = false) { var aiNode = new Ai.Node(mesh.Name); foreach (var subMesh in mesh.SubMeshes) { foreach (var indexTable in subMesh.IndexTables) { var aiSubMeshNode = new Ai.Node(subMesh.Name); var aiMesh = new Ai.Mesh(subMesh.Name, Ai.PrimitiveType.Triangle); var material = mesh.Materials[indexTable.MaterialIndex]; aiMesh.MaterialIndex = aiScene.Materials.FindIndex(x => x.Name.Equals(material.Name)); if (subMesh.Vertices != null) { aiMesh.Vertices.AddRange(subMesh.Vertices.Select( x => new Ai.Vector3D(x.X, x.Y, x.Z))); } if (subMesh.Normals != null) { aiMesh.Normals.AddRange(subMesh.Normals.Select( x => new Ai.Vector3D(x.X, x.Y, x.Z))); } if (subMesh.UVChannel1 != null) { aiMesh.TextureCoordinateChannels[0].AddRange(subMesh.UVChannel1.Select( x => new Ai.Vector3D(x.X, 1.0f - x.Y, 0.0f))); } if (subMesh.UVChannel2 != null) { aiMesh.TextureCoordinateChannels[1].AddRange(subMesh.UVChannel2.Select( x => new Ai.Vector3D(x.X, 1.0f - x.Y, 0.0f))); } // Why does 3DS Max go retarded when colors are exported? if (subMesh.Colors != null) { aiMesh.VertexColorChannels[0].AddRange(subMesh.Colors.Select( x => new Ai.Color4D(x.R, x.G, x.B, x.A))); } foreach (var triangle in indexTable.GetTriangles()) { var aiFace = new Ai.Face(); aiFace.Indices.Add(triangle.A); aiFace.Indices.Add(triangle.B); aiFace.Indices.Add(triangle.C); aiMesh.Faces.Add(aiFace); } if (indexTable.BoneIndices != null) { for (int i = 0; i < indexTable.BoneIndices.Length; i++) { int boneIndex = indexTable.BoneIndices[i]; var bone = mesh.Skin.Bones[boneIndex]; var aiBone = new Ai.Bone(); aiBone.Name = bone.Name; aiBone.OffsetMatrix = bone.Matrix.ToAssimp(); if (appendTags) { aiBone.Name = $"{aiBone.Name}{Tag.Create( "ID", bone.Id )}"; } for (int j = 0; j < subMesh.BoneWeights.Length; j++) { var weight = subMesh.BoneWeights[j]; if (weight.Index1 == i) { aiBone.VertexWeights.Add(new Ai.VertexWeight { VertexID = j, Weight = weight.Weight1 }); } if (weight.Index2 == i) { aiBone.VertexWeights.Add(new Ai.VertexWeight { VertexID = j, Weight = weight.Weight2 }); } if (weight.Index3 == i) { aiBone.VertexWeights.Add(new Ai.VertexWeight { VertexID = j, Weight = weight.Weight3 }); } if (weight.Index4 == i) { aiBone.VertexWeights.Add(new Ai.VertexWeight { VertexID = j, Weight = weight.Weight4 }); } } aiMesh.Bones.Add(aiBone); } } aiNode.Children.Add(aiSubMeshNode); aiSubMeshNode.MeshIndices.Add(aiScene.MeshCount); aiScene.Meshes.Add(aiMesh); } } if (appendTags) { aiNode.Name = $"{aiNode.Name}{Tag.Create( "ID", mesh.Id )}"; } return(aiNode); }
private Mesh processMesh(Assimp.Mesh mesh, Assimp.Scene scene) { // Data to fill List <Vertex> vertices = new List <Vertex>(); List <uint> indices = new List <uint>(); List <Texture> textures = new List <Texture>(); // Walk through each of the mesh's vertices for (int i = 0; i < mesh.VertexCount; i++) { Vertex vertex = new Vertex(); //Vertex3 vector = new Vertex3(); // We declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first. // Positions vertex.Position.X = mesh.Vertices[i].X; vertex.Position.Y = mesh.Vertices[i].Y; vertex.Position.Z = mesh.Vertices[i].Z; //vertex.Position = vector; // Normals vertex.Normal.X = mesh.Normals[i].X; vertex.Normal.Y = mesh.Normals[i].Y; vertex.Normal.Z = mesh.Normals[i].Z; //vertex.Normal = vector; // Texture Coordinates if (mesh.HasTextureCoords(0)) // Does the mesh contain texture coordinates? { Vertex2f vec; // A vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't // use models where a vertex can have multiple texture coordinates so we always take the first set (0). vec.x = mesh.TextureCoordinateChannels[0][i].X; vec.y = mesh.TextureCoordinateChannels[0][i].Y; vertex.TexCoords.X = vec.X; vertex.TexCoords.Y = vec.Y; } else { vertex.TexCoords.X = vertex.TexCoords.Y = 0; } vertices.Add(vertex); } // Now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices. for (int i = 0; i < mesh.FaceCount; i++) { Assimp.Face face = mesh.Faces[i]; // Retrieve all indices of the face and store them in the indices vector for (int j = 0; j < face.IndexCount; j++) { indices.Add((uint)face.Indices[j]); } } // Process materials if (mesh.MaterialIndex >= 0) { Assimp.Material material = scene.Materials[mesh.MaterialIndex]; // We assume a convention for sampler names in the shaders. Each diffuse texture should be named // as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER. // Same applies to other texture as the following list summarizes: // Diffuse: texture_diffuseN // Specular: texture_specularN // Normal: texture_normalN // 1. Diffuse maps List <Texture> diffuseMaps = this.loadMaterialTextures(material, TextureType.Diffuse, "texture_diffuse"); textures.InsertRange(textures.Count, diffuseMaps); // 2. Specular maps List <Texture> specularMaps = this.loadMaterialTextures(material, TextureType.Specular, "texture_specular"); textures.InsertRange(textures.Count, specularMaps); } // Return a mesh object created from the extracted mesh data return(new Mesh(vertices, indices, textures)); }
/// <summary> /// Constructs a new Mesh. /// </summary> /// <param name="mesh">Unmanaged AiMesh struct.</param> internal Mesh(AiMesh mesh) { _name = mesh.Name.GetString(); _primitiveType = mesh.PrimitiveTypes; _vertexCount = (int) mesh.NumVertices; _materialIndex = (int) mesh.MaterialIndex; //Load per-vertex arrays if(mesh.NumVertices > 0) { if(mesh.Vertices != IntPtr.Zero) { _vertices = MemoryHelper.MarshalArray<Vector3D>(mesh.Vertices, _vertexCount); } if(mesh.Normals != IntPtr.Zero) { _normals = MemoryHelper.MarshalArray<Vector3D>(mesh.Normals, _vertexCount); } if(mesh.Tangents != IntPtr.Zero) { _tangents = MemoryHelper.MarshalArray<Vector3D>(mesh.Tangents, _vertexCount); } if(mesh.BiTangents != IntPtr.Zero) { _bitangents = MemoryHelper.MarshalArray<Vector3D>(mesh.BiTangents, _vertexCount); } } //Load faces if(mesh.NumFaces > 0 && mesh.Faces != IntPtr.Zero) { AiFace[] faces = MemoryHelper.MarshalArray<AiFace>(mesh.Faces, (int) mesh.NumFaces); _faces = new Face[faces.Length]; for(int i = 0; i < _faces.Length; i++) { _faces[i] = new Face(faces[i]); } } //Load UVW components - this should match the texture coordinate channels uint[] components = mesh.NumUVComponents; if(components != null) { _texComponentNumber = new List<uint>(); foreach(uint num in components) { if(num > 0) { _texComponentNumber.Add(num); } } } //Load texture coordinate channels IntPtr[] texCoords = mesh.TextureCoords; if(texCoords != null) { _texCoords = new List<Vector3D[]>(); foreach(IntPtr texPtr in texCoords) { if(texPtr != IntPtr.Zero) { _texCoords.Add(MemoryHelper.MarshalArray<Vector3D>(texPtr, _vertexCount)); } } } //Load vertex color channels IntPtr[] vertexColors = mesh.Colors; if(vertexColors != null) { _colors = new List<Color4D[]>(); foreach(IntPtr colorPtr in vertexColors) { if(colorPtr != IntPtr.Zero) { _colors.Add(MemoryHelper.MarshalArray<Color4D>(colorPtr, _vertexCount)); } } } //Load bones if(mesh.NumBones > 0 && mesh.Bones != IntPtr.Zero) { AiBone[] bones = MemoryHelper.MarshalArray<AiBone>(mesh.Bones, (int) mesh.NumBones, true); _bones = new Bone[bones.Length]; for(int i = 0; i < _bones.Length; i++) { _bones[i] = new Bone(bones[i]); } } //Load anim meshes (attachment meshes) if(mesh.NumAnimMeshes > 0 && mesh.AnimMeshes != IntPtr.Zero) { AiAnimMesh[] animMeshes = MemoryHelper.MarshalArray<AiAnimMesh>(mesh.AnimMeshes, (int) mesh.NumAnimMeshes, true); _meshAttachments = new MeshAnimationAttachment[animMeshes.Length]; for(int i = 0; i < _meshAttachments.Length; i++) { _meshAttachments[i] = new MeshAnimationAttachment(animMeshes[i]); } } }
private Ai.Mesh ConvertGeometry(Scene scene, Node geometryNode, Geometry geometry) { var aiMesh = new Ai.Mesh(Ai.PrimitiveType.Triangle); if (geometry.Flags.HasFlag(GeometryFlags.HasMaterial)) { aiMesh.MaterialIndex = mAiScene.Materials.FindIndex(x => x.Name == AssimpConverterCommon.EscapeName(geometry.MaterialName)); } if (geometry.Flags.HasFlag(GeometryFlags.HasTriangles)) { foreach (var triangle in geometry.Triangles) { var aiFace = new Ai.Face(); aiFace.Indices.Add(( int )triangle.A); aiFace.Indices.Add(( int )triangle.B); aiFace.Indices.Add(( int )triangle.C); aiMesh.Faces.Add(aiFace); } } if (geometry.VertexAttributeFlags.HasFlag(VertexAttributeFlags.Position)) { foreach (var vertex in geometry.Vertices) { aiMesh.Vertices.Add(new Ai.Vector3D(vertex.X, vertex.Y, vertex.Z)); } } if (geometry.VertexAttributeFlags.HasFlag(VertexAttributeFlags.Normal)) { foreach (var normal in geometry.Normals) { aiMesh.Normals.Add(new Ai.Vector3D(normal.X, normal.Y, normal.Z)); } } if (geometry.VertexAttributeFlags.HasFlag(VertexAttributeFlags.Tangent)) { foreach (var tangent in geometry.Tangents) { aiMesh.Tangents.Add(new Ai.Vector3D(tangent.X, tangent.Y, tangent.Z)); } } if (geometry.VertexAttributeFlags.HasFlag(VertexAttributeFlags.Binormal)) { foreach (var binormal in geometry.Binormals) { aiMesh.BiTangents.Add(new Ai.Vector3D(binormal.X, binormal.Y, binormal.Z)); } } if (geometry.VertexAttributeFlags.HasFlag(VertexAttributeFlags.TexCoord0)) { foreach (var vertex in geometry.TexCoordsChannel0) { aiMesh.TextureCoordinateChannels[0].Add(new Ai.Vector3D(vertex.X, vertex.Y, 0)); } } if (geometry.VertexAttributeFlags.HasFlag(VertexAttributeFlags.TexCoord1)) { foreach (var vertex in geometry.TexCoordsChannel1) { aiMesh.TextureCoordinateChannels[1].Add(new Ai.Vector3D(vertex.X, vertex.Y, 0)); } } if (geometry.VertexAttributeFlags.HasFlag(VertexAttributeFlags.TexCoord2)) { foreach (var vertex in geometry.TexCoordsChannel2) { aiMesh.TextureCoordinateChannels[2].Add(new Ai.Vector3D(vertex.X, vertex.Y, 0)); } } /* todo: colors * if ( geometry.VertexAttributeFlags.HasFlag( VertexAttributeFlags.Color0 ) ) * { * foreach ( var color in geometry.ColorChannel0 ) * { * aiMesh.VertexColorChannels[0].Add( new Ai.Color4D( color. )) * } * } */ if (geometry.Flags.HasFlag(GeometryFlags.HasVertexWeights)) { var boneMap = new Dictionary <int, Ai.Bone>(); for (int i = 0; i < geometry.VertexWeights.Length; i++) { var vertexWeight = geometry.VertexWeights[i]; for (int j = 0; j < 4; j++) { var boneWeight = vertexWeight.Weights[j]; if (boneWeight == 0f) { continue; } var boneIndex = vertexWeight.Indices[j]; var nodeIndex = scene.BonePalette.BoneToNodeIndices[boneIndex]; if (!boneMap.ContainsKey(nodeIndex)) { var aiBone = new Ai.Bone(); var boneNode = scene.GetNode(nodeIndex); aiBone.Name = AssimpConverterCommon.EscapeName(boneNode.Name); aiBone.VertexWeights.Add(new Ai.VertexWeight(i, boneWeight)); Matrix4x4.Invert(geometryNode.WorldTransform, out Matrix4x4 invGeometryNodeWorldTransform); Matrix4x4.Invert(boneNode.WorldTransform * invGeometryNodeWorldTransform, out Matrix4x4 offsetMatrix); aiBone.OffsetMatrix = new Ai.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); boneMap[nodeIndex] = aiBone; } else { boneMap[nodeIndex].VertexWeights.Add(new Ai.VertexWeight(i, boneWeight)); } } } aiMesh.Bones.AddRange(boneMap.Values); } return(aiMesh); }
// Processa a malha lida pelo Assimp private Mesh ProcessMesh(Assimp.Mesh amesh, Assimp.Scene scene) { List <Vertex> vertices = new List <Vertex>(); List <uint> indices = new List <uint>(); List <Texture> textures = new List <Texture>(); Random r = new Random(); // Carrego pela malha do Assimp, a lista de vértice com a normal, UV (ST), tangente, bitangente for (int i = 0; i < amesh.VertexCount; i++) { Vertex vertex = new Vertex(); vertex.positionX = amesh.Vertices[i].X; vertex.positionY = amesh.Vertices[i].Y; vertex.positionZ = amesh.Vertices[i].Z; if (amesh.HasNormals) { vertex.normalX = amesh.Normals[i].X; vertex.normalY = amesh.Normals[i].Y; vertex.normalZ = amesh.Normals[i].Z; } if (amesh.HasTextureCoords(0)) { vertex.textureX = amesh.TextureCoordinateChannels[0][i].X; vertex.textureY = amesh.TextureCoordinateChannels[0][i].Y; vertex.bitangentX = amesh.BiTangents[i].X; vertex.bitangentY = amesh.BiTangents[i].Y; vertex.bitangentZ = amesh.BiTangents[i].Z; vertex.tangentX = amesh.Tangents[i].X; vertex.tangentY = amesh.Tangents[i].Y; vertex.tangentZ = amesh.Tangents[i].Z; } else { vertex.textureX = 0f; vertex.textureY = 0f; } vertex.colorA = (float)r.NextDouble(); vertex.colorR = (float)r.NextDouble(); vertex.colorB = (float)r.NextDouble(); vertex.colorG = 1f; vertices.Add(vertex); } // Carrega as informações das faces dos triâgulos, ou seja, informa quais vertices formam um triângulo da malha for (int i = 0; i < amesh.FaceCount; i++) { Assimp.Face face = amesh.Faces[i]; for (int j = 0; j < face.IndexCount; j++) { indices.Add((uint)face.Indices[j]); } } // Verifica se possui alguma textura ou arquivo mtl vinculado ao obj if (amesh.MaterialIndex >= 0) { Assimp.Material material = scene.Materials[amesh.MaterialIndex]; List <Texture> diffuseMaps = loadMaterialTextures(material, TextureType.Diffuse, "texture_diffuse"); textures.InsertRange(textures.Count, diffuseMaps); List <Texture> specularMaps = loadMaterialTextures(material, TextureType.Specular, "texture_specular"); textures.InsertRange(textures.Count, specularMaps); List <Texture> normalMaps = loadMaterialTextures(material, TextureType.Height, "texture_normal"); textures.InsertRange(textures.Count, normalMaps); } return(new Mesh(vertices, indices, textures)); }
/// <summary> /// Apply the EditMesh to a given Mesh. Call this only if you hold the monitor on /// the mesh or can otherwise ensure mutual exclusion. /// /// This can be called multiple times. The EditMesh can be re-used afterwards. /// /// Mesh name and material index are unchanged. /// </summary> /// <param name="mesh"></param> public void ApplyToMesh(Mesh mesh) { // Find subsets of vertices that are identical in all vertex components // and can be merged. To do this fast, we exploit the adjacency list in // the vertices. Each merge-able set must be a subset of already adjacent // vertices. Dictionary<EditVertex, int> indices = new Dictionary<EditVertex, int>(); Dictionary<int, EditVertex> reverseIndices = new Dictionary<int, EditVertex>(); int cursor = 0; foreach (EditVertex vert in Vertices) { if (indices.ContainsKey(vert)) { continue; } foreach (EditVertex adjacentVert in vert.AdjacentVertices) { if (adjacentVert == vert || vert.CanBeMergedWith(adjacentVert)) { indices[adjacentVert] = cursor; } } reverseIndices[cursor] = vert; ++cursor; } // Allocate output channels only if all input vertices set a component. bool hasNormals = Vertices.All(vert => vert.Normal.HasValue); bool hasTangentSpace = Vertices.All(vert => vert.Tangent.HasValue && vert.Bitangent.HasValue); bool[] hasTexCoords = Enumerable.Range(0, EditVertex.MaxTexcoordChannels). Select(i => Vertices.All(vert => vert.TexCoord[i].HasValue)).ToArray(); bool[] hasColors = Enumerable.Range(0, EditVertex.MaxColorChannels). Select(i => Vertices.All(vert => vert.Color[i].HasValue)).ToArray(); mesh.Vertices.Clear(); mesh.Normals.Clear(); mesh.Tangents.Clear(); mesh.BiTangents.Clear(); mesh.Vertices.Capacity = indices.Count; if (hasNormals) { mesh.Normals.Capacity = indices.Count; } if (hasTangentSpace) { mesh.Tangents.Capacity = indices.Count; mesh.BiTangents.Capacity = indices.Count; } for (var i = 0; i < EditVertex.MaxTexcoordChannels; ++i) { mesh.TextureCoordinateChannels[i].Clear(); mesh.TextureCoordinateChannels[i].Capacity = indices.Count; } for (var i = 0; i < EditVertex.MaxColorChannels; ++i) { mesh.VertexColorChannels[i].Clear(); mesh.VertexColorChannels[i].Capacity = indices.Count; } // Store unique indices. for (var i = 0; i < reverseIndices.Count; ++i) { var srcVert = reverseIndices[i]; mesh.Vertices.Add(srcVert.Position); if (hasNormals) { mesh.Normals.Add(srcVert.Normal.Value); } if (hasTangentSpace) { mesh.Tangents.Add(srcVert.Tangent.Value); mesh.BiTangents.Add(srcVert.Bitangent.Value); } for (var c = 0; c < EditVertex.MaxTexcoordChannels; ++c) { if (hasTexCoords[c]) { mesh.TextureCoordinateChannels[c].Add(srcVert.TexCoord[c].Value); } } for (var c = 0; c < EditVertex.MaxColorChannels; ++c) { if (hasColors[c]) { mesh.VertexColorChannels[c].Add(srcVert.Color[c].Value); } } } mesh.Faces.Clear(); mesh.Faces.Capacity = Faces.Count; foreach (var srcFace in Faces) { var face = new Face(); foreach (var srcVert in srcFace.Vertices) { face.Indices.Add(indices[srcVert]); } mesh.Faces.Add(face); } UpdateMeshPrimitiveTypeFlags(mesh); }