You are browsing as a guest. Sign up (or log in) to start making projects!

GVK renderer

  • 43 Devlogs
  • 61 Total hours

My own 3D renderer written in C++ with Vulkan, intended to be a user-friendly base that cuts out anything hard about graphics for the user and just let's them render objects with a single line of code. Not just a vulkan abstraction, a full renderer.

Ship #2

This is the second ship of my game engine / renderer. To explain, I like calling it a renderer instead of a game engine, because I purposefully tried to add as few bloat features as I could, I just wanted something that made rendering something that I don’t have to think about. More info on the README page, this isn’t a good explanation. Just know that it isn’t just a basic Vulkan abstraction, this is a full renderer with PBR, many post-processing effects, skyboxes, dynamic lights, rigged and animated meshes and frustrum culling ’cause why not.
Changelog since the last ship:

  • 2 new post-processing effects, pixelation and fog
  • I also added a feature where shiny objects reflect the skybox, which isn’t realistic, but it adds a great sense of realism and I like to add it to my games.
  • one of the largest changes was turning this into an actual library instead of an executable, which allows easier integration.
  • I also made a full game as a tech demo for this project, it can be found at this link or under my stardance profile. It turned out really well, and I’m proud of myself, because I finally made a game engine that I can actually make games in easily. (The screenshot is from the game)
  • and the smallest but still a significant change was rewriting the entire 2D rendering part of the engine for 2 reasons: it had a memory leak, and text rendering was buggy, slow and barely worked.
  • 11 devlogs
  • 13h
  • 19.44x multiplier
  • 261 Stardust
Try project → See source code →
Open comments for this post

27m 44s logged

I made a few minor tweaks to fog, and I started debugging it, which I ended up completely stopping and reverting, as it was useless. To be honest I’m really trying to find where this 27 minutes appeared, because I don’t remember spending half an hour on this

0
0
10
Open comments for this post

45m 36s logged

FOG

Yeah I just added fog because I thought it would look cool in my game. Obviously it’s over the top in this image because I wanted to show it off. I’m pretty proud of this one, definitely one of the more complex post-processing effects.

0
0
22
Open comments for this post

16m 56s logged

SKYBOX REFLECTIONS

This is a neat trick I did in my last engine and I’m happy I recreated
it in this one. Every single shiny surface reflects the skybox, which
while isn’t realistic, it does make those surfaces look a lot more shiny
than what they actually are, which is a great hack. It sure as hell
looks better in the environments I make.

0
0
16
Open comments for this post

30m 28s logged

Screen-space reflections would be a major challenge, but I learned that making the skybox reflect off of shiny surfaces is a pretty good way of making your renders seem much better. As of right now it technically works, but I came to realize that I wasn’t loading materials right, so if an image didn’t have a roughness texture, then it would end up completely shiny. I’m almost done fixing it.

0
0
30
Open comments for this post

51m 33s logged

PIXELATION POST-PROCESSING EFFECT

I made my post-processing system so expandable that I just casually added it ‘cause I thought it would look cool in the game I’m making. I’m sure as hell right about that.

0
0
11
Open comments for this post

3h 3m 9s logged

I wasted so much time trying to optimize it all to lead to nothing, but I did end up optimizing some stuff with the Surfaces along with actual color blending for them. I did end up optimizing a bit, but that’s basically nothing. This is the most worthless update to this entire project, I don’t even know how I spent 3 hours on this.

0
0
94
Open comments for this post

1h 18m 1s logged

I completely rewrote the text rendering in the Surface class and also fixed a giant memory leak. Here’s a picture of it in use in my game.

0
0
4
Open comments for this post

37m 19s logged

I rewrote the texture loading part of GLTF loading because it just plain didn’t work since I updated everything to tinygltf3, but I didn’t notice because it was after the demo. Anyways, it’s done now.

0
0
8
Open comments for this post

28m 1s logged

I also rewrote the single mesh gltf loading function to return the material and the entire vertex and index arrays, because I’ll need them for a feature I’m making for my game. This is slowly turning into engine development and I kinda like it.

0
0
7
Open comments for this post

4h 34m 50s logged

I worked for over 4 hours, but the renderer finally works as a library!!! That’s right, just put it in as a git submodule, add it as a subdirectory to you CMake project, and there it is! Way too much work for something so simple, but I had to debug a whole lot of stuff. I also edited the README to feature usage instructions and also how to try the demo.

0
0
14
Ship #1

GVK (short for gungu vulkan) is my new renderer using the Vulkan graphics api. I miss the times when I worked with pygame and love2d, where rendering an image was one simple line of code, and I intend to bring that experience to 3D with this project.

Everything is designed to be as easy as possible for the user, just writes
gvk::draw_mesh(mesh, material, position, scale, rotation);
and the mesh is where you want it, how you want it.

But don’t mistake it, this is not a game engine, this is just a renderer, something you can build an engine on. I made this tool so my later projects have a graphical backbone to build on, but every game needs a different engine.

Ever since I started graphics programming last year I knew that one day I had to learn Vulkan if I ever wanted a job in it in the future, and I’m very proud of myself for finally doing it. This was the greatest challenge I faced in programming so far, and I so glad I tackled it.

And as for AI:
This project was created so I could learn Vulkan, and if I copied everything from AI that would have been to effective. My goal was to use as little AI as I could, while still leaving out the headaches of development. Here’s what I used AI for:

  1. Many of the shaders were written by AI, but that’s because I haven’t learned any of the maths I need to know to write any of these shader. When a shader wasn’t too math heavy I wrote it myself, but there weren’t too many of those.
  2. The GLTF loading isn’t hard, it’s just a headache to work with it. GLTF is a horrible format for developers, but it’s the best I knew, so I rather had AI write the GLTF loading functions. I’m still glad I did that, I would have learned nothing from writing those.
  • 32 devlogs
  • 47h
  • 15.86x multiplier
  • 748 Stardust
Try project → See source code →
Open comments for this post

1h 50m 1s logged

THE GREAT DEBUGGING and A DEMO

This is the final post as long as everything works as intended. I fixed every single validation layer error that occurred, so this project is officially bug-free (to my knowledge). I also made a really simple demo that I uploaded to the github releases tab of the repository. I also finalized the readme, so now the project also has a fancy description.
What a ride, I love this project.

0
0
12
Open comments for this post

38m 9s logged

FINAL POLISHING (mostly just making the API more useable)

I genuinely can’t believe this. I did it, I made a renderer in Vulkan. Well, I’m still not in the clear yet, but I’m very close.

Changelog:

  • updated Skin struct to include find_joint() function
  • added Pose struct
  • updated existing skinned mesh systems to work with the Pose struct
  • added sample_clip(), compute_global_pose(), compute_skinning_matrices(), pose_set_local(), pose_set_global(), pose_get_global(), update_animation() and finalize_pose(). These are all helpers for making work with animated and rigged meshes a whole lot easier
  • moved all of the functions inside the gvk namespace, because they were about half and half before.
0
0
7
Open comments for this post

3h 4m 2s logged

SKINNED MESHES AND RIGGING

This renderer is extremely close to done. I just implemented fully rigged (and animated) meshes. They render properly and animations work too (although I didn’t really care enough to show an example). Now I am at the last 2 steps of this renderer before starting work on a game in it:
1. Polish up all the API commands so it’s more user friendly. For example, skinned meshes work and can be adjusted manually, but I have a really good idea on how to make working with them super easy, so I’ll definitely implement that.
2. Make a demo that includes basically everything I have developed so far. This step also includes writing compatibility for multiple platforms, because so far I’ve only tested this project on Ubuntu, and I’ll definitely need a windows version too.

And that’s it, the project is nearing it’s completion. I can’t wait to make a proper game in this, which I’ll document too of course. Also, I’m writing all of this while I’m on a vacation in Denmark, so I’m quite far from home, but I’m extremely motivated to get this project finished.

0
0
24
Open comments for this post

3h 26m 37s logged

SSAO (screen-space ambient occlusion)

This one was fun. Ambient occlusion is just a little shadow thing at the edge of meshes. It is not realistic, technically it doesn’t exist in the real world, yet it looks so much better with it. To be honest I don’t have a lot to say about this, it’s done and it’s cool.

0
0
4
Open comments for this post

1h 40m 32s logged

SCENE LOADING

I just got home from a 10 day adventure that’ll never forget, but I’m back to code, and to get myself to shake into the civilized world again I decided to do a simpler feature before shadow mapping, so I implemented full scene loading from GLTF files. It’s a pretty handy feature, I’m glad I finally made it. It doesn’t just load models and materials, but lights too, pretty handy.

0
0
5
Open comments for this post

19m 41s logged

NORMAL MAPPING

This was a really easy update, most of the shader changes were copied from my last engine, and the CPU side of things was just changing the vertex struct and loading the tangents in the mesh loading function. But it works.

0
0
4
Open comments for this post

3h 49m 54s logged

Well well well. Seems like it’s time for

LIGHTING !!!!! finally

This was not easy, and yet it was made so much easier by having done it once before last year. I added support for a directional light, a dynamic (aka not hard coded, so pratically infinite amount of) point lights and spot lights, full PBR, and I also made a little handy editor to go along with it, although that’s not in the renderer that’s just in the demo project. Anyways, this was an incredible journey filled with pain and suffering like never before, and I’m so glad I’m through it all.
And if this was a challenge, I don’t know what shadow mapping is going to be, which is going to be basically right now, I’m going to add tanget space normal mapping and then it’s already shadowmapping. I’m mentally unprepared, but oh well what can I do?

0
0
5
Open comments for this post

1h 53m 9s logged

This change is not too visible, but it is a major change in the engine

MATERIALS

Everybody who worked in any sort of 3D graphics knows what materials are. And those know, that the next step after this is lighting. This wouldn’t have been that big of a change, if not for one issue. I’m developing on linux, and every once in a while my GPU drivers uninstall themselves, so everything runs on the integrated graphics on the CPU. That happened, but I thought that the code just became really slow because I was sending 6 images to the GPU every single frame, and that slowed it down. So I spent a bunch of time making a large optimization, and it worked like a charm, it ran fast. Then I found out the entire thing was running on the CPU and I didn’t even need to optimize it. Anyway, it’s here, and it’s fast

0
0
6
Open comments for this post

2h 42m 51s logged

POST-PROCESSING STACK and TONEMAPPING AND COLOR GRADING (post-processing effect 5)

This is the finale to the post-processing saga, because I’m finished with tonemapping and color grading. Everything will look really good and cool and whatever, altough I’ve been coding non-stop for 2.5 hours and I don’t really care to give an explanation right now. I don’t have to explain color grading everybody knows that, and tonemapping is the process of mapping the internal HDR render image to an LDR (whatever it’s called) image that the display can actually render properly, how cool is that?

0
0
6
Open comments for this post

1h 22m 22s logged

BLOOM (post-processing effect 4)

I’m almost done with all of the post-processing effects, and this was by far the hardest of them all, but I managed to push through it. I’m really proud of myself, because I finally understand Vulkan enough where I didn’t need any sort of outside help to debug this error. I think I can finally call myself someone who understands Vulkan now. Anyway, now I just need to make tonemapping and the effects are done. After that I just make the simplest pipeline to composite it all, and I’m done with that as well.

0
0
2
Open comments for this post

1h 6m 54s logged

VIGNETTE (post-processing effect 3)

This was the most fun I’ve had debugging something in a while. This was really simple to implement, although I can’t really say a lot. The initialization was the same as the other effects, the actual logic of it was pretty similar, the shader wasn’t too hard to write too, but added up it was pretty bad. I accidentally left one of the push parameters in the CPU code as an int, but a float in the GPU code, which I ended up having to chase down for quite a while. The values are over the top on the image so it is more visible on the screenshot, of course I won’t leave it like this.

Also, I have written a new readme for the github page.

I just kinda wanted to, and thought why not?

0
0
4
Open comments for this post

18m 22s logged

BOX BLUR (post-processing effect 2)

I have to admit this took 11 minutes, and the rest of the 5 minutes I spent in this devlog was spent debugging 3 new errors so I can make a post about this feature too. It took so little because I literally just copied and renamed the gaussian blur functions, and changed the shader. Still, I have box blur now. Actually, I think there’s quite a difference between the 2 blurs, quite cool. Of course now that I look at it it’s barely visible in the screenshots.

0
0
3
Open comments for this post

2h 37m 10s logged

I thought how cool would it be if I just did a whole 10 hour devlog with all of post-processing in it, but I realized I wouldn’t be able to show off all the cool stuff I’ve done, so I’m doing it effect by effect, anyway,

GAUSSIAN BLUR (post-processing effect 1)

But not just that, I also brainstormed out the entire post-processing system, and “implemented” it. I didn’t exactly implement it yet because I need to finish all the effects, but it’s there. I still have to finish: box blur, bloom, vignette and tonemapping, and I also want support for custom effects, but that’ll be really easy so I don’t want to put it on this list.

0
0
2
Open comments for this post

1h 35m 51s logged

MSAA !! (multisampled anti-aliasing)

I always viewed anit-aliasing as this mystery thing that can make a game prettier and I’ll never know how it works. I have to say, it was way easier than expected, most of the time I spent was on some stupid bug or general debugging. You can’t really see the difference in a small screenshot, but it looks so much better full screen.

0
0
18
Open comments for this post

1h 33m 15s logged

2D rendering!!

I have to admit this feature was kinda easy to implement, because most of it was ripped straight from my last game engine, but I did it because I think it is a really smart way of handling how a 2D system should work. Everything relies on the Surface class, the display itself is a surface, the loaded images are surfaces, and those surfaces can draw to eachother. This makes the system easy yet expandable. I think it’s kinda cool. It was heavily inspired by how pygame does things.

0
0
6
Open comments for this post

1h 19m 50s logged

And just like that, the next major update is done!

SKYBOXES and other stuff

Here’s a full changelog of the last 3 posts:

  • I wrote a really handy shader compiler to make this update just a bit easier, now it automatically compiles all shaders at once I don’t have to do it one by one
  • I wrote a compositing pass that finally has a use case as can be seen right now. The skybox and the objects are rendered separately to separate images, and the compositing pass combines them and renders them to the screen together. Might sound simple, and I have to admit if I understood Vulkan a bit better it might have been, but right now I’m really proud of myself for it.
  • Of course the headline feature: The Skybox. This is most of what I’ve been working on for the last 3 updates. It’s done in a really cool way. The easy way of doing a skybox is to just render it as one giant object and then bim bam boom there it is, but sadly that has a couple of issues, the largest one is that this is extremely lazy. So I did it the smart way instead. What you’re seeing there is actually a cube a tad bit smaller than the monkey, but it’s rendered in a separate pass, where I only pass the camera’s rotation and not the position, and I also have the depth disabled. I render that to a separate image, use the compositing pass, and there it is, a beautiful, very stable and very professional skybox.
  • I’m almost done rambling, but I have to mention one last feature, and that is the loading of equirectangular images into a cubemap texture. I think I’ve typed enough for this update, but if you care you can look it up or like look at my code.

Next up: 2D rendering

and I have some great ideas for it

0
0
7
Open comments for this post

1h 33m 42s logged

This is a change that cannot be seen, but the composite pipeline is actually working. This is a really simple step in the graphics pipeline, it takes the images from the previous passes and combines them to make a final image. This will be useful for future features like 2D drawing, post-processing, the skybox, etc., so I’m happy I managed to implement it. It’s not something that can be seen with the naked eye, but believe me it’s there and I’m so happy for it.

As always, this is next to some generic bugfixes here and there, but it’s been 1.5 hours and I forgot what I fixed and what I didn’t so if you happen to care enough this is open-source just like go and check it out.

0
0
4
Open comments for this post

1h 40m 31s logged

I’m well into developing the skybox system along with a compositing pass, but since I needed to write so many new shaders for this update, I decided to write a simple shader compiler, and I kinda want to show it off so it’s not lost in the giant list of changes that I’ll push in the next update. That’s it, I rest my case, that’s all I wanted until I’m finished.

0
0
4
Open comments for this post

2h 14m 51s logged

I finished frustum culling.

You’ve probably seen this feature in some random wannabe gamedevs post on tiktok saying how they “optimized their game” by enabling frustum culling in Unity and calling themselves genius for it. Well it wasn’t as easy as pressing a button for me.

Here’s how it works:

I generate an axis aligned bounding box (AABB) for every object when loaded. Every frame I generate 6 planes for each boundary of the camera, the left, right, bottom, top, near and far planes. Then I also calculate the world position AABB for each mesh, which is just translating the original AABB and making a new one from that’s boundary. From that, it’s actually quite simple to compare if the box is inside the frustum or not, though it’s kinda hard to explain so I won’t bother, but I just run that for every object,
and it basically makes it, so if an object is not inside the camera’s vision, then it just makes it disappear.

I attached the majority of the logic in the second picture

0
0
3
Open comments for this post

1h 18m 44s logged

I implemented a fully automatic mipmap system. Basically, mipmaps are lower quality version of a texture that appear the farther you are from an object. The image I attached is of mipmap layer 4, but of course this was set manually to showcase the system working.

0
0
2
Open comments for this post

39m 49s logged

I wrote a giant list on what I want to implement into this framework to make it full. I’m pretty sure I’ll be done in about 150-200 hours, which I have about 40 days to make before the end of this thing. That is 3.75 - 5 hours of coding in a day. Anyway, here’s the list:

TODO FEATURES:

  • lighting
    • gpu scene data uniform buffer
    • ambient light
    • directional light
    • point lights
    • tangent space normal mapping
    • tangent generation in gltf loading
    • dynamic light count
    • proper api for handling lights
  • shadow mapping
    • depth-only pipeline
    • shadow map image
    • light space matrix
    • shadow pass
    • shadow sampling in the main fragment shader
    • shadow bias
    • PCF filtering
  • material system
    • material struct (albedo map, normal map, roughness map, emissive map, scalar tint and roughness and metallic factors)
    • material descriptor layout
    • default fallback textures
    • gltf material loading
    • draw_mesh api update
    • emissive support in the shader
    • creating and destroying materials for user-made materials
  • mipmaps and proper sample management
    • mipmap generation on upload
    • mip count calculation
    • sampler cache (so samplers are never duplicated)
  • instanced rendering
    • per-instance storage buffer
    • draw_mesh_instanced api
    • write the shader for it (gl_InstanceIndex)
    • move to indirect drawing so the instance count can eventually come from gpu-side data
  • skybox
    • cubemap loading
    • skybox pipeline
    • skybox shader
    • set_skybox api
  • frustrum culling
    • bounding sphere per mesh (compute in loading by finding the disctance from the centroid across all vectires)
    • frustrum plane extraction (gribb-hartmann)
    • cull loop
    • stats readout
  • post processing stack
    • fullscreen traingle pipeline
    • HDR tonemapping
    • guassian blur api
    • box blur api
    • bloom
    • vignette
  • 2D rendering
    • quad mesh
    • 2D pipeline
    • surface class
    • default surface
    • draw_surface
    • draw_rect
    • font atlas rendering
  • MSAA
    • multisample draw image
    • resolve attachment
    • configurable sample count
0
0
3
Open comments for this post

52m 43s logged

I have to admit I’m pretty proud of myself. I implemented the proper transformations for objects, I also made a good camera system, and I fixed the uv mapping of objects, so textures finally work properly. All this in under an hour.

0
0
3
Open comments for this post

1h 2m 27s logged

To be completely honest this engine development thing is going a lot more awful than I could have imagined. I tried to implement a proper camera and transformations for the objects, and now nothing works, yet I barely changed anything. I have been staring at this function for like 2 hours, I’ve tried everything, and nothing works.

0
0
3
Open comments for this post

1h 4m 7s logged

I finally finished the guide (🥳🥳🥳), so it’s time to make the game engine I want. My first improvement was adding a render queue, which basically means I can render anything in a much user friendly way.

0
0
2
Open comments for this post

48m 22s logged

Thanks to the major rework of the allocation of descriptors, I have
managed to implemented textures into rendering. I haven’t made
texture loading yet, since it’ll be an engine feature and I’m working on
project setup
, so enjoy the beautiful pink-black checkerboard pattern
on Suzie, the Blender monkey.

0
0
3
Open comments for this post

1h 20m 20s logged

I did a giant rework of the descriptor allocation to make handling textures a breeze in the future. Yes, I did mostly just follow the guide, but I am really getting the hang of how Vulkan works, and the guide is ending in a couple of chapers, and the rest will be up to me, and I already feel ready for the task. I have to admit it doesn’t exactly work yet, but I’m working on patching it, it shouldn’t be an issue.

0
0
5
Open comments for this post

1h 1m 46s logged

So mesh loading and rendering works, although I haven’t gotten the world matrix and transformations quite right😅
The guide I’m using to learn Vulkan actually recommended I use fastgltf, but I ended up going with tinygltf, as I’ve used it before and have a bunch more experience in it, and oh boy is having experience a good feeling when learning VK

0
0
3
Open comments for this post

1h 8m 2s logged

I’m progressing rather fast, I implemented a full mesh buffer system, which allows me to render any mesh. Mesh loading will be the next task, but until then the best display I can do is a colorful rectangle, I hope that’s good enough

0
0
4
Open comments for this post

29m 7s logged

Implementing a proper graphics pipeline was surprisingly easy. I remembered a lot from my experience in sokol and of course the guide was quite helpful as well. Got from a compute shader to a proper pipeline very fast. I’m still very eager to get back to the fun part of graphics programming and not be stuck in setup hell, but the next step is writing the mesh buffers, so that’ll be fun.

0
0
2
Open comments for this post

1h 5m 42s logged

I finished the ImGui implementation, I’m starting to get the hang of things. I’m still following vkguide.dev for the setup phase, but I’m eager to finally get to the fun part of graphics programming

0
0
2
Open comments for this post

1h 4m 46s logged

After about an hour of following vkguide.dev, I managed to make a little compute shader that display 16×16 cells of a gradient.
Great start!

0
0
6

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…