public override Assimp.Node assimpExport(ref Assimp.Scene scn, ref Dictionary <int, int> meshImportStatus) { Assimp.Mesh amesh = new Assimp.Mesh(); Assimp.Node node; amesh.Name = name; int meshHash = meshVao.GetHashCode(); //TESTING if (scn.MeshCount > 20) { node = base.assimpExport(ref scn, ref meshImportStatus); return(node); } if (!meshImportStatus.ContainsKey(meshHash)) //if (false) { meshImportStatus[meshHash] = scn.MeshCount; int vertcount = metaData.vertrend_graphics - metaData.vertrstart_graphics + 1; MemoryStream vms = new MemoryStream(gobject.meshDataDict[metaData.Hash].vs_buffer); MemoryStream ims = new MemoryStream(gobject.meshDataDict[metaData.Hash].is_buffer); BinaryReader vbr = new BinaryReader(vms); BinaryReader ibr = new BinaryReader(ims); //Initialize Texture Component Channels if (gobject.bufInfo[1] != null) { List <Assimp.Vector3D> textureChannel = new List <Assimp.Vector3D>(); amesh.TextureCoordinateChannels.Append(textureChannel); amesh.UVComponentCount[0] = 2; } //Generate bones only for the joints related to the mesh Dictionary <int, Assimp.Bone> localJointDict = new Dictionary <int, Assimp.Bone>(); //Export Bone Structure if (Skinned) //if (false) { for (int i = 0; i < meshVao.BoneRemapIndicesCount; i++) { int joint_id = meshVao.BoneRemapIndices[i]; //Fetch name Joint relJoint = null; foreach (Joint jnt in parentScene.jointDict.Values) { if (jnt.jointIndex == joint_id) { relJoint = jnt; break; } } //Generate bone Assimp.Bone b = new Assimp.Bone(); if (relJoint != null) { b.Name = relJoint.name; b.OffsetMatrix = MathUtils.convertMatrix(relJoint.invBMat); } localJointDict[i] = b; amesh.Bones.Add(b); } } //Write geometry info vbr.BaseStream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < vertcount; i++) { Assimp.Vector3D v, vN; for (int j = 0; j < gobject.bufInfo.Count; j++) { bufInfo buf = gobject.bufInfo[j]; if (buf is null) { continue; } switch (buf.semantic) { case 0: //vPosition { switch (buf.type) { case VertexAttribPointerType.HalfFloat: uint v1 = vbr.ReadUInt16(); uint v2 = vbr.ReadUInt16(); uint v3 = vbr.ReadUInt16(); uint v4 = vbr.ReadUInt16(); //Transform vector with worldMatrix v = new Assimp.Vector3D(Utils.Half.decompress(v1), Utils.Half.decompress(v2), Utils.Half.decompress(v3)); break; case VertexAttribPointerType.Float: //This is used in my custom vbos float f1 = vbr.ReadSingle(); float f2 = vbr.ReadSingle(); float f3 = vbr.ReadSingle(); //Transform vector with worldMatrix v = new Assimp.Vector3D(f1, f2, f3); break; default: throw new Exception("Unimplemented Vertex Type"); } amesh.Vertices.Add(v); break; } case 1: //uvPosition { Assimp.Vector3D uv; uint v1 = vbr.ReadUInt16(); uint v2 = vbr.ReadUInt16(); uint v3 = vbr.ReadUInt16(); uint v4 = vbr.ReadUInt16(); //uint v4 = Convert.ToUInt16(vbr.ReadUInt16()); uv = new Assimp.Vector3D(Utils.Half.decompress(v1), Utils.Half.decompress(v2), 0.0f); amesh.TextureCoordinateChannels[0].Add(uv); //Add directly to the first channel break; } case 2: //nPosition case 3: //tPosition { switch (buf.type) { case (VertexAttribPointerType.Float): float f1, f2, f3; f1 = vbr.ReadSingle(); f2 = vbr.ReadSingle(); f3 = vbr.ReadSingle(); vN = new Assimp.Vector3D(f1, f2, f3); break; case (VertexAttribPointerType.HalfFloat): uint v1, v2, v3; v1 = vbr.ReadUInt16(); v2 = vbr.ReadUInt16(); v3 = vbr.ReadUInt16(); vN = new Assimp.Vector3D(Utils.Half.decompress(v1), Utils.Half.decompress(v2), Utils.Half.decompress(v3)); break; case (VertexAttribPointerType.Int2101010Rev): int i1, i2, i3; uint value; byte[] a32 = new byte[4]; a32 = vbr.ReadBytes(4); value = BitConverter.ToUInt32(a32, 0); //Convert Values i1 = _2sComplement.toInt((value >> 00) & 0x3FF, 10); i2 = _2sComplement.toInt((value >> 10) & 0x3FF, 10); i3 = _2sComplement.toInt((value >> 20) & 0x3FF, 10); //int i4 = _2sComplement.toInt((value >> 30) & 0x003, 10); float norm = (float)Math.Sqrt(i1 * i1 + i2 * i2 + i3 * i3); vN = new Assimp.Vector3D(Convert.ToSingle(i1) / norm, Convert.ToSingle(i2) / norm, Convert.ToSingle(i3) / norm); //Debug.WriteLine(vN); break; default: throw new Exception("UNIMPLEMENTED NORMAL TYPE. PLEASE REPORT"); } if (j == 2) { amesh.Normals.Add(vN); } else if (j == 3) { amesh.Tangents.Add(vN); amesh.BiTangents.Add(new Assimp.Vector3D(0.0f, 0.0f, 1.0f)); } break; } case 4: //bPosition vbr.ReadBytes(4); // skip break; case 5: //BlendIndices + BlendWeights { int[] joint_ids = new int[4]; float[] weights = new float[4]; for (int k = 0; k < 4; k++) { joint_ids[k] = vbr.ReadByte(); } for (int k = 0; k < 4; k++) { weights[k] = Utils.Half.decompress(vbr.ReadUInt16()); } if (Skinned) //if (false) { for (int k = 0; k < 4; k++) { int joint_id = joint_ids[k]; Assimp.VertexWeight vw = new Assimp.VertexWeight(); vw.VertexID = i; vw.Weight = weights[k]; localJointDict[joint_id].VertexWeights.Add(vw); } } break; } case 6: break; //Handled by 5 default: { throw new Exception("UNIMPLEMENTED BUF Info. PLEASE REPORT"); break; } } } } //Export Faces //Get indices ibr.BaseStream.Seek(0, SeekOrigin.Begin); bool start = false; int fstart = 0; for (int i = 0; i < metaData.batchcount / 3; i++) { int f1, f2, f3; //NEXT models assume that all gstream meshes have uint16 indices f1 = ibr.ReadUInt16(); f2 = ibr.ReadUInt16(); f3 = ibr.ReadUInt16(); if (!start && this.type != TYPES.COLLISION) { fstart = f1; start = true; } else if (!start && this.type == TYPES.COLLISION) { fstart = 0; start = true; } int f11, f22, f33; f11 = f1 - fstart; f22 = f2 - fstart; f33 = f3 - fstart; Assimp.Face face = new Assimp.Face(); face.Indices.Add(f11); face.Indices.Add(f22); face.Indices.Add(f33); amesh.Faces.Add(face); } scn.Meshes.Add(amesh); } node = base.assimpExport(ref scn, ref meshImportStatus); node.MeshIndices.Add(meshImportStatus[meshHash]); return(node); }
protected override void ConvertGeometry(IGeometry iGeometry, ref Matrix4x4 nodeWorldTransform) { if (iGeometry.Format != GeometryFormat.Basic && iGeometry.Format != GeometryFormat.BasicDX) { throw new InvalidOperationException(); } var geometry = ( Geometry )iGeometry; var materialIndexMap = new int[Math.Max(1, geometry.Materials.Length)]; if (geometry.HasMaterials) { for (var i = 0; i < geometry.Materials.Length; i++) { // Convert material var material = geometry.Materials[i]; if (!mConvertedMaterialCache.TryGetValue(material, out var aiMaterialIndex)) { var textureName = material.UseTexture ? FormatTextureName(material.TextureId) : null; var aiMaterial = CreateMaterial(material.Diffuse, material.Specular, Color.Gray, textureName, material.ClampU, material.ClampV, material.FlipU, material.FlipV, material.UseAlpha); aiMaterialIndex = Scene.MaterialCount; Scene.Materials.Add(aiMaterial); mConvertedMaterialCache[material] = aiMaterialIndex; } materialIndexMap[i] = aiMaterialIndex; } } else { materialIndexMap[0] = GetNoMaterialMaterialIndex(); } foreach (var mesh in geometry.Meshes) { var aiMesh = new Assimp.Mesh(); // Convert mesh var hasNormals = geometry.HasNormals || mesh.HasNormals; var triangleIndices = mesh.ToTriangles(); var vertices = new List <Vertex>(); for (var i = 0; i < triangleIndices.Length; i += 3) { var aiFace = new Assimp.Face(); for (int j = 0; j < 3; j++) { var index = triangleIndices[i + j]; var vertex = new Vertex { Position = geometry.VertexPositions[index.VertexIndex] }; if (hasNormals) { vertex.Normal = geometry.HasNormals ? geometry.VertexNormals[index.VertexIndex] : index.Normal; } if (mesh.HasColors) { vertex.Color = index.Color; } if (mesh.HasUVs) { vertex.UV = UVCodec.Decode255(index.UV); } var vertexIndex = vertices.IndexOf(vertex); if (vertexIndex == -1) { vertexIndex = vertices.Count; vertices.Add(vertex); } aiFace.Indices.Add(vertexIndex); } aiMesh.Faces.Add(aiFace); } aiMesh.Vertices.AddRange(vertices.Select(x => ToAssimp(x.Position))); if (hasNormals) { aiMesh.Normals.AddRange(vertices.Select(x => ToAssimp(x.Normal))); } if (mesh.HasColors) { aiMesh.VertexColorChannels[0].AddRange(vertices.Select(x => ToAssimp(x.Color))); } if (mesh.HasUVs) { aiMesh.TextureCoordinateChannels[0].AddRange(vertices.Select(x => ToAssimp(x.UV))); } // Set mesh material index aiMesh.MaterialIndex = materialIndexMap[Math.Min(mesh.MaterialId, materialIndexMap.Length - 1)]; // Add mesh to scene Scene.Meshes.Add(aiMesh); } }
private void ConvertMeshes(List <Mesh> meshes, VertexPositionBuffer positionBuffer, VertexNormalBuffer normalBuffer, VertexColorBuffer colorBuffer, VertexUVBuffer uvBuffer) { var state = new MeshRenderState(); for (var i = 0; i < meshes.Count; i++) { var mesh = meshes[i]; if (mesh.Parameters != null && mesh.Parameters.Count > 0) { ProcessMeshParameters(mesh.Parameters, ref state); } var stateCopy = state; stateCopy.TextureId = 0; stateCopy.TileMode = 0; //stateCopy.IndexFlags = 0; stateCopy.AmbientColor = new Color(); sUniqueStates.Add(stateCopy); var aiMesh = new Assimp.Mesh(); var vertexCache = new List <Vertex>(); Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasPosition) ? positionBuffer != null : true); Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasNormal) ? normalBuffer != null : true); Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasColor) ? colorBuffer != null : true); Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasUV) ? uvBuffer != null : true); // Extract all vertices used by the triangles, and build a new vertex list // with each vertex attribute clumped together var aiFace = new Assimp.Face(); foreach (var index in mesh.DisplayLists.SelectMany(x => x.ToTriangles())) { var vertex = new Vertex(); if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasPosition)) { vertex.Position = positionBuffer.Elements[index.PositionIndex]; } if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasNormal)) { vertex.Normal = normalBuffer.Elements[index.NormalIndex]; } if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasColor)) { vertex.Color = colorBuffer.Elements[index.ColorIndex]; } if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasUV)) { vertex.UV = uvBuffer.Elements[index.UVIndex]; } // Find index of this vertex in the list in case it already exists var vertexIndex = vertexCache.IndexOf(vertex); if (vertexIndex == -1) { vertexIndex = vertexCache.Count; vertexCache.Add(vertex); } aiFace.Indices.Add(vertexIndex); if (aiFace.IndexCount == 3) { // Done with this face, move on to the next one aiMesh.Faces.Add(aiFace); aiFace = new Assimp.Face(); } } // Convert vertices aiMesh.Vertices.AddRange(vertexCache.Select(x => ToAssimp(x.Position))); if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasNormal)) { aiMesh.Normals.AddRange(vertexCache.Select(x => ToAssimp(x.Normal))); } if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasUV)) { aiMesh.TextureCoordinateChannels[0].AddRange(vertexCache.Select(x => ToAssimp(UVCodec.Decode1023(x.UV)))); } if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasColor)) { aiMesh.VertexColorChannels[0].AddRange(vertexCache.Select(x => ToAssimp(x.Color))); } // Convert material if (!mConvertedMaterialCache.TryGetValue(state, out var aiMaterialIndex)) { // Not in cache, so create a new one and add it aiMaterialIndex = Scene.MaterialCount; Scene.Materials.Add(CreateMaterial(Color.Gray, Color.Gray, Color.Gray, FormatTextureName(state.TextureId), false, false, state.TileMode.HasFlag(TileMode.MirrorU), state.TileMode.HasFlag(TileMode.MirrorV), state.BlendAlphaFlags.HasFlag(BlendAlphaFlags.UseAlpha))); mConvertedMaterialCache[state] = aiMaterialIndex; } aiMesh.MaterialIndex = aiMaterialIndex; // Add mesh to scene. Scene.Meshes.Add(aiMesh); } }
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 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); }