public ModelLoader(Device device, TextureLoadHandler textureLoadHandler) { _device = device; _textureLoadHandler = textureLoadHandler; _importer = new AssimpImporter(); _importer.SetConfig(new NormalSmoothingAngleConfig(66.0f)); }
public SimpleOpenGLSample() : base() { Title = "Quack! - Assimp.NET Simple OpenGL Sample"; String fileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "duck.dae"); AssimpImporter importer = new AssimpImporter(); importer.SetConfig(new NormalSmoothingAngleConfig(66.0f)); m_model = importer.ImportFile(fileName, PostProcessPreset.TargetRealTimeMaximumQuality); ComputeBoundingBox(); }
private Scene LoadDaeScene(String path) { Scene scene; using (var importer = new AssimpImporter()) { importer.SetConfig(new NormalSmoothingAngleConfig(66.0f)); scene = importer.ImportFile(path, PostProcessPreset.TargetRealTimeMaximumQuality); } return(scene); }
private ContentCompilerResult CompileFromFileInternal(string fileName, ModelCompilerOptions compilerOptions) { logger = new Logger(); var result = new ContentCompilerResult() { Logger = logger }; modelFilePath = fileName; modelDirectory = Path.GetDirectoryName(modelFilePath); // Preload AssimpLibrary if not already loaded if (!AssimpLibrary.Instance.LibraryLoaded) { var rootPath = Path.GetDirectoryName(typeof(AssimpLibrary).Assembly.Location); AssimpLibrary.Instance.LoadLibrary(Path.Combine(rootPath, AssimpLibrary.Instance.DefaultLibraryPath32Bit), Path.Combine(rootPath, AssimpLibrary.Instance.DefaultLibraryPath64Bit)); } var importer = new AssimpImporter(); importer.SetConfig(new Assimp.Configs.MaxBoneCountConfig(72)); //importer.SetConfig(new NormalSmoothingAngleConfig(66.0f)); // Steps for Direct3D Right-Handed, should we make this configurable? var steps = PostProcessSteps.FlipUVs | PostProcessSteps.FlipWindingOrder | PostProcessSteps.LimitBoneWeights | PostProcessSteps.SplitByBoneCount; // Setup quality switch (compilerOptions.Quality) { case ModelRealTimeQuality.Low: steps |= PostProcessPreset.TargetRealTimeFast; break; case ModelRealTimeQuality.Maximum: steps |= PostProcessPreset.TargetRealTimeMaximumQuality; break; default: steps |= PostProcessPreset.TargetRealTimeQuality; break; } scene = importer.ImportFile(fileName, steps); model = new ModelData(); ProcessScene(); result.IsContentGenerated = true; result.ModelData = model; return(result); }
static void Main(string[] args) { if (args.Length < 1) { Console.WriteLine("Usage: ModelCompiler.exe model.dae"); return; } foreach (string filename in args) { AssimpImporter importer = new AssimpImporter(); PostProcessSteps steps = PostProcessPreset.TargetRealTimeMaximumQuality; steps |= PostProcessSteps.OptimizeMeshes | PostProcessSteps.SplitLargeMeshes | PostProcessSteps.Triangulate | PostProcessSteps.FlipUVs | PostProcessSteps.LimitBoneWeights; importer.SetConfig(new VertexBoneWeightLimitConfig(2)); Scene scene = importer.ImportFile(filename, steps); Vector3D bbMin = new Vector3D(float.MaxValue, float.MaxValue, float.MaxValue); Vector3D bbMax = new Vector3D(float.MinValue, float.MinValue, float.MinValue); Node meshNode = scene.RootNode; while (!meshNode.HasMeshes) { meshNode = meshNode.Children[0]; } Mesh nodeGeometry = scene.Meshes[meshNode.MeshIndices[0]]; List <Vector3D> transformedVertices = new List <Vector3D>(); foreach (Vector3D vertex in nodeGeometry.Vertices) { Vector4 tempv = new Vector4(vertex.X, vertex.Y, vertex.Z, 1.0f); Matrix tempm = Matrix.Scaling(0.1f) * Matrix.RotationYawPitchRoll(((float)Math.PI / 2.0f), ((float)Math.PI / 2.0f), 0.0f) * new Matrix(meshNode.Transform.A1, meshNode.Transform.A2, meshNode.Transform.A3, meshNode.Transform.A3, meshNode.Transform.B1, meshNode.Transform.B2, meshNode.Transform.B3, meshNode.Transform.B3, meshNode.Transform.C1, meshNode.Transform.C2, meshNode.Transform.C3, meshNode.Transform.C3, meshNode.Transform.D1, meshNode.Transform.D2, meshNode.Transform.D3, meshNode.Transform.D3); Vector4 finalvec = Vector4.Transform(tempv, tempm); transformedVertices.Add(new Vector3D(finalvec.X, finalvec.Y, finalvec.Z)); } using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(filename + ".mdl"))) { foreach (Vector3D vector in transformedVertices) { bbMin.X = Math.Min(vector.X, bbMin.X); bbMin.Y = Math.Min(vector.Y, bbMin.Y); bbMin.Z = Math.Min(vector.Z, bbMin.Z); bbMax.X = Math.Max(vector.X, bbMax.X); bbMax.Y = Math.Max(vector.Y, bbMax.Y); bbMax.Z = Math.Max(vector.Z, bbMax.Z); } writer.Write(bbMin.X); writer.Write(bbMin.Y); writer.Write(bbMin.Z); writer.Write(bbMax.X); writer.Write(bbMax.Y); writer.Write(bbMax.Z); //writer.Write(scene.Meshes.Length); writer.Write(1); Mesh currentMesh = nodeGeometry; if (!currentMesh.HasTextureCoords(0)) { Console.WriteLine("ERROR: model must have texture coordinates"); return; } Vector3D[] texCoords = currentMesh.GetTextureCoords(0); writer.Write(currentMesh.VertexCount); for (int j = 0; j < currentMesh.VertexCount; j++) { writer.Write(transformedVertices[j].X); writer.Write(transformedVertices[j].Y); writer.Write(transformedVertices[j].Z); writer.Write(texCoords[j].X); writer.Write(texCoords[j].Y); } writer.Write(currentMesh.Faces.Length * 3); for (int j = 0; j < currentMesh.Faces.Length; j++) { Face currentFace = currentMesh.Faces[j]; if (currentFace.IndexCount != 3) { Console.WriteLine("ERROR: non-triangle found!"); Console.ReadKey(); return; } foreach (uint index in currentFace.Indices) { writer.Write((int)index); } } //writer.Write(currentMesh.Faces.Length * 3); //for (int j = 0; j < currentMesh.Faces.Length; j++) //{ // Face currentFace = currentMesh.Faces[j]; // if (currentFace.IndexCount != 3) // { // Console.WriteLine("ERROR: non-triangle found!"); // Console.ReadKey(); // return; // } // foreach (uint index in currentFace.Indices) // { // writer.Write(transformedVertices[(int)index].X); // writer.Write(transformedVertices[(int)index].Y); // writer.Write(transformedVertices[(int)index].Z); // writer.Write(texCoords[index].X); // writer.Write(texCoords[index].Y); // } //} } } }
public void TestImportFromFile() { String path = Path.Combine(TestHelper.RootPath, "TestFiles\\sphere.obj"); AssimpImporter importer = new AssimpImporter(); importer.SetConfig(new NormalSmoothingAngleConfig(55.0f)); importer.Scale = .5f; importer.XAxisRotation = 25.0f; importer.YAxisRotation = 50.0f; importer.VerboseLoggingEnabled = true; Assert.IsTrue(importer.ContainsConfig(NormalSmoothingAngleConfig.NormalSmoothingAngleConfigName)); importer.RemoveConfigs(); Assert.IsFalse(importer.ContainsConfig(NormalSmoothingAngleConfig.NormalSmoothingAngleConfigName)); importer.SetConfig(new NormalSmoothingAngleConfig(65.0f)); importer.SetConfig(new NormalSmoothingAngleConfig(22.5f)); importer.RemoveConfig(NormalSmoothingAngleConfig.NormalSmoothingAngleConfigName); Assert.IsFalse(importer.ContainsConfig(NormalSmoothingAngleConfig.NormalSmoothingAngleConfigName)); importer.SetConfig(new NormalSmoothingAngleConfig(65.0f)); Scene scene = importer.ImportFile(path, PostProcessPreset.TargetRealTimeMaximumQuality); Assert.IsNotNull(scene); Assert.IsTrue((scene.SceneFlags & SceneFlags.Incomplete) != SceneFlags.Incomplete); }
private void LoadSceneB() { Console.WriteLine("Thread B: Starting import."); AssimpImporter importer = new AssimpImporter(); String path = Path.Combine(TestHelper.RootPath, "TestFiles\\duck.dae"); importer.AttachLogStream(new ConsoleLogStream("Thread B:")); importer.SetConfig(new NormalSmoothingAngleConfig(55.0f)); Console.WriteLine("Thread B: Importing"); Scene scene = importer.ImportFile(path); Console.WriteLine("Thread B: Done importing"); }
private void ConvertSceneC() { Console.WriteLine("Thread C: Starting convert."); AssimpImporter importer = new AssimpImporter(); String path = Path.Combine(TestHelper.RootPath, "TestFiles\\duck.dae"); String outputPath = Path.Combine(TestHelper.RootPath, "TestFiles\\duck2.obj"); importer.AttachLogStream(new ConsoleLogStream("Thread C:")); importer.SetConfig(new NormalSmoothingAngleConfig(55.0f)); importer.SetConfig(new FavorSpeedConfig(true)); importer.VerboseLoggingEnabled = true; Console.WriteLine("Thread C: Converting"); ExportDataBlob blob = importer.ConvertFromFileToBlob(path, "obj"); Console.WriteLine("Thread C: Done converting"); }
public ModelLoader(Device device) { m_device = device; m_importer = new AssimpImporter(); m_importer.SetConfig(new NormalSmoothingAngleConfig(66.0f)); }
public override NodeContent Import(string filename, ContentImporterContext context) { ContentIdentity identity = new ContentIdentity(filename, GetType().Name); const int MAX_BONE_WEIGHTS = 4; VertexBoneWeightLimitConfig boneConfig = new VertexBoneWeightLimitConfig(MAX_BONE_WEIGHTS); AssimpImporter importer = new AssimpImporter(); importer.SetConfig(boneConfig); importer.AttachLogStream(new LogStream((msg, userData) => context.Logger.LogMessage(msg))); Scene scene = importer.ImportFile(filename, PostProcessSteps.FlipUVs | PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.Triangulate | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.FindInvalidData | PostProcessSteps.LimitBoneWeights | PostProcessSteps.FixInFacingNormals); // Root node NodeContent rootNode = new NodeContent { Name = scene.RootNode.Name, Identity = identity, Transform = Matrix.Transpose(ToXna(scene.RootNode.Transform)) }; // Materials MaterialContent[] materials = new MaterialContent[scene.MaterialCount]; for (int m = 0; m < scene.MaterialCount; m++) { materials[m] = new BasicMaterialContent(); materials[m].Identity = identity; // For some reason, there is all kinds of nasty junk in this string: materials[m].Name = CleanInput(scene.Materials[m].Name); for (int t = 0; t < scene.Materials[m].GetTextureCount(TextureType.Diffuse); t++) { TextureSlot diffuseMap = scene.Materials[m].GetTexture(TextureType.Diffuse, t); if (!String.IsNullOrEmpty(diffuseMap.FilePath)) { materials[m].Textures.Add("Texture" + (t > 0 ? t.ToString() : ""), new ExternalReference <TextureContent>(diffuseMap.FilePath, identity)); } } } // Bones // We find 'mesh container' nodes with the best names for those meshes while looking for the bones, // and will need them later when we create the MeshContents. I have a feeling that this won't work // in general, and may need to be made more robust. Dictionary <Mesh, string> meshNames = new Dictionary <Mesh, string>(); Dictionary <Node, BoneContent> nodeToBoneMap = new Dictionary <Node, BoneContent>(); BoneContent skeleton = null; // The root bone for the model. List <Node> hierarchyNodes = scene.RootNode.Children.SelectDeep(n => n.Children).ToList(); foreach (Node node in hierarchyNodes) { BoneContent bone = new BoneContent { Name = node.Name, Transform = Matrix.Transpose(ToXna(node.Transform)) }; if (node.MeshIndices != null) { // This node is a 'mesh container' instead of a bone, so we only care about extracting the name of the mesh. foreach (int meshIndex in node.MeshIndices) { if (!meshNames.ContainsKey(scene.Meshes[meshIndex])) { meshNames.Add(scene.Meshes[meshIndex], node.Name); } } } else if (node.Parent == scene.RootNode) { if (skeleton == null) { // This will be our skeleton so put the animations here: if (scene.HasAnimations) { foreach (Animation assimpAnim in scene.Animations) { if (assimpAnim.HasNodeAnimations) { AnimationContent newAnim = new AnimationContent(); newAnim.Identity = identity; newAnim.Duration = TimeSpan.FromSeconds(assimpAnim.DurationInTicks / assimpAnim.TicksPerSecond); newAnim.Name = assimpAnim.Name; foreach (NodeAnimationChannel nac in assimpAnim.NodeAnimationChannels) { Node animatedNode = hierarchyNodes.Find(n => n.Name == nac.NodeName); AnimationChannel newChan = BuildAnimtionChannel(animatedNode, nac); newAnim.Channels.Add(nac.NodeName, newChan); } if (String.IsNullOrEmpty(assimpAnim.Name)) { bone.Animations.Add("SkelematorNoAnimationName", newAnim); } else { bone.Animations.Add(assimpAnim.Name, newAnim); } } } } rootNode.Children.Add(bone); skeleton = bone; } else { context.Logger.LogWarning(null, identity, "Found multiple skeletons in the model, throwing extras away..."); } } else { BoneContent parent = nodeToBoneMap[node.Parent]; parent.Children.Add(bone); } nodeToBoneMap.Add(node, bone); } // Meshes Dictionary <Mesh, MeshContent> meshes = new Dictionary <Mesh, MeshContent>(); foreach (Mesh sceneMesh in scene.Meshes) { // See comment about meshNames at the beginning of the bone section. MeshBuilder mb = MeshBuilder.StartMesh(meshNames[sceneMesh]); mb.SwapWindingOrder = true; // Appears to require this... int positionIndex = -1; for (int v = 0; v < sceneMesh.VertexCount; v++) { Vector3D vert = sceneMesh.Vertices[v]; // CreatePosition should just return a 0-based index of the newly added vertex. positionIndex = mb.CreatePosition(new Vector3(vert.X, vert.Y, vert.Z)); if (positionIndex != v) { throw new InvalidContentException("Something unexpected happened while building a MeshContent from the Assimp scene mesh's vertices. The scene mesh may contains duplicate vertices."); } } if (positionIndex + 1 < 3) { throw new InvalidContentException("There were not enough vertices in the Assimp scene mesh."); } // Create vertex channels int normalVertexChannelIndex = mb.CreateVertexChannel <Vector3>(VertexChannelNames.Normal()); int[] texCoordVertexChannelIndex = new int[sceneMesh.TextureCoordsChannelCount]; for (int x = 0; x < sceneMesh.TextureCoordsChannelCount; x++) { texCoordVertexChannelIndex[x] = mb.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(x)); } int boneWeightVertexChannelIndex = -1; if (sceneMesh.HasBones) { boneWeightVertexChannelIndex = mb.CreateVertexChannel <BoneWeightCollection>(VertexChannelNames.Weights()); } // Prepare vertex channel data BoneWeightCollection[] boneWeightData = null; if (sceneMesh.HasBones) { boneWeightData = new BoneWeightCollection[sceneMesh.VertexCount]; for (int v = 0; v < sceneMesh.VertexCount; v++) { boneWeightData[v] = new BoneWeightCollection(); } foreach (Bone sceneMeshBone in sceneMesh.Bones) { // We have to assume that the bone's name matches up with a node, and therefore one of our BoneContents. foreach (VertexWeight sceneMeshBoneWeight in sceneMeshBone.VertexWeights) { boneWeightData[sceneMeshBoneWeight.VertexID].Add(new BoneWeight(sceneMeshBone.Name, sceneMeshBoneWeight.Weight)); } } for (int v = 0; v < sceneMesh.VertexCount; v++) { if (boneWeightData[v].Count <= 0) { throw new InvalidContentException("Encountered vertices without bone weights."); } boneWeightData[v].NormalizeWeights(); } } // Set the per-geometry data mb.SetMaterial(materials[sceneMesh.MaterialIndex]); mb.SetOpaqueData(new OpaqueDataDictionary()); // Add each vertex for (int f = 0; f < sceneMesh.FaceCount; f++) { if (sceneMesh.Faces[f].IndexCount != 3) { throw new InvalidContentException("Only triangular faces allowed."); } for (int t = 0; t < 3; t++) { mb.SetVertexChannelData(normalVertexChannelIndex, ToXna(sceneMesh.Normals[sceneMesh.Faces[f].Indices[t]])); for (int x = 0; x < sceneMesh.TextureCoordsChannelCount; x++) { mb.SetVertexChannelData(texCoordVertexChannelIndex[x], ToXnaVector2((sceneMesh.GetTextureCoords(x))[sceneMesh.Faces[f].Indices[t]])); } if (sceneMesh.HasBones) { mb.SetVertexChannelData(boneWeightVertexChannelIndex, boneWeightData[sceneMesh.Faces[f].Indices[t]]); } mb.AddTriangleVertex((int)(sceneMesh.Faces[f].Indices[t])); } } MeshContent mesh = mb.FinishMesh(); rootNode.Children.Add(mesh); meshes.Add(sceneMesh, mesh); } return(rootNode); }