public unsafe void TestImportFromMemory() { String path = Path.Combine(TestHelper.RootPath, "TestFiles\\duck.dae"); byte[] memory = File.ReadAllBytes(path); fixed(byte *ptr = memory) { AssimpContext importer = new AssimpContext(); LogStream.IsVerboseLoggingEnabled = true; LogStream logstream = new LogStream(delegate(String msg, String userData) { Console.WriteLine(msg); }); logstream.Attach(); Scene scene = importer.ImportFileFromMemory(new IntPtr(ptr), (uint)memory.Length, ".dae"); Assert.IsNotNull(scene); Assert.IsTrue((scene.SceneFlags & SceneFlags.Incomplete) != SceneFlags.Incomplete); } }
private void LoadModel(Asset asset) { // TODO: Remove assimp var context = new AssimpContext(); var logStream = new LogStream((msg, userData) => { Logging.Log($"{msg}"); }); logStream.Attach(); var extension = Path.GetExtension(asset.MountPath).Substring(1); using var memoryStream = new MemoryStream(asset.Data); memoryStream.Seek(0, SeekOrigin.Begin); var scene = context.ImportFile("Content/" + asset.MountPath, PostProcessSteps.Triangulate | PostProcessSteps.PreTransformVertices | PostProcessSteps.RemoveRedundantMaterials | PostProcessSteps.CalculateTangentSpace | PostProcessSteps.OptimizeMeshes | PostProcessSteps.OptimizeGraph | PostProcessSteps.ValidateDataStructure | PostProcessSteps.GenerateNormals | PostProcessSteps.FlipUVs); directory = Path.GetDirectoryName(asset.MountPath); ProcessNode(scene.RootNode, scene); }
// // IMPOTER // private void InitLog() { LogStream logstream = new LogStream(delegate(String msg, String userData) { Console.WriteLine(msg); }); logstream.Attach(); }
private void button1_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.Cancel) { return; } // Получаем выбранный файл string filename = openFileDialog1.FileName; textBox1.AppendText(String.Format("Load: {0} {1}", filename, Environment.NewLine)); // Включим логи для импортера LogStream logstream = new LogStream(delegate(String msg, String userData) { textBox1.AppendText(msg + Environment.NewLine); }); logstream.Attach(); // Импортиуем UVCoords = new List <Vector3D>(); // Координаты UVVertex = new HashSet <Vector3D>(); // Точки AssimpContext importer = new AssimpContext(); Scene scene = importer.ImportFile(filename, PostProcessSteps.ValidateDataStructure); // (PostProcessSteps.FindInstances | PostProcessSteps.ValidateDataStructure) if (scene.Meshes.Count > 0) { Mesh mesh = scene.Meshes[0]; if (mesh.TextureCoordinateChannelCount > 0) { UVCoords = mesh.TextureCoordinateChannels[0]; foreach (Vector3D uv in UVCoords) { UVVertex.Add(uv); } } } DrawImage(); importer.Dispose(); Refresh(); }
public Scene BuildAssimpScene(MemoryStream model_data, string format_hint) { Scene tmp_scene; using (var importer = new AssimpContext()) { importer.SetConfig(new NormalSmoothingAngleConfig(66.0f)); LogStream logstream = new LogStream((msg, userData) => _logger.Log(msg)); logstream.Attach(); tmp_scene = importer.ImportFileFromStream(model_data , PostProcessPreset.TargetRealTimeFast , format_hint); // we could load the model into our own data structures here } if (tmp_scene == null || tmp_scene.SceneFlags.HasFlag(SceneFlags.Incomplete)) { throw new Exception("Bad file format. Could not read data."); } return(tmp_scene); }
public static Scene LoadFbx(string fileName) { //Create a new importer using (var importer = new AssimpContext()) { //This is how we add a configuration (each config is its own class) NormalSmoothingAngleConfig config = new NormalSmoothingAngleConfig(66.0f); importer.SetConfig(config); //This is how we add a logging callback LogStream logstream = new LogStream(delegate(String msg, String userData) { Console.WriteLine(msg); }); logstream.Attach(); //Import the model. All configs are set. The model //is imported, loaded into managed memory. Then the unmanaged memory is released, and everything is reset. Scene model = importer.ImportFile(fileName, PostProcessPreset.TargetRealTimeMaximumQuality); return(model); } }
public void TestImportFromStream() { String path = Path.Combine(TestHelper.RootPath, "TestFiles\\duck.dae"); FileStream fs = File.OpenRead(path); AssimpContext importer = new AssimpContext(); LogStream.IsVerboseLoggingEnabled = true; LogStream logstream = new LogStream(delegate(String msg, String userData) { Console.WriteLine(msg); }); logstream.Attach(); Scene scene = importer.ImportFileFromStream(fs, ".dae"); fs.Close(); Assert.IsNotNull(scene); Assert.IsTrue((scene.SceneFlags & SceneFlags.Incomplete) != SceneFlags.Incomplete); }
public void TestExportBadFormatId() { AssimpContext importer = new AssimpContext(); NormalSmoothingAngleConfig config = new NormalSmoothingAngleConfig(66.0f); importer.SetConfig(config); LogStream logStream = new LogStream(delegate(string msg, string userData) { Console.WriteLine(msg); }); logStream.Attach(); Scene collada = importer.ImportFile(Path.Combine(TestHelper.RootPath, "TestFiles/duck.dae")); bool success = importer.ExportFile(collada, Path.Combine(TestHelper.RootPath, "TestFiles/output/exportedCollada.dae"), "dae"); Assert.IsFalse(success); success = importer.ExportFile(collada, Path.Combine(TestHelper.RootPath, "TestFiles/output/exportedCollada.dae"), "collada"); Assert.IsTrue(success); }
public static void LoadSource(this RMesh rmesh, string filename) { AssimpContext context = new AssimpContext(); context.SetConfig(new Assimp.Configs.FBXImportAllMaterialsConfig(true)); context.SetConfig(new Assimp.Configs.FBXImportAllGeometryLayersConfig(true)); context.SetConfig(new Assimp.Configs.MultithreadingConfig(2)); context.SetConfig(new Assimp.Configs.FBXStrictModeConfig(false)); if (!context.IsImportFormatSupported(Path.GetExtension(filename))) { throw new ReactorException("Attempted to load a model that Assimp doesn't know how to load"); } LogStream log = new LogStream((msg, user) => { RLog.Info(msg.Remove(msg.Length - 2)); }); log.Attach(); int platform = (int)Environment.OSVersion.Platform; Scene scene = context.ImportFile(filename, PostProcessSteps.FindInvalidData | PostProcessSteps.GenerateSmoothNormals | PostProcessSteps.Triangulate | PostProcessSteps.GenerateUVCoords | PostProcessSteps.CalculateTangentSpace | PostProcessSteps.PreTransformVertices); if (scene.HasMeshes) { foreach (Mesh mesh in scene.Meshes) { if (!mesh.HasVertices) { continue; } RMeshPart rmeshpart = RMeshPart.Create <RMeshPart> (); RVertexData [] data = new RVertexData [mesh.VertexCount]; List <int> indicesList = new List <int> (); if (mesh.HasFaces) { foreach (Face face in mesh.Faces) { indicesList.AddRange(face.Indices.ToArray()); foreach (int index in face.Indices) { Vector3D p = mesh.Vertices [index]; data [index].Position = new Vector3(p.X, p.Y, p.Z); if (mesh.HasTextureCoords(0)) { Vector3D t = mesh.TextureCoordinateChannels [0] [index]; data [index].TexCoord = new Vector2(t.X, -t.Y); } if (mesh.HasNormals) { Vector3D n = mesh.Normals [index]; data [index].Normal = new Vector3(n.X, n.Y, n.Z); } if (mesh.HasTangentBasis) { Vector3D b = mesh.BiTangents [index]; Vector3D t = mesh.Tangents [index]; data [index].Bitangent = new Vector3(b.X, b.Y, b.Z); data [index].Tangent = new Vector3(t.X, t.Y, t.Z); } } } } RVertexBuffer vbuffer = new RVertexBuffer(typeof(RVertexData), mesh.VertexCount, RBufferUsage.WriteOnly, true); RIndexBuffer ibuffer = new RIndexBuffer(typeof(int), indicesList.Count, RBufferUsage.WriteOnly); ibuffer.SetData(indicesList.ToArray()); vbuffer.SetData <RVertexData> (data); #if WINDOWS var separator = "\\"; #else var separator = "/"; #endif rmeshpart.VertexBuffer = vbuffer; rmeshpart.IndexBuffer = ibuffer; RMaterial material = new RMaterial(rmesh.Name + ":Material"); if (scene.HasMaterials) { Material mat = scene.Materials[mesh.MaterialIndex]; material.Shininess = mat.Shininess; material.SetColor(RMaterialColor.DIFFUSE, new RColor(mat.ColorDiffuse.R, mat.ColorDiffuse.G, mat.ColorDiffuse.B, mat.ColorDiffuse.A)); if (mat.HasTextureDiffuse) { var texFileName = Path.GetFileName(mat.TextureDiffuse.FilePath.Replace("\\", separator).Replace("/", separator)); RTexture2D tex = (RTexture2D)RTextures.Instance.CreateTexture <RTexture2D>(texFileName, "/textures/" + texFileName.ToLower()); tex.Bind(); tex.GenerateMipmaps(); tex.SetTextureMagFilter(RTextureMagFilter.Linear); tex.SetTextureMinFilter(RTextureMinFilter.LinearMipmapLinear); tex.SetTextureWrapMode(RTextureWrapMode.Repeat, RTextureWrapMode.Repeat); tex.Unbind(); material.SetTexture(RTextureLayer.DIFFUSE, tex); } if (mat.HasTextureNormal) { var texFileName = Path.GetFileName(mat.TextureNormal.FilePath.Replace("\\", separator).Replace("/", separator)); RTexture2D tex = (RTexture2D)RTextures.Instance.CreateTexture <RTexture2D>(texFileName, "/textures/" + texFileName.ToLower()); tex.Bind(); tex.GenerateMipmaps(); tex.SetTextureMagFilter(RTextureMagFilter.Linear); tex.SetTextureMinFilter(RTextureMinFilter.LinearMipmapLinear); tex.SetTextureWrapMode(RTextureWrapMode.Repeat, RTextureWrapMode.Repeat); tex.Unbind(); material.SetTexture(RTextureLayer.NORMAL, tex); } if (mat.HasTextureAmbient) { var texFileName = Path.GetFileName(mat.TextureAmbient.FilePath.Replace("\\", separator).Replace("/", separator)); RTexture2D tex = (RTexture2D)RTextures.Instance.CreateTexture <RTexture2D>(texFileName, "/textures/" + texFileName.ToLower()); tex.SetTextureMagFilter(RTextureMagFilter.Linear); tex.SetTextureMinFilter(RTextureMinFilter.LinearMipmapLinear); tex.SetTextureWrapMode(RTextureWrapMode.Repeat, RTextureWrapMode.Repeat); material.SetTexture(RTextureLayer.AMBIENT, tex); } if (mat.HasTextureHeight) { var texFileName = Path.GetFileName(mat.TextureHeight.FilePath.Replace("\\", separator).Replace("/", separator)); RTexture2D tex = (RTexture2D)RTextures.Instance.CreateTexture <RTexture2D>(texFileName, "/textures/" + texFileName.ToLower()); tex.SetTextureMagFilter(RTextureMagFilter.Linear); tex.SetTextureMinFilter(RTextureMinFilter.LinearMipmapLinear); tex.SetTextureWrapMode(RTextureWrapMode.Repeat, RTextureWrapMode.Repeat); material.SetTexture(RTextureLayer.HEIGHT, tex); } if (mat.HasTextureEmissive) { var texFileName = Path.GetFileName(mat.TextureEmissive.FilePath.Replace("\\", separator).Replace("/", separator)); RTexture2D tex = (RTexture2D)RTextures.Instance.CreateTexture <RTexture2D>(texFileName, "/textures/" + texFileName.ToLower()); tex.SetTextureMagFilter(RTextureMagFilter.Linear); tex.SetTextureMinFilter(RTextureMinFilter.LinearMipmapLinear); tex.SetTextureWrapMode(RTextureWrapMode.Repeat, RTextureWrapMode.Repeat); material.SetTexture(RTextureLayer.GLOW, tex); } if (mat.HasTextureSpecular) { var texFileName = Path.GetFileName(mat.TextureSpecular.FilePath.Replace("\\", separator).Replace("/", separator)); RTexture2D tex = (RTexture2D)RTextures.Instance.CreateTexture <RTexture2D>(texFileName, "/textures/" + texFileName.ToLower()); tex.SetTextureMagFilter(RTextureMagFilter.Linear); tex.SetTextureMinFilter(RTextureMinFilter.LinearMipmapLinear); tex.SetTextureWrapMode(RTextureWrapMode.Repeat, RTextureWrapMode.Repeat); material.SetTexture(RTextureLayer.SPECULAR, tex); } } rmeshpart.Material = material; rmesh.Parts.Add(rmeshpart); } //return rmesh; } //return null; if (rmesh.Parts.Count == 0) { throw new ReactorException("Attempted to load a model when Assimp couldn't find any verticies!"); } context.Dispose(); }
public override bool Execute(List <string> args) { if (args.Count < 1 || args.Count > 2) { return(false); } TagInstance destination = _cache.Tags[0x3317]; if (args.Count == 2) { destination = ArgumentParser.ParseTagIndex(_cache, args[0]); if (!destination.IsInGroup("mode")) { Console.WriteLine("Specified tag is not a render_model: " + args[0]); return(false); } args = args.Skip(1).ToList(); } var builder = new RenderModelBuilder(_info.Version); // Add a root node var node = builder.AddNode(new RenderModel.Node { Name = _stringIds.GetStringId("street_cone"), ParentNode = -1, FirstChildNode = -1, NextSiblingNode = -1, DefaultRotation = new Vector4(0, 0, 0, -1), DefaultScale = 1, InverseForward = new Vector3(1, 0, 0), InverseLeft = new Vector3(0, 1, 0), InverseUp = new Vector3(0, 0, 1), }); // Begin building the default region and permutation builder.BeginRegion(_stringIds.GetStringId("default")); builder.BeginPermutation(_stringIds.GetStringId("default")); using (var importer = new AssimpContext()) { Scene model; using (var logStream = new LogStream((msg, userData) => Console.WriteLine(msg))) { logStream.Attach(); model = importer.ImportFile(args[0], PostProcessSteps.CalculateTangentSpace | PostProcessSteps.GenerateNormals | PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.PreTransformVertices | PostProcessSteps.Triangulate); logStream.Detach(); } Console.WriteLine("Assembling vertices..."); // Build a multipart mesh from the model data, // with each model mesh mapping to a part of one large mesh and having its own material builder.BeginMesh(); ushort partStartVertex = 0; ushort partStartIndex = 0; var vertices = new List <RigidVertex>(); var indices = new List <ushort>(); foreach (var mesh in model.Meshes) { for (var i = 0; i < mesh.VertexCount; i++) { var position = mesh.Vertices[i]; var normal = mesh.Normals[i]; var uv = mesh.TextureCoordinateChannels[0][i]; var tangent = mesh.Tangents[i]; var bitangent = mesh.BiTangents[i]; vertices.Add(new RigidVertex { Position = new Vector4(position.X, position.Y, position.Z, 1), Normal = new Vector3(normal.X, normal.Y, normal.Z), Texcoord = new Vector2(uv.X, uv.Y), Tangent = new Vector4(tangent.X, tangent.Y, tangent.Z, 1), Binormal = new Vector3(bitangent.X, bitangent.Y, bitangent.Z), }); } // Build the index buffer var meshIndices = mesh.GetIndices(); indices.AddRange(meshIndices.Select(i => (ushort)(i + partStartVertex))); // Define a material and part for this mesh var material = builder.AddMaterial(new RenderMaterial { RenderMethod = _cache.Tags[0x101F], }); builder.DefinePart(material, partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount); // Move to the next part partStartVertex += (ushort)mesh.VertexCount; partStartIndex += (ushort)meshIndices.Length; } // Bind the vertex and index buffers builder.BindRigidVertexBuffer(vertices, node); builder.BindIndexBuffer(indices, PrimitiveType.TriangleList); builder.EndMesh(); } builder.EndPermutation(); builder.EndRegion(); Console.WriteLine("Building Blam mesh data..."); var resourceStream = new MemoryStream(); var renderModel = builder.Build(_info.Serializer, resourceStream); Console.WriteLine("Writing resource data..."); // Add a new resource for the model data var resources = new ResourceDataManager(); resources.LoadCachesFromDirectory(_fileInfo.DirectoryName); resourceStream.Position = 0; resources.Add(renderModel.Geometry.Resource, ResourceLocation.Resources, resourceStream); Console.WriteLine("Writing tag data..."); using (var cacheStream = _fileInfo.Open(FileMode.Open, FileAccess.ReadWrite)) { var tag = destination; var context = new TagSerializationContext(cacheStream, _cache, _stringIds, tag); _info.Serializer.Serialize(context, renderModel); } Console.WriteLine("Model imported successfully!"); return(true); }
public static void Init() { AssimpContext importer = new AssimpContext(); NormalSmoothingAngleConfig config = new NormalSmoothingAngleConfig(66.0f); importer.SetConfig(config); LogStream logStream = new LogStream(delegate(string msg, string userData) { Console.WriteLine(msg); }); logStream.Attach(); Scene scene = importer.ImportFile(@"resources/icosphere.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.Icosphere = scene.Meshes[0]; scene = importer.ImportFile(@"resources/icosphereHigh.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.IcosphereHigh = scene.Meshes[0]; scene = importer.ImportFile(@"resources/asteroid.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.Asteroid = scene.Meshes[0]; scene = importer.ImportFile(@"resources/point.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.Point = scene.Meshes[0]; scene = importer.ImportFile(@"resources/cube.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.Cube = scene.Meshes[0]; scene = importer.ImportFile(@"resources/camera.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.Camera = scene.Meshes[0]; scene = importer.ImportFile(@"resources/skybox.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.SkyboxFront = scene.Meshes[0]; Mesh.SkyboxBack = scene.Meshes[1]; Mesh.SkyboxRight = scene.Meshes[2]; Mesh.SkyboxLeft = scene.Meshes[3]; Mesh.SkyboxTop = scene.Meshes[4]; Mesh.SkyboxBottom = scene.Meshes[5]; scene = importer.ImportFile(@"resources/gizmoPosX.ply", PostProcessPreset.TargetRealTimeQuality); Mesh.GizmoXPos = scene.Meshes[0]; scene = importer.ImportFile(@"resources/gizmoPosY.ply", PostProcessPreset.TargetRealTimeQuality); Mesh.GizmoYPos = scene.Meshes[0]; scene = importer.ImportFile(@"resources/gizmoPosZ.ply", PostProcessPreset.TargetRealTimeQuality); Mesh.GizmoZPos = scene.Meshes[0]; scene = importer.ImportFile(@"resources/gizmoRotX.ply", PostProcessPreset.TargetRealTimeQuality); Mesh.GizmoXRot = scene.Meshes[0]; scene = importer.ImportFile(@"resources/gizmoRotY.ply", PostProcessPreset.TargetRealTimeQuality); Mesh.GizmoYRot = scene.Meshes[0]; scene = importer.ImportFile(@"resources/gizmoRotZ.ply", PostProcessPreset.TargetRealTimeQuality); Mesh.GizmoZRot = scene.Meshes[0]; scene = importer.ImportFile(@"resources/text000.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.Text000 = scene.Meshes[0]; scene = importer.ImportFile(@"resources/text090.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.Text090 = scene.Meshes[0]; scene = importer.ImportFile(@"resources/text180.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.Text180 = scene.Meshes[0]; scene = importer.ImportFile(@"resources/text270.obj", PostProcessPreset.TargetRealTimeQuality); Mesh.Text270 = scene.Meshes[0]; importer.Dispose(); logStream.Detach(); }
static public AssimpVolume LoadFromFile(string filename) { string path = Path.Combine("Assets", "Models", filename); AssimpContext importer = new AssimpContext(); NormalSmoothingAngleConfig normalSmoothing = new NormalSmoothingAngleConfig(66.0f); importer.SetConfig(normalSmoothing); LogStream logStream = new LogStream ( delegate(string message, string userData) { Console.Write(message); } ); logStream.Attach(); Scene model = importer.ImportFile(path, PostProcessPreset.TargetRealTimeMaximumQuality); Mesh mesh = model.Meshes[0]; AssimpVolume v = new AssimpVolume(); List <Vector3> newVertices = new List <Vector3>(); foreach (Assimp.Vector3D vert in mesh.Vertices) { newVertices.Add(new Vector3(vert.X, vert.Y, vert.Z)); } v.vertices = newVertices.ToArray(); v.indices = mesh.GetIndices(); if (mesh.HasNormals) { v.generateNormals = false; List <Vector3> newNormals = new List <Vector3>(); foreach (Assimp.Vector3D n in mesh.Normals) { newNormals.Add(new Vector3(n.X, n.Y, n.Z)); } v.normals = newNormals.ToArray(); } if (mesh.HasTextureCoords(0)) { List <Vector2> newTextureCoords = new List <Vector2>(); foreach (Assimp.Vector3D tc in mesh.TextureCoordinateChannels[0]) { newTextureCoords.Add(new Vector2(tc.X, tc.Y)); } v.textureCoords = newTextureCoords.ToArray(); } if (mesh.HasVertexColors(0)) { List <Vector3> newColors = new List <Vector3>(); foreach (Assimp.Color4D c in mesh.VertexColorChannels[0]) { newColors.Add(new Vector3(c.R, c.G, c.B)); } v.colors = newColors.ToArray(); } importer.Dispose(); return(v); }
public LogPipe(LogStore logStore) { _logStore = logStore; _stream = new LogStream(LogStreamCallback); _stream.Attach(); }
public override object Execute(List <string> args) { if (args.Count < 1 || args.Count > 2) { return(false); } var stringIdCount = Cache.StringTable.Count; var destinationTag = Cache.TagCache.GetTag(@"objects\gear\human\industrial\street_cone\street_cone", "mode"); string vertexType = "rigid"; if (args[0] == "skinned" || args[0] == "rigid") { vertexType = args[0]; args.RemoveAt(0); } if (args.Count == 2) { if (!Cache.TryGetTag(args[0], out destinationTag) || !destinationTag.IsInGroup("mode")) { Console.WriteLine("Specified tag is not a render_model: " + args[0]); return(false); } args.RemoveAt(0); } RenderModel edMode = null; using (var cacheStream = Cache.OpenCacheReadWrite()) edMode = Cache.Deserialize <RenderModel>(cacheStream, destinationTag); // Get a list of the original nodes var nodeIndices = new Dictionary <string, int>(); foreach (var a in edMode.Nodes) { nodeIndices.Add(Cache.StringTable.GetString(a.Name), edMode.Nodes.IndexOf(a)); } // Read the custom model file if (!File.Exists(args[0])) { return(false); } Console.WriteLine($"File date: {File.GetLastWriteTime(args[0])}"); var builder = new RenderModelBuilder(Cache); using (var importer = new AssimpContext()) { Scene model; if (vertexType == "skinned") { using (var logStream = new LogStream((msg, userData) => Console.WriteLine(msg))) { logStream.Attach(); model = importer.ImportFile(args[0], PostProcessSteps.CalculateTangentSpace | PostProcessSteps.GenerateNormals | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.Triangulate); logStream.Detach(); } for (var i = 0; i < model.Meshes.Count; i++) { if (!model.Meshes[i].HasBones) { throw new Exception($"Mesh \"{model.Meshes[i].Name}\" has no bones!"); } } } else { using (var logStream = new LogStream((msg, userData) => Console.WriteLine(msg))) { logStream.Attach(); model = importer.ImportFile(args[0], PostProcessSteps.CalculateTangentSpace | PostProcessSteps.GenerateNormals | PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.PreTransformVertices | PostProcessSteps.Triangulate); logStream.Detach(); } } Console.WriteLine("Assembling vertices..."); // Add nodes var rigidNode = builder.AddNode(new RenderModel.Node { Name = Cache.StringTable.GetStringId("street_cone"), ParentNode = -1, FirstChildNode = -1, NextSiblingNode = -1, DefaultRotation = new RealQuaternion(0, 0, 0, -1), DefaultScale = 1, InverseForward = new RealVector3d(1, 0, 0), InverseLeft = new RealVector3d(0, 1, 0), InverseUp = new RealVector3d(0, 0, 1), }); // Build a multipart mesh from the model data, // with each model mesh mapping to a part of one large mesh and having its own material ushort partStartVertex = 0; ushort partStartIndex = 0; var rigidVertices = new List <RigidVertex>(); var skinnedVertices = new List <SkinnedVertex>(); var indices = new List <ushort>(); Dictionary <string, int> newNodes = new Dictionary <string, int>(); foreach (var mesh in model.Meshes) { var meshIndex = model.Meshes.IndexOf(mesh); Console.Write($"Enter a region name for '{mesh.Name}' (mesh index {meshIndex}): "); var regionName = Console.ReadLine(); var regionStringId = Cache.StringTable.GetStringId(regionName); if (regionStringId == StringId.Invalid) { regionStringId = Cache.StringTable.AddString(regionName); } // Begin building the default region and permutation builder.BeginRegion(regionStringId); builder.BeginPermutation(Cache.StringTable.GetStringId("default")); builder.BeginMesh(); for (var i = 0; i < mesh.VertexCount; i++) { var position = mesh.Vertices[i]; var normal = mesh.Normals[i]; var uv = mesh.TextureCoordinateChannels[0][i]; var tangent = mesh.Tangents.Count != 0 ? mesh.Tangents[i] : new Vector3D(); var bitangent = mesh.BiTangents.Count != 0 ? mesh.BiTangents[i] : new Vector3D(); if (vertexType == "skinned") { var blendIndicesList = new List <byte>(); var blendWeightsList = new List <float>(); var bonesList = new List <string>(); foreach (var bone in mesh.Bones) { foreach (var vertexInfo in bone.VertexWeights) { if (vertexInfo.VertexID == i) { bonesList.Add(bone.Name); blendIndicesList.Add((byte)nodeIndices[bone.Name]); blendWeightsList.Add(vertexInfo.Weight); } } } var blendIndices = new byte[4]; var blendWeights = new float[4]; for (int j = 0; j < blendIndicesList.Count; j++) { if (j < 4) { blendIndices[j] = blendIndicesList[j]; } } for (int j = 0; j < blendWeightsList.Count; j++) { if (j < 4) { blendWeights[j] = blendWeightsList[j]; } } skinnedVertices.Add(new SkinnedVertex { Position = new RealQuaternion(position.X, position.Y, position.Z, 1), Texcoord = new RealVector2d(uv.X, -uv.Y), Normal = new RealVector3d(normal.X, normal.Y, normal.Z), Tangent = new RealQuaternion(tangent.X, tangent.Y, tangent.Z, 1), Binormal = new RealVector3d(bitangent.X, bitangent.Y, bitangent.Z), BlendIndices = blendIndices, BlendWeights = blendWeights }); } else { rigidVertices.Add(new RigidVertex { Position = new RealQuaternion(position.X, position.Y, position.Z, 1), Texcoord = new RealVector2d(uv.X, -uv.Y), Normal = new RealVector3d(normal.X, normal.Y, normal.Z), Tangent = new RealQuaternion(tangent.X, tangent.Y, tangent.Z, 1), Binormal = new RealVector3d(bitangent.X, bitangent.Y, bitangent.Z), }); } } // Build the index buffer var meshIndices = mesh.GetIndices(); indices.AddRange(meshIndices.Select(i => (ushort)(i + partStartVertex))); // Define a material and part for this mesh var material = builder.AddMaterial(new RenderMaterial { RenderMethod = Cache.TagCache.GetTag(@"shaders\invalid", "rmsh"), }); builder.BeginPart(material, partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount); builder.DefineSubPart(partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount); builder.EndPart(); // Move to the next part partStartVertex += (ushort)mesh.VertexCount; partStartIndex += (ushort)meshIndices.Length; // Bind the vertex and index buffers if (vertexType == "skinned") { builder.BindSkinnedVertexBuffer(skinnedVertices); } else { builder.BindRigidVertexBuffer(rigidVertices, rigidNode); } builder.BindIndexBuffer(indices, IndexBufferFormat.TriangleList); builder.EndMesh(); builder.EndPermutation(); builder.EndRegion(); } } Console.Write("Building render_geometry..."); var resourceStream = new MemoryStream(); var renderModel = builder.Build(Cache.Serializer, resourceStream); if (vertexType == "skinned") { // Copy required data from the original render_model tag renderModel.Nodes = edMode.Nodes; renderModel.MarkerGroups = edMode.MarkerGroups; renderModel.RuntimeNodeOrientations = edMode.RuntimeNodeOrientations; } Console.WriteLine("done."); // // Serialize the new render_model tag // Console.Write("Writing render_model tag data..."); using (var cacheStream = Cache.OpenCacheReadWrite()) Cache.Serialize(cacheStream, destinationTag, renderModel); Console.WriteLine("done."); // // Save any new string ids // if (stringIdCount != Cache.StringTable.Count) { Console.Write("Saving string ids..."); Cache.SaveStrings(); Console.WriteLine("done"); } Console.WriteLine("Model imported successfully!"); return(true); }
static int nullBonesC = 0; //TODO remove this counter public static void Main(string[] args) { //Dir if (Directory.Exists("./obj")) { Console.WriteLine("Directory Found"); } else { printError("Creating Dir"); Directory.CreateDirectory("./obj"); } //File Input string fileName = "./obj/" + getUserInput("File name"); if (fileName == "./obj/") { string[] possibleFiles = Directory.GetFiles("./obj"); foreach (string currFileName in possibleFiles) { if (!currFileName.EndsWith(".txt") && !currFileName.EndsWith(".js")) { fileName = currFileName; break; } } } else { string[] possibleFiles = Directory.GetFiles("./obj"); foreach (string currFileName in possibleFiles) { if (!currFileName.Contains("fileName")) { fileName = currFileName; break; } } } Console.WriteLine("Files found, starting to read them"); try { File.Delete("./obj/output.txt"); } catch (Exception e) { printError("No file to delete, ignore this error" + e); } //Create a new importer AssimpContext importer = new AssimpContext(); importer.SetConfig(new IFCUseCustomTriangulationConfig(true)); importer.SetConfig(new SortByPrimitiveTypeConfig(PrimitiveType.Line | PrimitiveType.Point)); importer.SetConfig(new VertexBoneWeightLimitConfig(4)); //This is how we add a configuration (each config is its own class) //NormalSmoothingAngleConfig config = new NormalSmoothingAngleConfig(66.0f); //importer.SetConfig(config); //This is how we add a logging callback LogStream logstream = new LogStream(delegate(String msg, String userData) { Console.WriteLine(msg); }); logstream.Attach(); //Import the model. All configs are set. The model //is imported, loaded into managed memory. Then the unmanaged memory is released, and everything is reset. //Triangulating is already being done //TODO aiProcess_JoinIdenticalVertices (Index buffer objects) scene = importer.ImportFile(fileName, PostProcessPreset.TargetRealTimeMaximumQuality | PostProcessSteps.FlipUVs | PostProcessSteps.OptimizeMeshes | PostProcessSteps.OptimizeGraph | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.LimitBoneWeights); extractBones(scene.RootNode); createBoneTree(scene.RootNode, -1, Matrix4x4.Identity); parseNode(scene.RootNode); //End of example importer.Dispose(); adjVert = (Lookup <Vector3D, triAndVertIndex>)toLookup.ToLookup((item) => item.Key, (item) => item.Value); //First 3 => Point, Second 3 => Line //TODO Make this a bit better //For each triangle, store some bary coords Bary[] bary = new Bary[normals.Count]; //Filled with: default( int ) //Edit #region Bary coords and bones //Lines: for (int j = 0; j < toLookup.Count; j += 3) { Vector3D v0 = toLookup[j + 2].Key - toLookup[j + 1].Key; Vector3D v1 = toLookup[j + 2].Key - toLookup[j].Key; Vector3D v2 = toLookup[j + 1].Key - toLookup[j].Key; double area = Math.Abs(Vector3D.Cross(v1, v2).Length()) / 2; //Determinant of a 2D matrix, used to calculate the area of a parallelogram IEnumerable <triAndVertIndex> matchingVertices0 = adjVert[toLookup[j].Key]; IEnumerable <triAndVertIndex> matchingVertices1 = adjVert[toLookup[j + 1].Key]; IEnumerable <triAndVertIndex> matchingVertices2 = adjVert[toLookup[j + 2].Key]; //2 Matching points //TriIndex = triangle index of the adjacent triangle foreach (triAndVertIndex index in matchingVertices0) { //Oh, yeah! It's working! (Magic!) //TODO turn this into a function as well foreach (triAndVertIndex otherIndex in matchingVertices1) { //If it is part of the same line if (otherIndex.triIndex == index.triIndex) { double angleBetweenTriangles = (Vector3D.Dot(faceNormals[j / 3], faceNormals[otherIndex.triIndex])); if (angleBetweenTriangles < THRESHOLD) { //area = 1/2*base*height //2*area / base = height /* * dist = vec3(area / v0.Length(), 0, 0); * gl_Position = gl_PositionIn[0]; * EmitVertex(); * dist = vec3(0, area / v1.Length(), 0); * gl_Position = gl_PositionIn[1]; * EmitVertex(); * dist = vec3(0, 0, area / v2.Length()); * gl_Position = gl_PositionIn[2]; * EmitVertex();*/ bary[j / 3].l2 = area / v2.Length(); // 1;// angleBetweenTriangles + addTo; } //If we found the adjacent triangle, we can go to the next one break; } } } foreach (triAndVertIndex index in matchingVertices1) { foreach (triAndVertIndex otherIndex in matchingVertices2) { if (otherIndex.triIndex == index.triIndex) { double angleBetweenTriangles = (Vector3D.Dot(faceNormals[j / 3], faceNormals[otherIndex.triIndex])); if (angleBetweenTriangles < THRESHOLD) { bary[j / 3].l0 = area / v0.Length(); // TODO angleBetweenTriangles + addTo; } break; } } } foreach (triAndVertIndex index in matchingVertices2) { foreach (triAndVertIndex otherIndex in matchingVertices0) { if (otherIndex.triIndex == index.triIndex) { double angleBetweenTriangles = (Vector3D.Dot(faceNormals[j / 3], faceNormals[otherIndex.triIndex])); if (angleBetweenTriangles < THRESHOLD) { bary[j / 3].l1 = area / v1.Length(); // TODO angleBetweenTriangles + addTo; } break; } } } } //Draw the points as well for (int j = 0; j < toLookup.Count; j += 3) { Vector3D v0 = toLookup[j + 2].Key - toLookup[j + 1].Key; Vector3D v1 = toLookup[j + 2].Key - toLookup[j].Key; Vector3D v2 = toLookup[j + 1].Key - toLookup[j].Key; double area = Math.Abs(Vector3D.Cross(v1, v2).Length()) / 2; //Determinant of a 2D matrix, used to calculate the area of a parallelogram IEnumerable <triAndVertIndex> matchingVertices0 = adjVert[toLookup[j].Key]; IEnumerable <triAndVertIndex> matchingVertices1 = adjVert[toLookup[j + 1].Key]; IEnumerable <triAndVertIndex> matchingVertices2 = adjVert[toLookup[j + 2].Key]; /*int numberOfAdjBary = 0; * * //Index of the adjacent triangle * foreach (triAndVertIndex index in matchingVertices0) * { * //TODO turn this into a function as well * if ((bary[index.triIndex], ((index.vertIndex + 1) % 3) + 3] > 0 || bary[index.triIndex, ((index.vertIndex + 2) % 3) + 3] > 0) * && index.triIndex != j / 3) * { * numberOfAdjBary++; * } * } * //Every line is actually 2 lines * if (numberOfAdjBary >= 4) * { * //Now, we need to do the point calculations * double dist0 = area / v0.Length(); * //bary[j / 3, 0] = ; * } * numberOfAdjBary = 0; * foreach (triAndVertIndex index in matchingVertices1) * { * if ((bary[index.triIndex, ((index.vertIndex + 1) % 3) + 3] > 0 || bary[index.triIndex, ((index.vertIndex + 2) % 3) + 3] > 0) * && index.triIndex != j / 3) * { * numberOfAdjBary++; * } * } * if (numberOfAdjBary >= 4) * { * bary[j / 3, 1] = area / v1.Length(); * } * numberOfAdjBary = 0; * foreach (triAndVertIndex index in matchingVertices2) * { * if ((bary[index.triIndex, ((index.vertIndex + 1) % 3) + 3] > 0 || bary[index.triIndex, ((index.vertIndex + 2) % 3) + 3] > 0) * && index.triIndex != j / 3) * { * numberOfAdjBary++; * } * } * if (numberOfAdjBary >= 4) * { * bary[j / 3, 2] = area / v2.Length(); * }***/ } #endregion #if true //Create the output file StreamWriter JSONFile = File.CreateText("./obj/output.txt"); //Write to file JSONFile.Write("model = ["); bool firstTime = true; for (int j = 0, texCount = 0; j < vertices.Count; j++) { var index = j - texCount; Vector3D[] currVert = Program.vertices[j]; if (currVert.Length == 1) { if (firstTime) { JSONFile.Write("{"); firstTime = false; } else { JSONFile.Write("]},\n{"); } JSONFile.Write("name:\"" + texNames[(int)currVert[0].X] + "\",model:["); Console.Write(texNames[(int)currVert[0].X] + "---"); texCount++; } else { //Edit string[] baryCoordsOfTri = toBary(bary[index]); //Triangle for (int i = 0; i < 3; i++) { JSONFile.Write(Vec3DToString(currVert[i])); JSONFile.Write(UVToString(uvs[index][i])); JSONFile.Write(Vec3DToString(normals[index][i])); JSONFile.Write(baryCoordsOfTri[i]); bones[index][i].Weights[1] = 0; if (bones[index][i].BoneIDs[1] == -1) { bones[index][i].Weights[0] = 1; } if (bones[index][i].Weights[0] == 0.5) { bones[index][i].Weights[0] = 0.49f; } JSONFile.Write((bones[index][i].BoneIDs[0] + 0.5) + "," + (bones[index][i].BoneIDs[1] + 0.5) + "," + bones[index][i].Weights[0] + ","); if (bones[index][i].Weights[0] > 0.45 && bones[index][i].Weights[0] < 0.55) { //printError("W1: " + string.Join(",.,", bones[index][i].Weights)); } if (bones[index][i].Weights[0] > 0.9) { //printError("W1: " + string.Join(",.,", bones[index][i].Weights)); } } } } JSONFile.Write("]}];"); JSONFile.Close(); #endif StreamWriter bonesFile = File.CreateText("./obj/outputBones.txt"); //You are going to have to reorder the parts manually bonesFile.Write("bones = ["); foreach (BoneInfo boneNode in boneNodesList) { //TODO Number of bones (To nearest power of 2) //TODO Max number of influencing bones per vertex Quaternion rot, offsetRot; Vector3D translation, offsetTranslation; Vector3D scale, offsetScale; boneNode.localMat.Decompose(out scale, out rot, out translation); boneNode.BoneOffsetMatrix.Decompose(out offsetScale, out offsetRot, out offsetTranslation); //Console.WriteLine(QuaternionToString(rot) + "->\n" + MatToString1(rot.GetMatrix())); //Console.WriteLine(QuaternionToString(rot) + "->\n" + Matrix4x4.FromTranslation(translation)); //Don't use .ToString(), use a custom function! bonesFile.WriteLine( "{name:\"" + boneNode.Name + "\",parent:" + boneNode.Parent + ",pos:[" + Vec3DToString(translation, false) + "],qRot:[" + QuaternionToString(rot) + "],offsetPos:[" + Vec3DToString(offsetTranslation, false) + "],offsetRot:[" + QuaternionToString(offsetRot) + "]},"); } bonesFile.Write("];"); bonesFile.WriteLine("\nvar animations = [];"); bonesFile.Close(); try { File.Delete("./obj/output.js"); } catch (Exception) { }; try { File.Delete("./obj/outputBones.js"); } catch (Exception) { }; try { File.Move("./obj/output.txt", Path.ChangeExtension("./obj/output.txt", ".js")); } catch (Exception) { }; try { File.Move("./obj/outputBones.txt", Path.ChangeExtension("./obj/outputBones.txt", ".js")); } catch (Exception) { }; Console.WriteLine("Info: {0} Bones {1} vertices without bones", boneNodesList.Count, nullBonesC); Console.WriteLine("DONE!"); Console.Read(); }