private static Ai.Node CreateAiNodeFromObject(Object obj, Ai.Scene aiScene) { var aiObjectNode = new Ai.Node(obj.Name); foreach (var mesh in obj.Meshes) { for (int i = 0; i < mesh.SubMeshes.Count; i++) { var subMesh = mesh.SubMeshes[i]; string name = mesh.Name; if (i > 0) { name += "." + i.ToString("D3"); } var aiSubMeshNode = new Ai.Node(name); var aiMesh = CreateAiMeshFromSubMesh(subMesh, mesh, obj, aiScene, name); aiSubMeshNode.MeshIndices.Add(aiScene.Meshes.Count); aiScene.Meshes.Add(aiMesh); aiObjectNode.Children.Add(aiSubMeshNode); } } return(aiObjectNode); }
public static void ExportFile(Ai.Scene scene, string path) { var aiContext = new Ai.AssimpContext(); aiContext.XAxisRotation = 90; aiContext.ExportFile(scene, path, "collada", Ai.PostProcessSteps.FlipUVs); }
/* * There is not parent child direct access method in the kinect API, * so we have to do it manually * See hierarchy : https://msdn.microsoft.com/en-us/library/hh973073.aspx */ private void CreateNodeHierarchy(JointCollection jointCollection, Scene mainScene) { Node root = mainScene.RootNode = new Node(); Node hipcenter = AddChildNode(root, jointCollection[JointType.HipCenter]); Node spine = AddChildNode(hipcenter, jointCollection[JointType.Spine]); Node shouldcenter = AddChildNode(spine, jointCollection[JointType.ShoulderCenter]); //ShouldCenter children build AddChildNode(shouldcenter, jointCollection[JointType.Head]); Node shoulderleft = AddChildNode(shouldcenter, jointCollection[JointType.ShoulderLeft]); Node elbowleft = AddChildNode(shoulderleft, jointCollection[JointType.ElbowLeft]); Node wristleft = AddChildNode(elbowleft, jointCollection[JointType.WristLeft]); AddChildNode(wristleft, jointCollection[JointType.HandLeft]); Node shoulderright = AddChildNode(shouldcenter, jointCollection[JointType.ShoulderRight]); Node elbowright = AddChildNode(shoulderright, jointCollection[JointType.ElbowRight]); Node wristright = AddChildNode(elbowright, jointCollection[JointType.WristRight]); AddChildNode(wristright, jointCollection[JointType.HandRight]); //HipCenter children build Node hipleft = AddChildNode(hipcenter, jointCollection[JointType.HipLeft]); Node kneeleft = AddChildNode(hipleft, jointCollection[JointType.KneeLeft]); Node ankleleft = AddChildNode(kneeleft, jointCollection[JointType.AnkleLeft]); AddChildNode(ankleleft, jointCollection[JointType.FootLeft]); Node hipright = AddChildNode(hipcenter, jointCollection[JointType.HipRight]); Node kneeright = AddChildNode(hipright, jointCollection[JointType.KneeRight]); Node ankleright = AddChildNode(kneeright, jointCollection[JointType.AnkleRight]); AddChildNode(ankleright, jointCollection[JointType.FootRight]); }
public void SetInverseBindMatrices(Assimp.Scene scene, List <Rigging.Bone> flatSkel) { for (int i = 0; i < flatSkel.Count; i++) { InverseBindMatrices.Add(new Matrix4(Vector4.UnitX, Vector4.UnitY, Vector4.UnitZ, Vector4.UnitW)); } foreach (Mesh mesh in scene.Meshes) { foreach (Assimp.Bone bone in mesh.Bones) { Console.Write("."); Matrix4x4 assMat = bone.OffsetMatrix; Matrix4 transposed = new Matrix4(assMat.A1, assMat.B1, assMat.C1, assMat.D1, assMat.A2, assMat.B2, assMat.C2, assMat.D2, assMat.A3, assMat.B3, assMat.C3, assMat.D3, assMat.A4, assMat.B4, assMat.C4, assMat.D4); int index = flatSkel.FindIndex(x => x.Name == bone.Name); if (index == -1) { throw new System.Exception(String.Format("Model uses bone that isn't part of the skeleton: {0}", bone.Name)); } InverseBindMatrices[index] = transposed; flatSkel[index].SetInverseBindMatrix(transposed); } } Console.Write(".✓"); }
/// <summary> /// Recursively calculates the bounding box of the whole model. /// </summary> private void ComputeBoundingBox(Scene scene, Node node, ref Vector3 min, ref Vector3 max, ref Matrix transform) { var previousTransform = transform; transform = Matrix.Multiply(previousTransform, node.Transform.ToMatrix()); if (node.HasMeshes) { foreach (int index in node.MeshIndices) { Mesh mesh = scene.Meshes[index]; for (int i = 0; i < mesh.VertexCount; i++) { var tmp = mesh.Vertices[i].ToVector3(); Vector4 result; Vector3.Transform(ref tmp, ref transform, out result); min.X = System.Math.Min(min.X, result.X); min.Y = System.Math.Min(min.Y, result.Y); min.Z = System.Math.Min(min.Z, result.Z); max.X = System.Math.Max(max.X, result.X); max.Y = System.Math.Max(max.Y, result.Y); max.Z = System.Math.Max(max.Z, result.Z); } } } // Go down the hierarchy if children are present. for (int i = 0; i < node.ChildCount; i++) ComputeBoundingBox(scene, node.Children[i], ref min, ref max, ref transform); transform = previousTransform; }
public Model LoadFromFile(string path) { AssimpContext Importer = new AssimpContext(); Importer.SetConfig(new NormalSmoothingAngleConfig(66.0f)); String fileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), path); modelDirPath = Path.GetDirectoryName(fileName); //Scene scene = Importer.ImportFileFromStream(stream); Assimp.Scene scene = Importer.ImportFile( fileName, PostProcessSteps.FindDegenerates | PostProcessSteps.FindInvalidData | PostProcessSteps.FlipUVs | // Required for Direct3D PostProcessSteps.FlipWindingOrder | // Required for Direct3D PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.ImproveCacheLocality | PostProcessSteps.OptimizeMeshes | PostProcessSteps.Triangulate ); _meshes = new List <Mesh>(); ProcessNode(scene.RootNode, scene); return(new Model(path, ref _meshes)); }
private void ExtractTextures(Assimp.Scene fileScene) { foreach (var texture in fileScene.Textures) { if (texture.HasCompressedData) { using (var stream = new MemoryStream(texture.CompressedData)) { using (var img = (System.Drawing.Bitmap)(Image.FromStream(stream))) { if (img.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb) { using (var rightImage = img.Clone(new System.Drawing.Rectangle(0, 0, img.Width, img.Height), System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { var str = Path.GetTempFileName(); rightImage.Save(str); textures.Add(LoadTextureFromFile(str, true, 4)); } } else { var str = Path.GetTempFileName(); img.Save(str); textures.Add(LoadTextureFromFile(str, true, 4)); } } } } else { textures.Add(defaultTexture); } } }
private static void ConvertAiNodesFromObjects(Ai.Scene aiScene, List <Object> objects, bool appendTags = false) { foreach (var obj in objects) { aiScene.RootNode.Children.Add(ConvertAiNodeFromObject(obj, aiScene, appendTags)); } }
/// <summary> /// Build a Node hierachy into the scene property 'mainScene' from a Hand object /// </summary> /// <param name="hand"></param> private void CreateNodeHierarchy(Hand hand, Scene handScene) { Node rootNode = handScene.RootNode = new Node(); Node handNode = new Node(); handNode.Name = GetNodeHandName(hand.Id.ToString()); rootNode.Children.Add(handNode); NodeAnimationChannel bonetest = new NodeAnimationChannel(); bonetest.NodeName = GetNodeHandName(hand.Id.ToString()); handScene.Animations[0].NodeAnimationChannels.Add(bonetest); foreach (Finger finger in hand.Fingers) { Node fingerNode = handNode; foreach (Leap.Bone.BoneType boneType in (Leap.Bone.BoneType[])Enum.GetValues(typeof(Leap.Bone.BoneType))) { string fingerType = finger.Type.ToString(); //Add a node hierarchy fingerNode = AddChildBone(fingerType, boneType.ToString(), hand, fingerNode); //Fill the NodeAnimChannel NodeAnimationChannel bone = new NodeAnimationChannel(); bone.NodeName = GetNodeBoneName(fingerType, boneType.ToString(), hand); handScene.Animations[0].NodeAnimationChannels.Add(bone); } } }
public static Model Load(Arguments args) { string extension = Path.GetExtension(args.input_path); Model output = null; if (extension == ".bmd" || extension == ".bdl") { using (FileStream str = new FileStream(args.input_path, FileMode.Open, FileAccess.Read)) { EndianBinaryReader reader = new EndianBinaryReader(str, Endian.Big); output = new Model(reader, args); } } else { Assimp.AssimpContext cont = new Assimp.AssimpContext(); // AssImp adds dummy nodes for pivots from FBX, so we'll force them off cont.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); Assimp.PostProcessSteps postprocess = Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices; if (args.tristrip_mode == "none") { // By not joining identical vertices, the Tri Strip algorithm we use cannot make tristrips, // effectively disabling tri stripping postprocess = Assimp.PostProcessSteps.Triangulate; } Assimp.Scene aiScene = cont.ImportFile(args.input_path, postprocess); output = new Model(aiScene, args); } return(output); }
private static void ConvertAiNodesFromMeshes(Ai.Scene aiScene, List <Mesh> meshes, bool appendTags = false) { foreach (var mesh in meshes) { aiScene.RootNode.Children.Add(ConvertAiNodeFromMesh(mesh, aiScene, appendTags)); } }
public JNT1(Assimp.Scene scene) { BoneNameIndices = new Dictionary <string, int>(); FlatSkeleton = new List <Rigging.Bone>(); Assimp.Node root = null; for (int i = 0; i < scene.RootNode.ChildCount; i++) { if (scene.RootNode.Children[i].Name.ToLowerInvariant() == "skeleton_root") { root = scene.RootNode.Children[i].Children[0]; break; } } if (root == null) { throw new Exception("Skeleton root was not found. Please make sure the root is under a node called \"skeleton_root.\""); } SkeletonRoot = AssimpNodesToBonesRecursive(root, null, FlatSkeleton); foreach (Rigging.Bone bone in FlatSkeleton) { BoneNameIndices.Add(bone.Name, FlatSkeleton.IndexOf(bone)); } }
public JNT1(Assimp.Scene scene, VTX1 vertexData) { BoneNameIndices = new Dictionary <string, int>(); FlatSkeleton = new List <Rigging.Bone>(); Assimp.Node root = null; for (int i = 0; i < scene.RootNode.ChildCount; i++) { if (scene.RootNode.Children[i].Name.ToLowerInvariant() == "skeleton_root") { root = scene.RootNode.Children[i].Children[0]; break; } } if (root == null) { SkeletonRoot = new Rigging.Bone("root"); SkeletonRoot.Bounds.GetBoundsValues(vertexData.Attributes.Positions); FlatSkeleton.Add(SkeletonRoot); BoneNameIndices.Add("root", 0); } else { SkeletonRoot = AssimpNodesToBonesRecursive(root, null, FlatSkeleton); foreach (Rigging.Bone bone in FlatSkeleton) { BoneNameIndices.Add(bone.Name, FlatSkeleton.IndexOf(bone)); } } }
/// <summary> /// Import a mesh from a model file. /// </summary> /// <param name="path"></param> /// <returns></returns> public static Mesh Load(string path) { Mesh mesh = new Mesh() { Path = path }; a.AssimpContext context = new a.AssimpContext(); a.Scene scene = context.ImportFile(path, a.PostProcessSteps.Triangulate); a.Mesh aMesh = scene.Meshes[0]; mesh.vertices = new Vector4[aMesh.VertexCount]; mesh.normals = new Vector4[aMesh.VertexCount]; mesh.uvs = new Vector4[aMesh.VertexCount]; for (int i = 0; i < aMesh.VertexCount; i++) { a.Vector3D aVertex = aMesh.Vertices[i]; a.Vector3D aNormal = aMesh.Normals[i]; a.Vector3D aUv = aMesh.TextureCoordinateChannels[0][i]; mesh.vertices[i] = new Vector4(aVertex.X, aVertex.Y, aVertex.Z, 1f); mesh.normals[i] = new Vector4(aNormal.X, aNormal.Y, aNormal.Z, 0f); mesh.uvs[i] = new Vector4(aUv.X, aUv.Y, 0f, 0f); } mesh.indices = aMesh.GetIndices(); return(mesh); }
public ModelMesh(GameMode gameMode, Assimp.Scene assimpScene, Assimp.Mesh assimpMesh, string modelDirectory) { var geometryData = GenerateGeometryDataFromAssimpMesh(assimpMesh); gameMode.EnsureExecutedInMainThread(() => Mesh = new Mesh(gameMode.GraphicsDevice, geometryData)); Material = GenerateMaterialFromMesh(assimpMesh.MaterialIndex, gameMode, assimpScene, modelDirectory); }
public static Model Load(Arguments args) { string extension = Path.GetExtension(args.input_path); Model output = null; if (extension == ".bmd" || extension == ".bdl") { using (FileStream str = new FileStream(args.input_path, FileMode.Open, FileAccess.Read)) { EndianBinaryReader reader = new EndianBinaryReader(str, Endian.Big); output = new Model(reader); } } else { Assimp.AssimpContext cont = new Assimp.AssimpContext(); // AssImp adds dummy nodes for pivots from FBX, so we'll force them off cont.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); Assimp.Scene aiScene = cont.ImportFile(args.input_path, Assimp.PostProcessSteps.Triangulate); output = new Model(aiScene, args); } return(output); }
void WriteModel (Scene scene, BinaryWriter writer, Dictionary<string,string> textures) { var boneCounts = new Dictionary<int, int>(); var boneSlotCounts = new Dictionary<int, int>(); foreach (var mesh in scene.Meshes) { var matId = mesh.MaterialIndex; var boneSlotCount = this.GetBoneSlotCount(mesh); var boneCount = mesh.BoneCount; if (!boneCounts.ContainsKey(matId) || boneCounts[matId] < boneCount) boneCounts[matId] = boneCount; if (!boneSlotCounts.ContainsKey(matId) || boneSlotCounts[matId] < boneSlotCount) boneSlotCounts[matId] = boneSlotCount; } writer.Write(scene.MaterialCount); for (var i = 0; i < scene.MaterialCount; i++) { var mat = scene.Materials[i]; this.WriteMaterial(mat, writer, textures, boneCounts[i], boneSlotCounts[i]); } writer.Write(scene.MeshCount); foreach (var mesh in scene.Meshes) this.WriteMesh(mesh, writer); writer.Write(scene.Animations.Count(i => i.HasNodeAnimations)); foreach (var anim in scene.Animations) { if (anim.HasMeshAnimations) Console.WriteLine("WARNING: mesh animations are not currently supported"); if (anim.HasNodeAnimations) this.WriteAnimation(anim, writer); } this.WriteNode(scene.RootNode, writer); }
//recursively calculates the bounding box of the whole model private void ComputeBoundingBox(Scene scene, Node node, ref Vector3 min, ref Vector3 max, ref Matrix transform) { Matrix previousTransform = transform; transform = Matrix.Multiply(previousTransform, FromMatrix(node.Transform)); if (node.HasMeshes) { foreach (int index in node.MeshIndices) { Assimp.Mesh mesh = scene.Meshes[index]; for (int i = 0; i < mesh.VertexCount; i++) { Vector3 tmp = FromVector(mesh.Vertices[i]); Vector4 result; Vector3.Transform(ref tmp, ref transform, out result); min.X = Math.Min(min.X, result.X); min.Y = Math.Min(min.Y, result.Y); min.Z = Math.Min(min.Z, result.Z); max.X = Math.Max(max.X, result.X); max.Y = Math.Max(max.Y, result.Y); max.Z = Math.Max(max.Z, result.Z); } } } //go down the hierarchy if children are present for (int i = 0; i < node.ChildCount; i++) { ComputeBoundingBox(scene, node.Children[i], ref min, ref max, ref transform); } transform = previousTransform; }
private SHP1(Assimp.Scene scene, VertexData vertData, Dictionary <string, int> boneNames, EVP1 envelopes, DRW1 partialWeight, string tristrip_mode = "static") { Shapes = new List <Shape>(); RemapTable = new List <int>(); foreach (Mesh mesh in scene.Meshes) { Shape meshShape = new Shape(); meshShape.SetDescriptorAttributes(mesh, boneNames.Count); if (boneNames.Count > 1) { meshShape.ProcessVerticesWithWeights(mesh, vertData, boneNames, envelopes, partialWeight, tristrip_mode == "all"); } else { meshShape.ProcessVerticesWithoutWeights(mesh, vertData); partialWeight.WeightTypeCheck.Add(false); partialWeight.Indices.Add(0); } Shapes.Add(meshShape); } }
public static Model ConvertFromAssimpScene(Ai.Scene aiScene, ModelConverterOptions options) { var scene = new Model(options.Version); // Convert assimp nodes to our nodes var nodeLookup = new Dictionary <string, NodeInfo>(); int nextNodeIndex = 0; scene.RootNode = ConvertAssimpNodeRecursively(aiScene, aiScene.RootNode, nodeLookup, ref nextNodeIndex, options); // Process the meshes attached to the assimp nodes var nodeToBoneIndices = new Dictionary <int, List <int> >(); int nextBoneIndex = 0; var boneInverseBindMatrices = new List <Matrix4x4>(); var transformedVertices = new List <Vector3>(); ProcessAssimpNodeMeshesRecursively(aiScene.RootNode, aiScene, nodeLookup, ref nextBoneIndex, nodeToBoneIndices, boneInverseBindMatrices, transformedVertices, options); // Don't build a bone palette if there are no skinned meshes if (boneInverseBindMatrices.Count > 0) { // Build bone palette for skinning scene.Bones = BuildBonePalette(boneInverseBindMatrices, nodeToBoneIndices); } // Build bounding box & sphere scene.BoundingBox = BoundingBox.Calculate(transformedVertices); scene.BoundingSphere = BoundingSphere.Calculate(scene.BoundingBox.Value, transformedVertices); return(scene); }
private static void CreateAiNodesFromBoneInfos(List <BoneInfo> boneInfos, Ai.Scene aiScene, Ai.Node aiParentBone, BoneInfo parentBoneInfo, Dictionary <string, Ai.Node> convertedBones) { foreach (var boneInfo in boneInfos) { if (boneInfo.Parent != parentBoneInfo) { continue; } if (!convertedBones.TryGetValue(boneInfo.Name, out var aiBoneNode)) { aiBoneNode = CreateAiNodeFromBoneInfo(boneInfo, parentBoneInfo?.InverseBindPoseMatrix ?? Matrix4x4.Identity); if (aiParentBone == null) { aiScene.RootNode.Children.Add(aiBoneNode); } else { aiParentBone.Children.Add(aiBoneNode); } convertedBones.Add(boneInfo.Name, aiBoneNode); } CreateAiNodesFromBoneInfos(boneInfos, aiScene, aiBoneNode, boneInfo, convertedBones); } }
private static Object ConvertObjectFromAiNode(Ai.Node aiNode, Ai.Scene aiScene, Matrix4x4 parentTransformation, string texturesDirectory, TextureSet textureSet) { var obj = new Object { Name = aiNode.Name, Skin = new Skin() }; var boneMap = new Dictionary <string, int>(StringComparer.OrdinalIgnoreCase); var materialMap = new Dictionary <string, int>(StringComparer.OrdinalIgnoreCase); ConvertMeshesFromAiNodesRecursively(obj, aiNode, aiScene, parentTransformation, boneMap, materialMap, texturesDirectory, textureSet); if (obj.Skin.Bones.Count == 0) { obj.Skin = null; } obj.BoundingSphere = new AxisAlignedBoundingBox(obj.Meshes.SelectMany(x => x.Vertices)).ToBoundingSphere(); return(obj.Meshes.Count != 0 ? obj : null); }
internal void LoadPrimitveFromFile(string fileName, out DebugVertexType[] vertices, out UInt16[] indices) { Assimp.Scene scene = m_importer.ImportFile(fileName, PostProcessPreset.TargetRealTimeMaximumQuality | PostProcessPreset.ConvertToLeftHanded); // Loaded primitive files should always only contain a single mesh so we load only the first mesh if (scene.HasMeshes) { Assimp.Mesh assimpMesh = scene.Meshes[0]; vertices = new DebugVertexType[assimpMesh.Vertices.Count]; indices = new UInt16[assimpMesh.GetIndices().Length]; for (int i = 0; i < assimpMesh.Vertices.Count; ++i) { Vector3 position = FromAssimpVector(assimpMesh.Vertices[i]); vertices[i].position = position; } for (int i = 0; i < assimpMesh.GetIndices().Length; i++) { int index = assimpMesh.GetIndices()[i]; indices[i] = (UInt16)index; } } else { vertices = new DebugVertexType[0]; indices = new UInt16[0]; } }
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); } }
//recursively calculates the bounding box of the whole model private void ComputeBoundingBox(Assimp.Scene scene, Node node, ref Vector3 min, ref Vector3 max, ref Matrix transform) { Matrix previousTransform = transform; transform = Matrix.Multiply(previousTransform, FromAssimpMatrix(node.Transform)); if (node.HasMeshes) { foreach (int index in node.MeshIndices) { Assimp.Mesh mesh = scene.Meshes[index]; for (int i = 0; i < mesh.VertexCount; i++) { Vector3 tmp = FromAssimpVector(mesh.Vertices[i]); Vector4 result; Vector3.Transform(ref tmp, ref transform, out result); min.X = Math.Min(min.X, result.X); min.Y = Math.Min(min.Y, result.Y); min.Z = Math.Min(min.Z, result.Z); max.X = Math.Max(max.X, result.X); max.Y = Math.Max(max.Y, result.Y); max.Z = Math.Max(max.Z, result.Z); } } } //go down the hierarchy if children are present for (int i = 0; i < node.ChildCount; i++) { ComputeBoundingBox(scene, node.Children[i], ref min, ref max, ref transform); } transform = previousTransform; }
private void Reset() { StopAnimation(); _monoGameContent?.Dispose(); _monoGameContent = null; Debug.Assert(ModelNode == null || ModelNode.IsDisposed, "ModelNode should be disposed together with the ContentManager."); ModelNode = null; Model = null; _tempDirectoryHelper?.Dispose(); _tempDirectoryHelper = null; _assimpScene = null; if (_outlineService != null && _outlineService.Outline == Outline) { _outlineService.Outline = null; } if (_propertiesService != null && _propertiesService.PropertySource == _currentPropertySource) { _propertiesService.PropertySource = null; } CleanErrors(); }
private void LoadMeshes(GeometryModel3D[] meshes, Scene scene, SystemMaterial[] materials) { for (int i = 0; i < scene.MeshCount; ++i) { meshes[i] = this.ConvertMesh(scene.Meshes[i], materials); } }
private static void LoadMaterial(SystemMaterial[] materials, Scene scene, string path) { for (int i = 0; i < scene.MaterialCount; ++i) { materials[i] = ConvertMaterial(scene.Materials[i], path); } }
public Dictionary <string, EngineMaterial> LoadFromFile(string path) { string relativeLocation = Directory.GetParent(path).FullName; Dictionary <string, EngineMaterial> mats = new Dictionary <string, EngineMaterial>(); List <Mesh> meshes = new List <Mesh>(); AssimpContext context = new AssimpContext(); Scene loadedAssimpScene = context.ImportFile(path, PostProcessSteps.OptimizeMeshes | PostProcessSteps.Triangulate | PostProcessSteps.FlipUVs); if (loadedAssimpScene == null || loadedAssimpScene.SceneFlags == SceneFlags.Incomplete) { Console.WriteLine("Scene error"); } List <AssimpMat> materials = loadedAssimpScene.Materials; foreach (var material in materials) { EngineMaterial _material = new EngineMaterial(); _material.MaterialName = material.Name; TextureSlot[] textureSlots = material.GetAllMaterialTextures(); if (material.HasTextureDiffuse) { _material.DiffuseMap = "C:/Users/kpbil/source/models/mira/textures/Mira_bc2.jpg"; //Path.Combine(relativeLocation, material.TextureDiffuse.FilePath); } if (material.HasTextureNormal) { _material.NormalMap = "C:/Users/kpbil/source/models/mira/textures/Mira_nm.jpg"; //Path.Combine(relativeLocation, material.TextureNormal.FilePath); } if (material.HasTextureAmbient) { _material.AmbientMap = "C:/Users/kpbil/source/models/mira/textures/Mira_ao.jpg";//Path.Combine(relativeLocation, material.TextureAmbient.FilePath); } try { _material.Metallic = "C:/Users/kpbil/source/models/mira/textures/Mira_metal.jpg";//Path.Combine(relativeLocation, textureSlots.Where(t => t.TextureType == TextureType.Unknown).FirstOrDefault().FilePath); } catch { //TODO: add handling } try { _material.Roughness = "C:/Users/kpbil/source/models/mira/textures/Mira_rou.jpg";//Path.Combine(relativeLocation, textureSlots.Where(t => t.TextureType == TextureType.Unknown).FirstOrDefault().FilePath); } catch { //TODO: add handling } mats.Add(_material.MaterialName, _material); } return(mats); }
Mesh processMesh(Assimp.Mesh mesh, Assimp.Scene scene) { List <Vertex> vertices = null; List <int> indices = null; List <Texture> textures = null; for (int i = 0; i < mesh.VertexCount; i++) { Vertex vert = new Vertex(); Vector3 vec = new Vector3(); vec.X = mesh.Vertices[i].X; vec.Y = mesh.Vertices[i].Y; vec.Z = mesh.Vertices[i].Z; vert.position = vec; vec.X = mesh.Normals[i].X; vec.Y = mesh.Normals[i].Y; vec.Z = mesh.Normals[i].Z; vert.normal = vec; if (mesh.HasTextureCoords(0)) { Vector2 vec2 = new Vector2(); vec2.X = mesh.TextureCoordinateChannels[0][i].X; vec2.Y = mesh.TextureCoordinateChannels[0][i].Y; vert.texCoord = vec2; } else { vert.texCoord = new Vector2(0, 0); } vertices.Add(vert); } for (int i = 0; i < mesh.FaceCount; i++) { Assimp.Face face = new Face(); face = mesh.Faces[i]; for (int j = 0; j < face.IndexCount; j++) { indices.Add(face.Indices[j]); } } if (mesh.MaterialIndex >= 0) { Material material = scene.Materials[mesh.MaterialIndex]; List <Texture> diffuseMaps = new List <Texture>(); diffuseMaps.AddRange(loadMaterialTextures(material, TextureType.Diffuse, "texture_diffuse")); textures.InsertRange(textures.Count + 1, diffuseMaps); List <Texture> specularMaps = new List <Texture>(); specularMaps.AddRange(loadMaterialTextures(material, TextureType.Specular, "texture_specular")); textures.InsertRange(textures.Count + 1, specularMaps); } return(new Mesh(vertices, indices, textures)); }
private void processNode(Node node, Assimp.Scene scene) { for (int i = 0; i < node.MeshCount; i++) { Assimp.Mesh mesh = scene.Meshes[node.MeshIndices[i]]; meshes.Add(processMesh(mesh, scene)); } }
public Import3DModelWindowViewModel() { modelPath = String.Empty; scene = new Scene(); browseDirectoriesCommand = new DelegateCommand(BrowseDirectories); importModelCommand = new RelayCommand(ImportModel); cancelImportCommand = new RelayCommand(CancelImport); }
protected List <Containers.Mesh> Process(Assimp.Scene scene) { List <Containers.Mesh> meshes = new List <Containers.Mesh>(); if (scene.HasMeshes) { foreach (Assimp.Mesh m in scene.Meshes) { if (m.HasNormals && m.HasTextureCoords(0) && m.HasVertices) { Containers.Mesh ms = new Containers.Mesh(); foreach (Vector3D v in m.Normals) { ms.normals.Add(new Materia.Math3D.Vector3(v.X, v.Y, v.Z)); //we also add placeholders for tangents ms.tangents.Add(new Materia.Math3D.Vector4(0, 0, 0, 1)); } foreach (Vector3D v in m.Vertices) { ms.vertices.Add(new Materia.Math3D.Vector3(v.X, v.Y, v.Z)); } foreach (Vector3D v in m.TextureCoordinateChannels[0]) { ms.uv.Add(new Materia.Math3D.Vector2(v.X, v.Y)); } ms.indices = new List <int>(m.GetIndices()); //store faces for use with Mikktspace generation //and for displaying UVs foreach (Face f in m.Faces) { if (f.IndexCount == 3) { Triangle t = new Triangle(); t.n0 = t.v0 = t.u0 = f.Indices[0]; t.n1 = t.v1 = t.u1 = f.Indices[1]; t.n2 = t.v2 = t.u2 = f.Indices[2]; ms.AddTriangle(t); } } //generate tangents using mikktspace Mikkt.GenTangents(ms); meshes.Add(ms); } } } return(meshes); }
private static Mesh GetMesh(Assimp.Scene scene, Node node = null, Assimp.Mesh mesh = null, bool Root = true) { Mesh result = InitMesh(ref scene, ref node, ref Root); ProcessMesh(ref mesh, ref result); ProcessNode(ref scene, ref node, ref mesh, ref result); result.UpdateBuffers(); return(result); }
private void Init(string path) { mAiScene = new Ai.Scene(); mPath = Path.GetFullPath(path); mFileName = Path.GetFileNameWithoutExtension(mPath); mBaseDirectoryPath = Path.GetDirectoryName(mPath); mTextureBaseDirectoryPath = Path.Combine(mBaseDirectoryPath, $"{mFileName}_Textures"); mTextureBaseRelativeDirectoryPath = mTextureBaseDirectoryPath.Substring(mBaseDirectoryPath.Length); }
public static Mesh LoadFromModel(string Filename) { if (Cache.ContainsKey(Filename)) { return(Cache[Filename]); } Assimp.Scene scene = Context.ImportFile(Filename, PostProcess); Cache.Add(Filename, GetMesh(scene)); return(Cache[Filename]); }
private static void ConvertAiMaterialsFromMaterials(Ai.Scene aiScene, List <Material> materials, TextureSet textures) { foreach (var material in materials) { if (!aiScene.Materials.Any(x => x.Name.Equals(material.Name))) { aiScene.Materials.Add(ConvertAiMaterialFromMaterial(material, textures)); } } }
public static void Export(Ai.Scene aiScene, string fileName, Ai.PostProcessSteps postProcessSteps = Ai.PostProcessSteps.None) { var aiContext = new Ai.AssimpContext(); var formatExtension = Path.GetExtension(fileName).Substring(1); var formatId = aiContext.GetSupportedExportFormats() .First(x => x.FileExtension.Equals(formatExtension, StringComparison.OrdinalIgnoreCase)).FormatId; aiContext.ExportFile(aiScene, fileName, formatId, postProcessSteps); }
/// <summary> /// Generate weights and skeleton Nodes from an assimp skeleton Node. /// However pinocchio does not looks to be very good with /// that Method. /// It takes a /// </summary> /// <param name="modelPath">The original model Path</param> /// <param name="scene"></param> /// <param name="skeletalAnim"></param> /// <param name="rootSkeletalAnim"></param> public void AutomaticRiggingFromSkeleton(string modelPath, Scene scene, Animation skeletalAnim, Node rootSkeletalAnim) { string skelPathFile = Path.Combine(Path.Combine(projectPath, PINOCCHIO_TMP_DIR_INPUT), "skeleton.out"); ExportToPinocchioFormat(projectPath, skeletalAnim, rootSkeletalAnim, 0); LaunchPinocchioBinary(modelPath, skelPathFile); //Import Data that pinocchio did generated //There is a problem here since we dont have a way to associate AssimpNodes and Bones in the attachement.out for now() BuildBones(scene.Meshes[0], rootSkeletalAnim); BuildBonesWeight(scene); }
//calculates the bounding box of the whole model private void ComputeBoundingBox(Model model, Scene scene) { Vector3 sceneMin = new Vector3(1e10f, 1e10f, 1e10f); Vector3 sceneMax = new Vector3(-1e10f, -1e10f, -1e10f); Matrix transform = Matrix.Identity; ComputeBoundingBox(scene, scene.RootNode, ref sceneMin, ref sceneMax, ref transform); //set min and max of bounding box model.SetAABox(sceneMin, sceneMax); }
public void SetUp() { var assimpNetimporter = new Assimp.AssimpContext(); Assimp.LogStream.IsVerboseLoggingEnabled = true; var logger = new Assimp.ConsoleLogStream(); logger.Attach(); assimpNetScene = assimpNetimporter.ImportFile(filename); logger.Detach(); var assimpSharpImporter = new AssimpSharp.XFile.XFileImporter(); assimpSharpScene = new AssimpSharp.Scene(); assimpSharpImporter.InternReadFile(filename, assimpSharpScene); }
/// <summary> /// Generate weights and skeleton Nodes from Nothing. /// It takes a scene with a single model and generates inside a NodeArchitectures/Associated Bones/Vertex Weights /// </summary> /// <param name="modelPath">The original model Path</param> /// <param name="scene">The scene with the model</param> public void AutomaticRigging(string modelPath, Scene scene) { string skelPathFile = Path.Combine(Path.Combine(projectPath, PINOCCHIO_TMP_DIR_OUTPUT), "skeleton.out"); LaunchPinocchioBinary(modelPath, null); //Import Data that pinocchio did generated Node rootNodeSkeletalAnim = BuildNodesFromSkeleton(skelPathFile); /// Pinocchio algorithm only can be apply on a single Mesh, so we only /// need to fetch the first Mesh BuildBones(scene.Meshes[0], rootNodeSkeletalAnim); BuildBonesWeight(scene); scene.RootNode.Children.Add(rootNodeSkeletalAnim); }
static Bone LookForBone(Scene root, string name) { string namelow = name.ToLower(); for (int i = 0; i < root.Meshes.Count; i++) { for (int x = 0; x < root.Meshes[i].Bones.Count; x++) { if (root.Meshes[i].Bones[x].Name.ToLower() == namelow) { return root.Meshes[i].Bones[x]; } } } return null; }
public void Init(Scene scene) { if (!scene.HasAnimations) { return; } Release(); _skeleton = CreateBoneTree(scene.RootNode, null); foreach (var mesh in scene.Meshes) { foreach (var bone in mesh.Bones) { Bone found; if (!_bonesByName.TryGetValue(bone.Name, out found)) continue; var skip = (from t in _bones let bname = bone.Name where t.Name == bname select t).Any(); if (skip) continue; found.Offset = Matrix.Transpose(bone.OffsetMatrix.ToMatrix()); _bones.Add(found); _bonesToIndex[found.Name] = _bones.IndexOf(found); } var mesh1 = mesh; foreach (var bone in _bonesByName.Keys.Where(b => mesh1.Bones.All(b1 => b1.Name != b) && b.StartsWith("Bone"))) { _bonesByName[bone].Offset = _bonesByName[bone].Parent.Offset; _bones.Add(_bonesByName[bone]); _bonesToIndex[bone] = _bones.IndexOf(_bonesByName[bone]); } } ExtractAnimations(scene); const float timestep = 1.0f / 30.0f; for (var i = 0; i < Animations.Count; i++) { SetAnimationIndex(i); var dt = 0.0f; for (var ticks = 0.0f; ticks < Animations[i].Duration; ticks += Animations[i].TicksPerSecond / 30.0f) { dt += timestep; Calculate(dt); var trans = new List<Matrix>(); for (var a = 0; a < _bones.Count; a++) { var rotMat = _bones[a].Offset * _bones[a].GlobalTransform; trans.Add(rotMat); } Animations[i].Transforms.Add(trans); } } Console.WriteLine("Finished loading animations with " + _bones.Count + " bones"); }
/** * This function will Initialize (names, size, ect...) * the mChannels array in Animation newly created class. * @param skeleton Skeleton Fetch on the kinect stream */ private void InitAnimBones(Scene scene, Skeleton skeleton) { Animation newAnim = new Animation(); //We set 0 by defaults but it should be interesting to check tickpersecond for a skeleton record newAnim.TicksPerSecond = 0; newAnim.DurationInTicks = 0; scene.Animations.Add(newAnim); //this.animList.Add(new Tuple<Int32, Animation>(skeleton.TrackingId, newAnim)); foreach (Joint joint in skeleton.Joints) { NodeAnimationChannel bone = new NodeAnimationChannel(); bone.NodeName = joint.JointType.ToString(); newAnim.NodeAnimationChannels.Add(bone); } }
private static void ImportGenericModel(String path, out Scene scene) { try { using (LogStream logStream = new LogStream(delegate(String msg, String userData) { Console.WriteLine(msg); })) { logStream.Attach(); using (AssimpContext importer = new AssimpContext()) scene = importer.ImportFile(path, PostProcessPreset.TargetRealTimeMaximumQuality); logStream.Detach(); } } catch (Exception exception) { scene = null; System.Windows.MessageBox.Show(exception.Message); } }
internal SceneAnimator(Scene scene) { _scene = scene; _raw = scene.Raw; Debug.Assert(_raw != null, "scene must already be loaded"); _nodeStateByName = new Dictionary<string, NodeState>(); int maxBoneCount = 0; for (int i = 0; i < _raw.MeshCount; ++i) { var bc = _raw.Meshes[i].BoneCount; if(bc > maxBoneCount) { maxBoneCount = bc; } } _boneMatrices = new Matrix4[maxBoneCount]; // initialize the node hierarchy ActiveAnimation = -1; }
private SEAObject3D AppendLight(Scene scene, Node node, Light light, SEAObject3D parent) { int sIndex = GetIndexByTag(node); if (sIndex != -1) return (SEAObject3D)Writer.Objects[sIndex]; SEALight seaLight = null; if (light.LightType == LightSourceType.Point) { SEAPointLight pLight = new SEAPointLight(GetValidString(objects, node.Name)); pLight.multiplier = 1; pLight.color = ToInteger( light.ColorDiffuse ); pLight.position = ToPositionArray( node.Transform ); seaLight = pLight; } else if (light.LightType == LightSourceType.Directional || light.LightType == LightSourceType.Spot) { SEADirectionalLight dLight = new SEADirectionalLight(GetValidString(objects, node.Name)); dLight.multiplier = 1; dLight.color = ToInteger( light.ColorDiffuse ); dLight.transform = To3x4Array( node.Transform ); seaLight = dLight; } if (seaLight != null) { seaLight.parent = parent != null ? GetIndex(parent) : -1; seaLight.tag = node; objects.Add(seaLight); Writer.AddObject(seaLight); } return seaLight; }
private SEAObject3D AppendObject3D(Scene scene, Node node) { return AppendObject3D(scene, node, null); }
private List<Animation> GetAnimation(Scene scene, string name) { List<Animation> list = new List<Animation>(); foreach (Animation anm in scene.Animations) { if (anm.Name == name) { list.Add(anm); } } return list; }
private object GetUnrelatedObjectByNode(Node node, Scene scene) { foreach (Light light in scene.Lights) { if (light.Name == node.Name) return light; } foreach (Camera camera in scene.Cameras) { if (camera.Name == node.Name) return camera; } return null; }
private SEASkeleton AppendSkeletonAnimation(Scene scene, Mesh mesh) { return null; }
private SEAObject AppendTextureFromSlot(Scene scene, TextureSlot slot) { if (slot.FilePath.Length > 0 && slot.FilePath[0] != '*') { return AppendTexture(getURL(slot.FilePath)); } else if (slot.TextureIndex < scene.TextureCount) { return AppendTexture(scene.Textures[slot.TextureIndex]); } return null; }
private SEASkeleton AppendSkeleton(Scene scene, Mesh mesh) { SEASkeleton skl = new SEASkeleton(GetValidString(modifiers, mesh.Name)); skl.joints = new List<JointData>(); foreach (Bone bone in mesh.Bones) { JointData jnt = new JointData(); jnt.name = bone.Name; jnt.parentIndex = -1; jnt.inverseBindMatrix = To3x4Array( bone.OffsetMatrix ); } modifiers.Add(skl); Writer.AddObject(skl); return skl; }
private SEAMaterial AppendMaterial(Scene scene, Material material) { int sIndex = GetIndexByTag(material); if (sIndex != -1) return (SEAMaterial)Writer.Objects[sIndex]; SEAMaterial mat = new SEAMaterial(GetValidString(materials, material.Name)); mat.doubleSided = material.IsTwoSided; mat.receiveLights = true; mat.receiveShadows = true; mat.receiveFog = true; mat.repeat = true; mat.alpha = material.Opacity; // // DEFAULT // PhongTech defaultTech = new PhongTech(); defaultTech.diffuseColor = ToInteger( material.ColorDiffuse ); defaultTech.specularColor = ToInteger( material.ColorSpecular ); defaultTech.specular = material.ShininessStrength; defaultTech.gloss = material.Shininess; mat.techniques.Add(defaultTech); // // DIFFUSE_MAP // if (material.HasTextureDiffuse) { SEAObject tex = AppendTextureFromSlot(scene, material.TextureDiffuse); if (tex != null) { DiffuseMapTech tech = new DiffuseMapTech(); tech.texture = GetIndex(tex); mat.techniques.Add(tech); } } // // SPECULAR_MAP // if (material.HasTextureSpecular) { SEAObject tex = AppendTextureFromSlot(scene, material.TextureSpecular); if (tex != null) { SpecularMapTech tech = new SpecularMapTech(); tech.texture = GetIndex(tex); mat.techniques.Add(tech); } } // // EMISSIVE_MAP // if (material.HasTextureAmbient || material.HasTextureEmissive) { SEAObject tex = AppendTextureFromSlot(scene, material.HasTextureAmbient ? material.TextureAmbient : material.TextureEmissive); if (tex != null) { EmissiveMapTech tech = new EmissiveMapTech(); tech.texture = GetIndex(tex); mat.techniques.Add(tech); } } // // NORMAL_MAP // if (material.HasTextureNormal) { SEAObject tex = AppendTextureFromSlot(scene, material.TextureNormal); if (tex != null) { NormalMapTech tech = new NormalMapTech(); tech.texture = GetIndex(tex); mat.techniques.Add(tech); } } // // OPACITY_MAP // if (material.HasTextureOpacity) { SEAObject tex = AppendTextureFromSlot(scene, material.TextureOpacity); if (tex != null) { OpacityMapTech tech = new OpacityMapTech(); tech.texture = GetIndex(tex); mat.techniques.Add(tech); } } // // REFLECTION_MAP // if (material.HasTextureReflection) { SEAObject tex = AppendTextureFromSlot(scene, material.TextureReflection); if (tex != null) { ReflectionTech tech = new ReflectionTech(); tech.texture = GetIndex(tex); tech.alpha = material.Reflectivity; mat.techniques.Add(tech); } } // -- mat.tag = material; materials.Add(mat); Writer.AddObject(mat); return mat; }
private void Export(object parameter) { FileExtension = FileExtension.ToString(); string exportedFile = FilePath + "\\" + FileName + '.' + FileExtension; if (FileExtension == "") { System.Windows.MessageBox.Show("Select a file extension"); return; } if (FileName == "") { System.Windows.MessageBox.Show("Choose a name for your file"); return; } if (!Directory.Exists(FilePath)) { System.Windows.MessageBox.Show("Path is invalid"); return; } if (File.Exists(exportedFile)) { System.Windows.MessageBox.Show("File already exists at " + FilePath); return; } else { bool result = false; if (Session.CurrentSession.HasCurrentProject() && Session.CurrentSession.CurrentProject.CurrentModel3D != null) scene = Session.CurrentSession.CurrentProject.CurrentModel3D.GetScene(); if (Scene == null) { System.Windows.MessageBox.Show("You must open a scene in order to export it"); return; } using (AssimpContext exporter = new AssimpContext()) { ExportFormatDescription[] exportFormat = exporter.GetSupportedExportFormats(); foreach (ExportFormatDescription format in exportFormat) { if (format.FileExtension == FileExtension) { result = exporter.ExportFile(scene, exportedFile, format.FormatId); break; } } if (result == false) { System.Windows.MessageBox.Show("Bad export file extension"); return; } } if (result == false) { System.Windows.MessageBox.Show("Export failed"); return; } Window currentWindow = parameter as Window; McWindow.CloseWindow(currentWindow); } }
private SEAObject3D AppendObject3D(Scene scene, Node node, SEAObject3D parent) { SEAObject3D object3d = null; /* mtx.e00 / scale.x, mtx.e10 / scale.x, mtx.e20 / scale.x, mtx.e01 / scale.y, mtx.e11 / scale.y, mtx.e21 / scale.y, mtx.e02 / scale.z, mtx.e12 / scale.z, mtx.e22 / scale.z */ //node.Transform = node.Transform * Matrix4x4.FromEulerAnglesXYZ(-90, 0, 0); if (node.MeshCount > 0) { object3d = AppendMesh(scene, node, scene.Meshes, parent); } else if (!MeshOnly && scene.RootNode != node) { object unrelatedObject = GetUnrelatedObjectByNode(node, scene); if (unrelatedObject is Light) { object3d = AppendLight(scene, node, (Light)unrelatedObject, parent); } else if (unrelatedObject is Camera) { object3d = AppendCamera(scene, node, (Camera)unrelatedObject, parent); } else if (EnabledDummy) { object3d = AppendDummy(scene, node, parent); } } foreach (Node children in node.Children) { AppendObject3D(scene, children, object3d); } return null; }
private SEAMesh AppendMesh(Scene scene, Node node, List<Mesh> meshes, SEAObject3D parent) { int sIndex = GetIndexByTag(node); if (sIndex != -1) return (SEAMesh)Writer.Objects[sIndex]; List<Animation> anmList = GetAnimation(scene, node.Name); SEAGeometry geo = AppendGeometry(scene, node, meshes); if (geo != null) { SEAMesh seaMesh = new SEAMesh(node.Name); /*if (meshes[0].HasMeshAnimationAttachments) { }*/ Mesh mesh = meshes[0]; if (Modifiers && geo.jointPerVertex > 0) { seaMesh.modifiers.Add((uint)GetIndex(AppendSkeleton(scene, mesh))); seaMesh.animations.Add((uint)GetIndex(AppendSkeletonAnimation(scene, mesh))); } if (mesh.MaterialIndex != -1) { seaMesh.materials.Add(GetIndex(AppendMaterial(scene, scene.Materials[mesh.MaterialIndex]))); } seaMesh.parent = parent != null ? GetIndex(parent) : -1; objects.Add(seaMesh); Writer.AddObject(seaMesh); seaMesh.transform = To3x4Array( node.Transform ); seaMesh.geometry = GetIndex(geo); seaMesh.tag = node; return seaMesh; } return null; }
/// <summary> /// Ucitavanje podataka o sceni iz odgovarajuceg fajla. /// </summary> private void LoadScene() { // Instanciranje klase za ucitavanje podataka o sceni. AssimpImporter importer = new AssimpImporter(); // Definisanje callback delegata za belezenje poruka u toku ucitavanja podataka o sceni. LogStream logstream = new LogStream(delegate(String msg, String userData) { Console.WriteLine(msg); }); importer.AttachLogStream(logstream); // Ucitavanje podataka o sceni iz odgovarajuceg fajla. m_scene = importer.ImportFile(Path.Combine(m_scenePath, m_sceneFileName), PostProcessPreset.TargetRealTimeMaximumQuality); // Oslobadjanje resursa koriscenih za ucitavanje podataka o sceni. importer.Dispose(); }
private void AppendScene(Scene scene) { AppendObject3D(scene, scene.RootNode); if (!SceneOnly) { foreach (Material mat in scene.Materials) { AppendMaterial(scene, mat); } } }