[{"content":"Model importer using SharpGLTF for OpenTK Hey! This blog would be how I implemented a model importer using SharpGLTF that imports .glb as raw data that we can then render using OpenTK. I tried to find a beginner guide on this but there isn\u0026rsquo;t a lot of stuff available apart from the examples (which to be honest proved to be of no use for me)\nThe game engine I\u0026rsquo;ve been working on does not have multiple features so we will only be going over the top.\nA glTF file is basically a JSON file that has a scene and multiple nodes and meshes inside. The nodes of that file can have different components attached to it (mesh, camera etc). For my game engine, I converted each node into an instance of Gameobject and then added a Mesh and MeshRenderer component to them.\nYou can refer to https://github.khronos.org/glTF-Tutorials/gltfTutorial/ for a more detailed tutorial/guide on glTF files.\nFirst step is adding SharpGLTF as a dependency. You can grab the NuGet package or get it from its Github repository.\nHandling the scenes and nodes To load a model, we can call ModelRoot.Load(modelPath) where modelPath is the path of the model.\nFrom here on, based on how your engine is made, you can either recursively go through all the nodes in the scene, or just take all the meshes and render them. For my engine, I just created a gameobject for each node and added the children based on the nodes.\nOur main model begins at a scene, so we assign a variable to it var scene = model.DefaultScene; . Then, we can loop through all of the nodes in the scene:\nforeach (var node in scene.VisualChildren) { //Handle nodes ImportNode(node, gameobject); } To handle the nodes, I created another function static void ImportNode(Node node, Gameobject parent) which can handle each node.\nTo handle each node, what I did was obtain the local transform of the node using Matrix4x4 local = node.LocalMatrix;. We can then decompose the matrix to obtain the values:\nMatrix4x4.Decompose( local, out Vector3 scale, out Quaternion rotation, out Vector3 translation ); And then I assign these values to my Gameobject that is created using the node.\nI can then recursively run this function in order to obtain every single node.\nforeach (var child in node.VisualChildren) ImportNode(child, go, shader); If the node has a mesh, I run another function ImportMesh(node.Mesh, go, shader) and in the ImportNode method if (node.Mesh != null) ImportMesh(node.Mesh, go);\nWhere go is just my gameobject. For every mesh, I create another gameobject.\nImporting the mesh We can obtain the list primitives from the mesh using mesh.primitives. We can then loop through the list. To actually obtain our data, we need to create and use accessors.\nvar positionAccessor = primitive.GetVertexAccessor(\u0026quot;POSITION\u0026quot;); var normalAccessor = primitive.GetVertexAccessor(\u0026quot;NORMAL\u0026quot;); var texAccessor = primitive.GetVertexAccessor(\u0026quot;TEXCOORD_0\u0026quot;); var indexAccessor = primitive.GetIndexAccessor(); We then convert those accessors into arrays\nvar positions = positionAccessor.AsVector3Array().ToArray(); var normals = normalAccessor?.AsVector3Array().ToArray(); var uvs = texAccessor?.AsVector2Array().ToArray(); var indices = indexAccessor.AsIndicesArray().ToArray(); And these arrays are the data you require in order to build the model. It has the vertex information, (positions, normals, uv\u0026rsquo;s) and the indices. For my engine, I have a vertex struct:\npublic struct Vertex { public Vector3 Position; public Vector3 Normal; public Vector2 TexCoords; } And I use this struct for my MeshRenderer. Since the position\u0026rsquo;s indexes correspond to the normals and uv\u0026rsquo;s, we can simply loop through it.\nfor (int i = 0; i \u0026lt; positions.Length; i++) { Vertex v = new Vertex(); v.Position.X = positions[i].X; v.Position.Y = positions[i].Y; v.Position.Z = positions[i].Z; if (normals != null) { v.Normal.X = normals[i].X; v.Normal.Y = normals[i].Y; v.Normal.Z = normals[i].Z; } if (uvs != null) { v.TexCoords.X = uvs[i].X; v.TexCoords.Y = 1.0f - uvs[i].Y; } vertices.Add(v); } And then I can just pass on this information onto my mesh component, which constructs the mesh using the vertex information and the indices.\nmeshComp.Initialize(vertices, indicesList); Materials Materials have a lot to offer and frankly, I haven\u0026rsquo;t explored too much into it. I simply obtain the base color and the texture and apply it. In the future, I might build more upon it.\nWe can obtain the material using primitive.Material. The material itself has multiple channels that contain values. The one I need for the diffuse texture is called BaseColor, so we obtain that channel and get its texture and color.\nMaterial? mat = primitive.Material; MaterialChannel? baseColor = mat.FindChannel(\u0026quot;BaseColor\u0026quot;); Texture? texture = null; if (baseColor != null) { texture = baseColor.Value.Texture; } To handle images, I use a library called StbImageSharp. It can load images using memory, and that is exactly what we need.\nif (texture != null) { byte[] content = texture.PrimaryImage.Content.Content.ToArray(); baseTex = new Rendering.Texture( Rendering.Texture.LoadFromMemory(content), Rendering.TextureType.texture_diffuse ); } else { baseTex = new Rendering.Texture( Rendering.Texture.LoadFromFile(\u0026quot;Resources/Textures/white.png\u0026quot;), Rendering.TextureType.texture_diffuse ); } Rendering.Texture is my the class that handles textures, It simple loads the image, binds it to the texturing target, specifies the texture image, generate mipmaps, set filtering etc. It returns the handle which you can then bind to the texture target.\nIf a texture is not found, I just load a white 1x1 image. We can also get the Color of the BaseColor channel using\nbaseColor.Value.Color.X, baseColor.Value.Color.Y, baseColor.Value.Color.Z) And then assign it to the material class.\nEnd result:\nModel: Half-Life - C1a0a by Maxime66410\n","permalink":"https://scruffiebaka.pages.dev/posts/sharp-gltf/","summary":"\u003ch1 id=\"model-importer-using-sharpgltf-for-opentk\"\u003eModel importer using SharpGLTF for OpenTK\u003c/h1\u003e\n\u003cp\u003eHey! This blog would be how I implemented a model importer using SharpGLTF that imports .glb as raw data that we can then render using OpenTK. I tried to find a beginner guide on this but there isn\u0026rsquo;t a lot of stuff available apart from the examples (which to be honest proved to be of no use for me)\u003c/p\u003e\n\u003cp\u003eThe game engine I\u0026rsquo;ve been working on does not have multiple features so we will only be going over the top.\u003c/p\u003e","title":"Model importer using SharpGLTF for OpenTK"},{"content":"Introduction Welcome to my website. Here, I will usually post Devlogs, Tutorials, posts about programming and computer science in general.\nAbout I\u0026rsquo;m a 18-year-old student keenly interested in video games and software development. I\u0026rsquo;m also interested in music and musical theory even though I\u0026rsquo;m bad at composing stuff. I also love checking out new stuff in the tech.\nSkillset I started programming when I was about 11 years old, in C#. Since then I have a moderate experience in Unity and OpenTK. Currently I know C#, Python and C. I\u0026rsquo;m also getting into Rust.\nI also used to be a Minecraft forge modder. Because of that I also have a moderate experience with Java. Currently, I\u0026rsquo;m trying to learn systems-level programming and maybe produce and sell actual games in the future.\n\u0026hellip;The future? Though I\u0026rsquo;m not sure what I want to be in the future, it will likely be tech and computer science engineering-oriented, like software development. I also have an interest in aviation, aeronautics and electronics so I will always look forward to something similar.\nThanks for reading along, I hope you will be interested enough to check out my future blog posts and papers ;) ","permalink":"https://scruffiebaka.pages.dev/about/","summary":"\u003ch2 id=\"introduction\"\u003eIntroduction\u003c/h2\u003e\n\u003cp\u003eWelcome to my website. Here, I will usually post \u003cstrong\u003eDevlogs\u003c/strong\u003e, \u003cstrong\u003eTutorials\u003c/strong\u003e, posts about \u003cstrong\u003eprogramming and computer science\u003c/strong\u003e in general.\u003c/p\u003e\n\u003ch2 id=\"about\"\u003eAbout\u003c/h2\u003e\n\u003cp\u003eI\u0026rsquo;m a 18-year-old student keenly interested in video games and software development. I\u0026rsquo;m also interested in music and musical theory even though I\u0026rsquo;m bad at composing stuff. I also love checking out new stuff in the tech.\u003c/p\u003e\n\u003ch2 id=\"skillset\"\u003eSkillset\u003c/h2\u003e\n\u003cp\u003eI started programming when I was about 11 years old, in C#. Since then I have a moderate experience in Unity and OpenTK. Currently I know C#, Python and C. I\u0026rsquo;m also getting into Rust.\u003c/p\u003e","title":"About"}]