private Ai.Node ConvertNode(Model model, Node node, Ai.Node aiParent) { var aiNode = new Ai.Node(AssimpConverterCommon.EscapeName(node.Name), aiParent) { Transform = new Ai.Matrix4x4(node.LocalTransform.M11, node.LocalTransform.M21, node.LocalTransform.M31, node.LocalTransform.M41, node.LocalTransform.M12, node.LocalTransform.M22, node.LocalTransform.M32, node.LocalTransform.M42, node.LocalTransform.M13, node.LocalTransform.M23, node.LocalTransform.M33, node.LocalTransform.M43, node.LocalTransform.M14, node.LocalTransform.M24, node.LocalTransform.M34, node.LocalTransform.M44) }; if (node.HasProperties) { ConvertNodeProperties(node.Properties, aiNode); } if (node.HasAttachments) { ConvertNodeAttachments(model, node, aiNode); } if (node.HasChildren) { foreach (var childNode in node.Children) { aiNode.Children.Add(ConvertNode(model, childNode, aiNode)); } } return(aiNode); }
private static void ProcessAssimpNodeMeshesRecursively(Ai.Node aiNode, Ai.Scene aiScene, Dictionary <string, NodeInfo> nodeLookup, ref int nextBoneIndex, Dictionary <int, List <int> > nodeToBoneIndices, List <Matrix4x4> boneInverseBindMatrices, List <Vector3> transformedVertices, ModelConverterOptions options) { if (aiNode.HasMeshes) { var nodeInfo = nodeLookup[AssimpConverterCommon.UnescapeName(aiNode.Name)]; var node = nodeInfo.Node; var nodeWorldTransform = node.WorldTransform; Matrix4x4.Invert(nodeWorldTransform, out var nodeInverseWorldTransform); foreach (var aiMeshIndex in aiNode.MeshIndices) { var aiMesh = aiScene.Meshes[aiMeshIndex]; var aiMaterial = aiScene.Materials[aiMesh.MaterialIndex]; var geometry = ConvertAssimpMeshToGeometry(aiMesh, aiMaterial, nodeLookup, ref nextBoneIndex, nodeToBoneIndices, boneInverseBindMatrices, ref nodeWorldTransform, ref nodeInverseWorldTransform, transformedVertices, options); if (!nodeInfo.IsMeshAttachment) { node.Attachments.Add(new NodeMeshAttachment(geometry)); } else { node.Parent.Attachments.Add(new NodeMeshAttachment(geometry)); node.Parent.RemoveChildNode(node); } } } foreach (var aiNodeChild in aiNode.Children) { ProcessAssimpNodeMeshesRecursively(aiNodeChild, aiScene, nodeLookup, ref nextBoneIndex, nodeToBoneIndices, boneInverseBindMatrices, transformedVertices, options); } }
private void ConvertNodeAttachments(Model model, Node node, Ai.Node aiNode) { for (int i = 0; i < node.Attachments.Count; i++) { var attachment = node.Attachments[i]; switch (attachment.Type) { case NodeAttachmentType.Mesh: { var mesh = ConvertGeometry(model, node, attachment.GetValue <Mesh>()); mesh.Name = $"{AssimpConverterCommon.EscapeName(node.Name)}_Attachment{i}_Mesh"; aiNode.MeshIndices.Add(mAiScene.Meshes.Count); mAiScene.Meshes.Add(mesh); } break; case NodeAttachmentType.Camera: { var camera = attachment.GetValue <Camera>(); mAiScene.Cameras.Add(new Ai.Camera { Name = node.Name, Position = camera.Position.ToAssimp(), Up = camera.Up.ToAssimp(), Direction = -camera.Direction.ToAssimp(), FieldOfview = MathHelper.DegreesToRadians(camera.FieldOfView), ClipPlaneNear = camera.ClipPlaneNear, ClipPlaneFar = camera.ClipPlaneFar, AspectRatio = camera.AspectRatio }); } break; case NodeAttachmentType.Light: { var light = attachment.GetValue <Light>(); mAiScene.Lights.Add(new Ai.Light { Name = node.Name, AngleInnerCone = light.AngleInnerCone, AngleOuterCone = light.AngleOuterCone, ColorAmbient = light.AmbientColor.ToAssimpAsColor3D(), ColorDiffuse = light.DiffuseColor.ToAssimpAsColor3D(), ColorSpecular = light.SpecularColor.ToAssimpAsColor3D(), LightType = light.Type == LightType.Point ? Ai.LightSourceType.Point : light.Type == LightType.Spot ? Ai.LightSourceType.Spot : Ai.LightSourceType.Directional, }); } break; default: //throw new NotImplementedException(); break; } } }
private void ConvertTextures(TextureDictionary textureDictionary) { Directory.CreateDirectory(mTextureBaseDirectoryPath); foreach (var texture in textureDictionary.Textures) { var texturePath = Path.Combine(mTextureBaseDirectoryPath, AssimpConverterCommon.EscapeName(texture.Name)); File.WriteAllBytes(texturePath, texture.Data); } }
private Ai.Material ConvertMaterial(Material material) { var aiMaterial = new Ai.Material { Name = AssimpConverterCommon.EscapeName(material.Name), ColorAmbient = new Ai.Color4D(material.AmbientColor.X, material.AmbientColor.Y, material.AmbientColor.Z, material.AmbientColor.W), ColorDiffuse = new Ai.Color4D(material.DiffuseColor.X, material.DiffuseColor.Y, material.DiffuseColor.Z, material.DiffuseColor.W), ColorSpecular = new Ai.Color4D(material.SpecularColor.X, material.SpecularColor.Y, material.SpecularColor.Z, material.SpecularColor.W), ColorEmissive = new Ai.Color4D(material.EmissiveColor.X, material.EmissiveColor.Y, material.EmissiveColor.Z, material.EmissiveColor.W) }; if (material.Flags.HasFlag(MaterialFlags.HasDiffuseMap)) { aiMaterial.TextureDiffuse = new Ai.TextureSlot( Path.Combine(mTextureBaseRelativeDirectoryPath, AssimpConverterCommon.EscapeName(material.DiffuseMap.Name)), Ai.TextureType.Diffuse, 0, Ai.TextureMapping.FromUV, 0, 0, Ai.TextureOperation.Add, Ai.TextureWrapMode.Wrap, Ai.TextureWrapMode.Wrap, 0); } if (material.Flags.HasFlag(MaterialFlags.HasNormalMap)) { aiMaterial.TextureNormal = new Ai.TextureSlot( Path.Combine(mTextureBaseRelativeDirectoryPath, AssimpConverterCommon.EscapeName(material.NormalMap.Name)), Ai.TextureType.Normals, 1, Ai.TextureMapping.FromUV, 0, 0, Ai.TextureOperation.Add, Ai.TextureWrapMode.Wrap, Ai.TextureWrapMode.Wrap, 0); } if (material.Flags.HasFlag(MaterialFlags.HasSpecularMap)) { aiMaterial.TextureSpecular = new Ai.TextureSlot( Path.Combine(mTextureBaseRelativeDirectoryPath, AssimpConverterCommon.EscapeName(material.SpecularMap.Name)), Ai.TextureType.Specular, 2, Ai.TextureMapping.FromUV, 0, 0, Ai.TextureOperation.Add, Ai.TextureWrapMode.Wrap, Ai.TextureWrapMode.Wrap, 0); } if (material.Flags.HasFlag(MaterialFlags.HasReflectionMap)) { aiMaterial.TextureReflection = new Ai.TextureSlot( Path.Combine(mTextureBaseRelativeDirectoryPath, AssimpConverterCommon.EscapeName(material.ReflectionMap.Name)), Ai.TextureType.Reflection, 3, Ai.TextureMapping.FromUV, 0, 0, Ai.TextureOperation.Add, Ai.TextureWrapMode.Wrap, Ai.TextureWrapMode.Wrap, 0); } // todo: add more textures return(aiMaterial); }
private static TextureInfo ConvertTexture(Ai.TextureSlot aiTextureSlot, string baseDirectoryPath) { var relativeFilePath = aiTextureSlot.FilePath; var fullFilePath = Path.GetFullPath(Path.Combine(baseDirectoryPath, relativeFilePath)); var textureName = AssimpConverterCommon.UnescapeName(Path.GetFileNameWithoutExtension(relativeFilePath) + ".dds"); Texture texture; if (!File.Exists(fullFilePath)) { texture = Texture.CreateDefaultTexture(textureName); } else if (relativeFilePath.EndsWith(".dds", StringComparison.InvariantCultureIgnoreCase)) { texture = new Texture(textureName, TextureFormat.DDS, File.ReadAllBytes(fullFilePath)); } else { var bitmap = new Bitmap(fullFilePath); texture = TextureEncoder.Encode(textureName, TextureFormat.DDS, bitmap); } return(TextureInfo.GetTextureInfo(texture)); }
private static Mesh ConvertAssimpMeshToGeometry(Ai.Mesh aiMesh, Ai.Material material, Dictionary <string, NodeInfo> nodeLookup, ref int nextBoneIndex, Dictionary <int, List <int> > nodeToBoneIndices, List <Matrix4x4> boneInverseBindMatrices, ref Matrix4x4 nodeWorldTransform, ref Matrix4x4 nodeInverseWorldTransform, List <Vector3> transformedVertices, ModelConverterOptions options) { if (!aiMesh.HasVertices) { throw new Exception("Assimp mesh has no vertices"); } var geometry = new Mesh(); var geometryTransformedVertices = new Vector3[aiMesh.VertexCount]; geometry.Vertices = aiMesh.Vertices .Select(x => new Vector3(x.X, x.Y, x.Z)) .ToArray(); for (int i = 0; i < geometry.Vertices.Length; i++) { geometryTransformedVertices[i] = Vector3.Transform(geometry.Vertices[i], nodeWorldTransform); } transformedVertices.AddRange(geometryTransformedVertices); if (aiMesh.HasNormals) { geometry.Normals = aiMesh.Normals .Select(x => new Vector3(x.X, x.Y, x.Z)) .ToArray(); } if (aiMesh.HasTextureCoords(0)) { geometry.TexCoordsChannel0 = aiMesh.TextureCoordinateChannels[0] .Select(x => new Vector2(x.X, x.Y)) .ToArray(); } if (aiMesh.HasTextureCoords(1)) { geometry.TexCoordsChannel1 = aiMesh.TextureCoordinateChannels[1] .Select(x => new Vector2(x.X, x.Y)) .ToArray(); } if (aiMesh.HasTextureCoords(2)) { geometry.TexCoordsChannel2 = aiMesh.TextureCoordinateChannels[2] .Select(x => new Vector2(x.X, x.Y)) .ToArray(); } if (aiMesh.HasVertexColors(0)) { geometry.ColorChannel0 = aiMesh.VertexColorChannels[0] .Select(x => ( uint )(( byte )(x.B * 255f) | ( byte )(x.G * 255f) << 8 | ( byte )(x.R * 255f) << 16 | ( byte )(x.A * 255f) << 24)) .ToArray(); } else if (options.GenerateVertexColors) { geometry.ColorChannel0 = new uint[geometry.VertexCount]; for (int i = 0; i < geometry.ColorChannel0.Length; i++) { geometry.ColorChannel0[i] = 0xFFFFFFFF; } } if (aiMesh.HasVertexColors(1)) { geometry.ColorChannel1 = aiMesh.VertexColorChannels[1] .Select(x => ( uint )(( byte )(x.B * 255f) | ( byte )(x.G * 255f) << 8 | ( byte )(x.R * 255f) << 16 | ( byte )(x.A * 255f) << 24)) .ToArray(); } if (aiMesh.HasFaces) { geometry.TriangleIndexFormat = aiMesh.VertexCount <= ushort.MaxValue ? TriangleIndexFormat.UInt16 : TriangleIndexFormat.UInt32; geometry.Triangles = aiMesh.Faces .Select(x => new Triangle(( uint )x.Indices[0], ( uint )x.Indices[1], ( uint )x.Indices[2])) .ToArray(); } if (aiMesh.HasBones) { geometry.VertexWeights = new VertexWeight[geometry.VertexCount]; for (int i = 0; i < geometry.VertexWeights.Length; i++) { geometry.VertexWeights[i].Indices = new byte[4]; geometry.VertexWeights[i].Weights = new float[4]; } var vertexWeightCounts = new int[geometry.VertexCount]; for (var i = 0; i < aiMesh.Bones.Count; i++) { var aiMeshBone = aiMesh.Bones[i]; // Find node index for the bone var boneLookupData = nodeLookup[AssimpConverterCommon.UnescapeName(aiMeshBone.Name)]; int nodeIndex = boneLookupData.Index; // Calculate inverse bind matrix var boneNode = boneLookupData.Node; var bindMatrix = boneNode.WorldTransform * nodeInverseWorldTransform; if (options.ConvertSkinToZUp) { bindMatrix *= YToZUpMatrix; } Matrix4x4.Invert(bindMatrix, out var inverseBindMatrix); // Get bone index int boneIndex; if (!nodeToBoneIndices.TryGetValue(nodeIndex, out var boneIndices)) { // No entry for the node was found, so we add a new one boneIndex = nextBoneIndex++; nodeToBoneIndices.Add(nodeIndex, new List <int>() { boneIndex }); boneInverseBindMatrices.Add(inverseBindMatrix); } else { // Entry for the node was found // Try to find the bone index based on whether the inverse bind matrix matches boneIndex = -1; foreach (int index in boneIndices) { if (boneInverseBindMatrices[index].Equals(inverseBindMatrix)) { boneIndex = index; } } if (boneIndex == -1) { // None matching inverse bind matrix was found, so we add a new entry boneIndex = nextBoneIndex++; nodeToBoneIndices[nodeIndex].Add(boneIndex); boneInverseBindMatrices.Add(inverseBindMatrix); } } foreach (var aiVertexWeight in aiMeshBone.VertexWeights) { int vertexWeightCount = vertexWeightCounts[aiVertexWeight.VertexID]++; geometry.VertexWeights[aiVertexWeight.VertexID].Indices[vertexWeightCount] = ( byte )boneIndex; geometry.VertexWeights[aiVertexWeight.VertexID].Weights[vertexWeightCount] = aiVertexWeight.Weight; } } } geometry.MaterialName = AssimpConverterCommon.UnescapeName(material.Name); geometry.BoundingBox = BoundingBox.Calculate(geometry.Vertices); geometry.BoundingSphere = BoundingSphere.Calculate(geometry.BoundingBox.Value, geometry.Vertices); geometry.Flags |= GeometryFlags.Flag80000000; return(geometry); }
private static Node ConvertAssimpNodeRecursively(Assimp.Scene aiScene, Ai.Node aiNode, Dictionary <string, NodeInfo> nodeLookup, ref int nextIndex, ModelConverterOptions options) { aiNode.Transform.Decompose(out var scale, out var rotation, out var translation); // Create node var node = new Node(AssimpConverterCommon.UnescapeName(aiNode.Name), new Vector3(translation.X, translation.Y, translation.Z), new Quaternion(rotation.X, rotation.Y, rotation.Z, rotation.W), new Vector3(scale.X, scale.Y, scale.Z)); if (!IsMeshAttachmentNode(aiNode)) { // Convert properties ConvertAssimpMetadataToProperties(aiNode.Metadata, node); if (options.SetFullBodyNodeProperties) { if (node.Name == "See User Defined Properties") { TryAddProperty(node.Properties, new UserIntProperty("NiSortAdjustNode", 0)); } else if (node.Name.EndsWith("root") || node.Name == "Bip01") { TryAddProperty(node.Properties, new UserIntProperty("KFAccumRoot", 0)); } else if (sFullBodyObjectNames.Contains(node.Name)) { TryAddFullBodyObjectProperties(node.Properties, node.Name); } } if (!nodeLookup.ContainsKey(node.Name)) { // Add to lookup nodeLookup.Add(node.Name, new NodeInfo(aiNode, node, nextIndex++, false)); } else { throw new Exception($"Duplicate node name '{node.Name}'"); } // Is this a camera? var index = -1; if ((index = aiScene.Cameras.FindIndex(x => x.Name == node.Name)) != -1) { var aiCamera = aiScene.Cameras[index]; var camera = new Camera(-aiCamera.Direction.ToNumerics(), aiCamera.Up.ToNumerics(), aiCamera.Position.ToNumerics(), aiCamera.ClipPlaneNear, aiCamera.ClipPlaneFar, MathHelper.RadiansToDegrees(aiCamera.FieldOfview), aiCamera.AspectRatio, 0 ) { Version = options.Version }; node.Attachments.Add(new NodeCameraAttachment(camera)); } else if ((index = aiScene.Lights.FindIndex(x => x.Name == node.Name)) != -1) { var aiLight = aiScene.Lights[index]; var lightType = LightType.Point; switch (aiLight.LightType) { case Ai.LightSourceType.Directional: lightType = LightType.Type1; break; case Ai.LightSourceType.Point: case Ai.LightSourceType.Ambient: lightType = LightType.Point; break; case Ai.LightSourceType.Spot: lightType = LightType.Spot; break; } var light = new Light { Version = options.Version, AmbientColor = aiLight.ColorAmbient.ToNumerics(), DiffuseColor = aiLight.ColorDiffuse.ToNumerics(), SpecularColor = aiLight.ColorSpecular.ToNumerics(), AngleInnerCone = aiLight.AngleInnerCone, AngleOuterCone = aiLight.AngleOuterCone, Type = lightType, Flags = LightFlags.Bit1 | LightFlags.Bit2 }; node.Attachments.Add(new NodeLightAttachment(light)); } // Process children foreach (var aiNodeChild in aiNode.Children) { if (aiNodeChild.Name == "RootNode") { // For compatibility with old exports // Merge children of 'RootNode' node with actual root node foreach (var aiFakeRootNodeChild in aiNodeChild.Children) { var childNode = ConvertAssimpNodeRecursively(aiScene, aiFakeRootNodeChild, nodeLookup, ref nextIndex, options); node.AddChildNode(childNode); } } else { var childNode = ConvertAssimpNodeRecursively(aiScene, aiNodeChild, nodeLookup, ref nextIndex, options); node.AddChildNode(childNode); } } } else { nodeLookup.Add(node.Name, new NodeInfo(aiNode, node, -1, true)); } return(node); }
private static Material ConvertMaterialAndTextures(Ai.Material aiMaterial, ModelPackConverterOptions options, string baseDirectoryPath, TextureDictionary textureDictionary) { // Convert all textures TextureInfo diffuseTexture = null; if (aiMaterial.HasTextureDiffuse) { diffuseTexture = ConvertTexture(aiMaterial.TextureDiffuse, baseDirectoryPath); } TextureInfo lightmapTexture = null; if (aiMaterial.HasTextureLightMap) { lightmapTexture = ConvertTexture(aiMaterial.TextureLightMap, baseDirectoryPath); } TextureInfo displacementTexture = null; if (aiMaterial.HasTextureDisplacement) { displacementTexture = ConvertTexture(aiMaterial.TextureDisplacement, baseDirectoryPath); } TextureInfo opacityTexture = null; if (aiMaterial.HasTextureOpacity) { opacityTexture = ConvertTexture(aiMaterial.TextureOpacity, baseDirectoryPath); } TextureInfo normalTexture = null; if (aiMaterial.HasTextureNormal) { normalTexture = ConvertTexture(aiMaterial.TextureNormal, baseDirectoryPath); } TextureInfo heightTexture = null; if (aiMaterial.HasTextureHeight) { heightTexture = ConvertTexture(aiMaterial.TextureHeight, baseDirectoryPath); } TextureInfo emissiveTexture = null; if (aiMaterial.HasTextureEmissive) { emissiveTexture = ConvertTexture(aiMaterial.TextureEmissive, baseDirectoryPath); } TextureInfo ambientTexture = null; if (aiMaterial.HasTextureAmbient) { ambientTexture = ConvertTexture(aiMaterial.TextureAmbient, baseDirectoryPath); } TextureInfo specularTexture = null; if (aiMaterial.HasTextureSpecular) { specularTexture = ConvertTexture(aiMaterial.TextureSpecular, baseDirectoryPath); } TextureInfo reflectionTexture = null; if (aiMaterial.HasTextureReflection) { reflectionTexture = ConvertTexture(aiMaterial.TextureReflection, baseDirectoryPath); } // Convert material Material material = null; string materialName = AssimpConverterCommon.UnescapeName(aiMaterial.Name); switch (options.MaterialPreset) { case MaterialPreset.FieldTerrain: { if (diffuseTexture != null) { textureDictionary.Add(diffuseTexture.Texture); material = MaterialFactory.CreateFieldTerrainMaterial(materialName, diffuseTexture.Name, HasAlpha(diffuseTexture.PixelFormat)); } } break; case MaterialPreset.FieldTerrainVertexColors: { if (diffuseTexture != null) { textureDictionary.Add(diffuseTexture.Texture); material = MaterialFactory.CreateFieldTerrainVertexColorsMaterial(materialName, diffuseTexture.Name, HasAlpha(diffuseTexture.PixelFormat)); } } break; case MaterialPreset.FieldTerrainCastShadow: { if (diffuseTexture != null) { textureDictionary.Add(diffuseTexture.Texture); material = MaterialFactory.CreateFieldTerrainCastShadowMaterial(materialName, diffuseTexture.Name, HasAlpha(diffuseTexture.PixelFormat)); } } break; case MaterialPreset.CharacterSkinP5: case MaterialPreset.CharacterSkinFB: { if (diffuseTexture != null) { textureDictionary.Add(diffuseTexture.Texture); string shadowTextureName = diffuseTexture.Name; if (ambientTexture != null) { textureDictionary.Add(ambientTexture.Texture); shadowTextureName = ambientTexture.Name; } // TODO: transparency var hasTransparency = HasAlpha(diffuseTexture.PixelFormat); if (options.MaterialPreset == MaterialPreset.CharacterSkinP5) { material = MaterialFactory.CreateCharacterSkinP5Material(materialName, diffuseTexture.Name, shadowTextureName, hasTransparency); } else { material = MaterialFactory.CreateCharacterSkinFBMaterial(materialName, diffuseTexture.Name, shadowTextureName, hasTransparency); } } } break; case MaterialPreset.PersonaSkinP5: { if (diffuseTexture != null) { textureDictionary.Add(diffuseTexture.Texture); string shadowTextureName = diffuseTexture.Name; string specularTextureName = diffuseTexture.Name; if (ambientTexture != null) { textureDictionary.Add(ambientTexture.Texture); shadowTextureName = ambientTexture.Name; } if (specularTexture != null) { textureDictionary.Add(specularTexture.Texture); specularTextureName = specularTexture.Name; } material = MaterialFactory.CreatePersonaSkinP5Material(materialName, diffuseTexture.Name, specularTextureName, shadowTextureName); } } break; case MaterialPreset.CharacterClothP4D: { if (diffuseTexture != null) { textureDictionary.Add(diffuseTexture.Texture); material = MaterialFactory.CreateCharacterClothP4DMaterial(materialName, diffuseTexture.Name, HasAlpha(diffuseTexture.PixelFormat)); } } break; case MaterialPreset.CharacterSkinP3DP5D: { if (diffuseTexture != null) { textureDictionary.Add(diffuseTexture.Texture); material = MaterialFactory.CreateCharacterSkinP3DP5DMaterial(materialName, diffuseTexture.Name, HasAlpha(diffuseTexture.PixelFormat)); } } break; } // Create dummy material if none was created if (material == null) { material = new Material(materialName); } return(material); }
private Ai.Mesh ConvertGeometry(Model model, Node geometryNode, Mesh mesh) { var aiMesh = new Ai.Mesh(Ai.PrimitiveType.Triangle); if (mesh.Flags.HasFlag(GeometryFlags.HasMaterial)) { aiMesh.MaterialIndex = mAiScene.Materials.FindIndex(x => x.Name == AssimpConverterCommon.EscapeName(mesh.MaterialName)); } if (mesh.Flags.HasFlag(GeometryFlags.HasTriangles)) { foreach (var triangle in mesh.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); } } var vertices = mesh.Vertices; var normals = mesh.Normals; if (mesh.VertexWeights != null) { (vertices, normals) = mesh.Transform(geometryNode, model.Nodes.ToList(), model.Bones); } if (mesh.VertexAttributeFlags.HasFlag(VertexAttributeFlags.Position)) { foreach (var vertex in vertices) { aiMesh.Vertices.Add(new Ai.Vector3D(vertex.X, vertex.Y, vertex.Z)); } } if (mesh.VertexAttributeFlags.HasFlag(VertexAttributeFlags.Normal)) { foreach (var normal in normals) { aiMesh.Normals.Add(new Ai.Vector3D(normal.X, normal.Y, normal.Z)); } } if (mesh.VertexAttributeFlags.HasFlag(VertexAttributeFlags.Tangent)) { foreach (var tangent in mesh.Tangents) { aiMesh.Tangents.Add(new Ai.Vector3D(tangent.X, tangent.Y, tangent.Z)); } } if (mesh.VertexAttributeFlags.HasFlag(VertexAttributeFlags.Binormal)) { foreach (var binormal in mesh.Binormals) { aiMesh.BiTangents.Add(new Ai.Vector3D(binormal.X, binormal.Y, binormal.Z)); } } if (mesh.VertexAttributeFlags.HasFlag(VertexAttributeFlags.TexCoord0)) { foreach (var vertex in mesh.TexCoordsChannel0) { aiMesh.TextureCoordinateChannels[0].Add(new Ai.Vector3D(vertex.X, vertex.Y, 0)); } } if (mesh.VertexAttributeFlags.HasFlag(VertexAttributeFlags.TexCoord1)) { foreach (var vertex in mesh.TexCoordsChannel1) { aiMesh.TextureCoordinateChannels[1].Add(new Ai.Vector3D(vertex.X, vertex.Y, 0)); } } if (mesh.VertexAttributeFlags.HasFlag(VertexAttributeFlags.TexCoord2)) { foreach (var vertex in mesh.TexCoordsChannel2) { aiMesh.TextureCoordinateChannels[2].Add(new Ai.Vector3D(vertex.X, vertex.Y, 0)); } } /* todo: colors * if ( mesh.VertexAttributeFlags.HasFlag( VertexAttributeFlags.Color0 ) ) * { * foreach ( var color in mesh.ColorChannel0 ) * { * aiMesh.VertexColorChannels[0].Add( new Ai.Color4D( color. )) * } * } */ if (mesh.Flags.HasFlag(GeometryFlags.HasVertexWeights)) { var boneMap = new Dictionary <int, Ai.Bone>(); for (int i = 0; i < mesh.VertexWeights.Length; i++) { var vertexWeight = mesh.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 = model.Bones[boneIndex].NodeIndex; if (!boneMap.ContainsKey(nodeIndex)) { var aiBone = new Ai.Bone(); var boneNode = model.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); }