Current design decisions for my game engine:
-
The good news is that I got Qt Advanced Docking System to work together with 3D viewports of my Vulkan engine just the way I had envisioned :D
So now I can finally focus more on editor features such as gizmos, scene tree editing, component inspectors, etcAlso I removed all QtQuick (Qt's more "browser-like" UI framework) dependencies for now. It seemed nice but two of the libraries I want to use are based on QtWidgets (a more traditional C++ framework) and I'd rather not mix and match unless I find a good reason for it.
This also simplifies viewports. I no longer export/import memory between two Vulkan instances and instead just embed my game's SDL window in a Qt dock widget.
-
Also I removed all QtQuick (Qt's more "browser-like" UI framework) dependencies for now. It seemed nice but two of the libraries I want to use are based on QtWidgets (a more traditional C++ framework) and I'd rather not mix and match unless I find a good reason for it.
This also simplifies viewports. I no longer export/import memory between two Vulkan instances and instead just embed my game's SDL window in a Qt dock widget.
What makes a 3D editor a 3D editor? That's right, an infinite grid!
Implemented the shader from this excellent article by @bgolus: https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8
-
What makes a 3D editor a 3D editor? That's right, an infinite grid!
Implemented the shader from this excellent article by @bgolus: https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8
Now with major and minor grid lines and colored x- and z- axes
-
There's this philosophy that you should be very conservative with the C++ features you use, only use those that are at least a decade old, and that ideally you'd just write C.
I'm of the philosophy that I wanna see for myself if a feature is problematic, even if I might have to suffer the consequences.
Anyway last week I learned about C++ "concepts" and over the weekend I already found a use case for them. Terrible name but cool concept!
-
There's this philosophy that you should be very conservative with the C++ features you use, only use those that are at least a decade old, and that ideally you'd just write C.
I'm of the philosophy that I wanna see for myself if a feature is problematic, even if I might have to suffer the consequences.
Anyway last week I learned about C++ "concepts" and over the weekend I already found a use case for them. Terrible name but cool concept!
In a similar vein, I tried out C++ modules in the previous iteration of the engine and learned first hand why people warn against them. No regrets though.
-
In a similar vein, I tried out C++ modules in the previous iteration of the engine and learned first hand why people warn against them. No regrets though.
Camera controls for the engine editor. I stole the exact keybindings from Godot >:)
-
Finally had some time again to work on the project. The scene tree is now shown in a QTreeView and you can toggle the visibility of individual nodes. Also re-implemented the resource manager and scene deserialization from the previous version.
Next up: Let the editor actually edit the scene and save it to disk!
-
Finally had some time again to work on the project. The scene tree is now shown in a QTreeView and you can toggle the visibility of individual nodes. Also re-implemented the resource manager and scene deserialization from the previous version.
Next up: Let the editor actually edit the scene and save it to disk!
Wait, this isn't progressing in the right direction - maybe I should take a break...
-
Today has been a very relaxing goblin mode coding Sunday :D Some more non-visual updates:
- StringIDs. Like Godot's StringNames, internedΒΉ strings are hashed and stored in an internal database. "bla"_id gets converted to a handle that is faster to compare for equality than std::strings.
- Loading scenes from the editor via a file dialog, including a "Recents" menu. The UI was surprisingly easy to implement with Qt!
-
Today has been a very relaxing goblin mode coding Sunday :D Some more non-visual updates:
- StringIDs. Like Godot's StringNames, internedΒΉ strings are hashed and stored in an internal database. "bla"_id gets converted to a handle that is faster to compare for equality than std::strings.
- Loading scenes from the editor via a file dialog, including a "Recents" menu. The UI was surprisingly easy to implement with Qt!
Thinking about the next steps for the editor. I want to add a transform gizmo, which means I need some way of recognizing when I click/drag things in the 3D viewport, so I'll try to find out how other editors do that. Naively I'd think I need a physics engine for that, but in Godot I can accurately select meshes without collision shapes π€
-
Thinking about the next steps for the editor. I want to add a transform gizmo, which means I need some way of recognizing when I click/drag things in the 3D viewport, so I'll try to find out how other editors do that. Naively I'd think I need a physics engine for that, but in Godot I can accurately select meshes without collision shapes π€
AABBs (partially) implemented
They don't support scaling and rotations yet, but for starters it's good enough for (1) visualizing selected nodes and (2) testing raycasts from the cursor position against.
-
AABBs (partially) implemented
They don't support scaling and rotations yet, but for starters it's good enough for (1) visualizing selected nodes and (2) testing raycasts from the cursor position against.
Got node selection working, without a physics engine or CPU-side triangle raycasting! Used this idea from a colleague:
- Put mouse position and node ID into push constants
- In the fragment shader, check if current pixel is under the mouse
- If so, write node ID and depth into a list in a storage buffer
- On CPU, read back the buffer and sort by depthUpside: No need for AABB testing, proxy meshes, or duplicating skinning code on the CPU
Downside: Has to be included in most shaders
-
Got node selection working, without a physics engine or CPU-side triangle raycasting! Used this idea from a colleague:
- Put mouse position and node ID into push constants
- In the fragment shader, check if current pixel is under the mouse
- If so, write node ID and depth into a list in a storage buffer
- On CPU, read back the buffer and sort by depthUpside: No need for AABB testing, proxy meshes, or duplicating skinning code on the CPU
Downside: Has to be included in most shaders
Weekend progress update: we have a transform gizmo!
It can't actually transform anything yet but it jumps to the average position of the selected nodes and disappears when nothing is selected.
-
Weekend progress update: we have a transform gizmo!
It can't actually transform anything yet but it jumps to the average position of the selected nodes and disappears when nothing is selected.
Bonus screenshot: one of the fun things that can happen when you mess up and bind invalid descriptor handles. Had a lot of GPU hangs today :P
-
Bonus screenshot: one of the fun things that can happen when you mess up and bind invalid descriptor handles. Had a lot of GPU hangs today :P
The translate gizmo is now functional :D
-
For a second there I thought my refactor of the materials system just worked on first try, but no, it only seemed to work by accident and now my GPU crashed. Time to go to bed :D
-
For a second there I thought my refactor of the materials system just worked on first try, but no, it only seemed to work by accident and now my GPU crashed. Time to go to bed :D
The refactor being: First I had a global buffer of materials with albedo color, roughness, metallic, bindless texture indices etc that's always bound to every shader and I pass a material ID via push constants with each object. But not every material is PBR, there's going to be custom shaders using different data. So now the global buffer is an array of pointers to material buffers of different types, and I send an additional material type index via push constants as well.
-
The refactor being: First I had a global buffer of materials with albedo color, roughness, metallic, bindless texture indices etc that's always bound to every shader and I pass a material ID via push constants with each object. But not every material is PBR, there's going to be custom shaders using different data. So now the global buffer is an array of pointers to material buffers of different types, and I send an additional material type index via push constants as well.
Update:
- Proper dynamic point lights based on nodes (previously the light was just hardcoded in the fragment shader)
- Billboard shader
- Badly drawn icons for point lights in the editor using billboard shader
- Icons have the color of the light -
Update:
- Proper dynamic point lights based on nodes (previously the light was just hardcoded in the fragment shader)
- Billboard shader
- Badly drawn icons for point lights in the editor using billboard shader
- Icons have the color of the lightUpdate: KTX2 texture support. Smaller VRAM usage due to GPU block encoding, much faster loading times since I also downscaled some textures, and much better looking textures from afar due to mimapping that comes for free (the toktx tool I use to convert to ktx can automatically generate them).
Conversion to KTX isn't automated yet, but I hope to do that as part of the import process in the future.
Again mostly copied from the old engine and slightly adjusted
-
Update: KTX2 texture support. Smaller VRAM usage due to GPU block encoding, much faster loading times since I also downscaled some textures, and much better looking textures from afar due to mimapping that comes for free (the toktx tool I use to convert to ktx can automatically generate them).
Conversion to KTX isn't automated yet, but I hope to do that as part of the import process in the future.
Again mostly copied from the old engine and slightly adjusted
The temptation to rush ahead and implement the the fun stuff is real :Β§ But before that I really gotta make a proof of concept at least for a core architectural system.
In Godot you have individual .tres / .tscn files for custom resources and scenes. I want to instead use a single SQL database for everything (or at very least for resources like items etc., but ideally also for whole scene hierarchies). That idea needs testing.