Activity

Simon

Shipped this project!

Hours: 11.61
Cookies: 🍪 111
Multiplier: 9.59 cookies/hr

This is the first ship of cirruspad.
The idea is a cloud based note taking app, but for now it is only an editor that stores the changed files in ram, so they are gone after you close the window/tab.

It is more of a technical demonstration than a fully functional product, but I think it allready is at a point where I can share it with the world.

Simon

Shipped this project!

Hours: 114.25
Cookies: 🍪 3082
Multiplier: 26.98 cookies/hr

I built VoxelWorld. A minecraft like game but with a twist:

The world is not infinite but feels like a sphere, actually is a 4D torus.
So walking in one direction eventually brings you back to where you started.
Select a small planet size so you can get around in a reasonable time.

You can build and explore the procedurally generated terrain.

Getting this to work at the frame rates you get was extremly hard, especially as this is my first opengl project. Starting I wanted to use QRhi a 3D abstraction layer but there simply were not enough possibilities for me to customize and optimize so that I switched to OpenGL with GLFW eventually and basically started from scratch.
Starting I knew that multithreading was the only way to give the player consistent frame rates while doing heavy computation for chunk generation and meshing. Actually doing multithreading was hard. You need to protect all your variable with a mutex or make them atomic if they are used by multiple threads. You need to decide what does each thread do and how do they communicate. But in the end I am quite proud with the current solution. It runs quite good and always stays responsive even on old hardware (the chunks just take quite a while to generate xD).

If you want to know more details please feel free to comment on the devlogs and I am happy to explain how the systems work or look around in the source code (I would recommend to start at main.cpp, get an idea how the threads are started and then look into what they do in their loops)

Simon

Devlog 21:

Getting everything ready for shipping and a few last finishing touches…

Screenshot from windows :-)

Attachment
0
Simon

Devlog 20:

Changed world generation so it uses 4D coordinates on a torus to get rid of the ugly transitions at the edges where the world was stitched together.
Also added a dropdown to choose the block for placing

Attachment
0
Simon

Devlog 19:

Added block placing and breaking and highlights so you see which block you are interacting with. The highlight works through the shader and is rendered in the fragement shader as an overlay on top of the texture/color.

You now can build a dirt house, while also being able to fly around the planet and come back after a full circle. :)

Attachment
Attachment
0
Simon

Devlog 18:

Added a main menu to set “planet” size and set a seed.

Fixed the edges by simply flatening them out to remove the cut in the world and improved face culling by making the boxes larger the smaller your world is and the stronger the distortion. Anything below 256 chunks only is there for demonstrational purposes.

Attachment
Attachment
Attachment
0
Simon

Devlog 17:

Stiched the world together. The world generation is not changed yet but the fact that you now can move around the “planet” and come back to where you started is quite impressive I think

0
Simon

Devlog 16:

Added textures with a texture atlas (they look horrible at the moment) and spend way too much time to make warping the world so it looks like a sphere possible, simply just beacause I made a wrong assumption about code I wrote some time ago and it took me forever to find it. I asked ai about it and as I added this assumption as a comment the ai simply took it and went with it and made the same mistakes I made as well, but now it works :)

Attachment
Attachment
0
Simon

Devlog 15:

  • added block registry to setup rendering data from cpp and not hard code it into the shader.
    –> as I use OpenGL 4.1 for compatability I had to use a texture buffer instead of a ssbo but it works perfectly fine with this setup now as well.

  • I also updated the chunk generation to put snow on the mountain tops and a layer of stone around the snow to have a transition between the grass on the ground and the snow on the mountain peeks.

Attachment
0
Simon

Devlog 14:

Small improvements:

  • optimized chunk ram usage by splitting the chunks into small pieces that only store one block if all blocks in the piece are the same as it is the case for a lot of the deep ground and sky
  • added frustum culling to only render visible chunks
  • added fog for a seemless transition in the fragement shader
0
Simon

Devlog 13:
Added DearImGui for a debug screen and an option to change settings during gameplay.

This also required a bit of a rework how I handle these variables.

For the render distance I now safe it in the chunk manager and check every tick if it changed and if it did I update the loaded chunks.

For the player speed I simply replaced the static variable with the one controlled by the window.

To make the connection between my rendering pipeline and the engine possible I created a settings singelton that holds all the settings in a thread safe way and makes it possible for threads to read and write to them.

Attachment
0
Simon

Devlog 12:

Added FastNoise2 for fast procedural generation.

Reduced the amount of things happening on the rendering thread to a minimum to allow for an increadible render distances of 24 32x32x32 in every direction without frustum culling (I should have prioritized this more…).
The chunks that should be loaded and the starting of the mesh generation now is 100% managed by the engine thread. The only thing the rendering thread gets are updates which chunks are there to be rendered and which chunks to delete so the shared_ptr to the vertices is deleted as well.

Blocks > 135 are blue as an experiment with world gen.

Attachment
0
Simon

Devlog 11:

Fully working async chunk generation using taskflow is now working with versioned chunk-vertex-data. This allows for very fast remeshing.

For testing I currently spawn a block 5 blocks in the view direction from the player, but only in the same chunk so this is why the result may look a bit weird.

The biggest achievement at the moment is that it works to have two threads working independently from each other on the same elements without dead locking themselfes out or waiting forever for the other thread to finish working on some data.
One thread for rendering and only parsing the input and a second one to check if the player changed the chunk, update the chunks that need to be rendered and start the corresponding tasks in their own threads.
The next time after I finished calculating the vertices of a chunk when the renderer checked if the version changed it uploads the vertex data to the gpu and from there on it does not need to access the vertex data in the ram anymore as it has its own copy on the gpu where it needs it.

If you are interested in any other more specific features feel free to ask.

1

Comments

Simon
Simon about 2 months ago

The noise you see here was a fractal noise function claude sonnet 4.6 gave me. This is changed later.

Simon

Devlog 10:

Went from Qt to GLFW for rendering and split the work into multiple classes in the process.
This gives me way more control and way better readability of the code.

By also going away from Qt Threads I now have to rework the multithreading, so only simple renderside generated chunk meshes consisting of only one cube for now.

The difference is not that notable in the recording but with qt i was hard stuck at 180 fps, with glfw the upper limit actually is my hardware.

Terrain generation also is implemented it just can not be used at the moment.

Attachment
Attachment
0
Simon

Devlog 09:

Added binary chunk mesh generation and paralized everything so chunks are properly loaded and unloaded by multiple threads.

Simple diffuse lighting also is implemented in the fragment shader

Attachment
Attachment
Attachment
Attachment
Attachment
Attachment
Attachment
0
Simon

Devlog 08:

Added Meshes and logic to always load the chunks around the player and unload those that are further away. The meshes currently generate dummy data in their own thread, but are ready to be filled with the actual chunk mesh.

To reduce the data sent to the gpu, for every face there is one vertex that then by using instancing is used 4 times for a GL_TRIANGLE_STRIP.

Everything works async and should be thread safe, so one thread can write to it and another can read from it. Currently there is one thread for the inputs, one for the gameLoop that currently is not used yet and one for rendering.

Everything is coming together

0
Simon

Devlog 07:

We are back to a cube and a moving camera, so the foundation is laid.

The input is recorded through QML and passed on to the PlayerController. The renderer then updates the position according to the current inputs and the time since the last frame, so it feels as smooth as possible.

As the basic chunk data structure allready is there, it should not be too difficult to implement chunk rendering with a simple chunk meshing algorithm.

0
Simon

Devlog 06:

Added basic engine structure and player movement for a portable approach to allow for multiple rendering engines and easy switching in the future.

That is:

  • World Data Structure in Chunks
  • Block Data
  • Engine to run in its own thread and call a tick function every 50ms
  • PlayerController to live between the threads, input from qml, updates/ticks every frame and to be used in the engine
Attachment
1

Comments

Simon
Simon about 2 months ago

Completely seperated from the rendering which allowed my to do fundamental changes to the renderer later on wihtout destroying the engine system.

Simon

Devlog 05:

After trying to use vulkan with qt on macOS for a too long time, I now switched to OpenGL as it should me get quite a long way and allow for way faster prototyping and faster progress.

This also allows me to rewrite the chunk data backend and optimize and structure it better than it was before to make for a more stable gameplay and avoid stuff like chunks not unloading properly.

QRhi limited me as it seperated the chunk upload and configuring from the rendering. With OpenGL I now am able to change uniform buffers in between draw calls and also more complex features like indirect drawing are possible.

This means a fresh start so all I have to show for now after trying around to much is a black window, but more will follow soon.

What are your thoughts?
Is OpenGL a good starting point?

Attachment
1

Comments

Simon
Simon about 2 months ago

At this stage I used Qt for my windows I later changed to glfw to gain more control and get rid of the Qt Event System that was stealing too much performance.

Simon

Devlog 04:

After some more optimizations I am now able to render quite a large region. The problem that now arrises is the amount of buffers used. Every chunk at the moment uses 6 buffers and QRhi just cant handle this. The next approach to fix this is to switch from QRhi to Vulkan to gain more control and implement a solution that can work for far larger render distances.

Optimizations:

  • Greedy Meshing
  • Frustum Culling
  • Fully async chunk and mesh generation
  • Removing faces that are facing away from the player
1

Comments

Simon
Simon about 2 months ago

Vulkan looked way to hard so OpenGL was the final decision in the end

Simon

Devlog 03:

Voxel Worlds are hard :(

What I did:

  • Moved chunk mesh generation in seperate worker threads and tried to make everything needed thread safe
  • Implemented movement and game logic through its own classes running in its own thread
  • Implemented instanced drawing for quads, drasticly reducing the amount of verticies and removing the need of indicies through TriangleStrip
  • Added chunk generation using perlin noise
Attachment
0
Simon

Devlog 02:

After too many hours, I now finally got a codebase, that can do efficient rendering of chunks using QRhi under Qml.

To achieve this the hardest parts were:

  • Reducing the trafic between cpu and gpu. Only seending meshes if they changed
  • Creating efficient meshes, using face culling for now (greedy meshing planned)
  • Effiently storing the chunk data
  • Getting the order of the triangles right to enable backface culling
  • QRhi stuff:
    • Understanding the basics of the rendering pipeline and how QRhiCommandBuffers work

The picture currently shows one 32x16x32 stone chunk rendered with different colored faces.

If you have any questions feel free to comment <:

Attachment
0
Simon

Devlog 01:

Tried a lot with QRhi and Qt Quick 3D but always had problems with optimization and different threads accessing different things and bing blocked by operations.

New try with QRhiWindow to stay in c++ for the whole 3D pipeline.

Allready learned a lot about 3D rendering and optimization.

Attachment
1

Comments

Simon
Simon about 2 months ago

Actually never went with QRhiWindow…

Simon

Devlog 06:

New Features:

  • changed from simple TabBar to ListView for workspace tab bar
  • added drag and drop support for workspace tab bar, so you can reorder the files manually after opening

Fixes / Polishing:

  • used enum for node type in cpp backend instead of string
0
Simon

Devlog 05:

Added web assembly demo hosted on github pages.
The project is not optimized for web assembly yet but it works.

Additionally some small features were added:

  • closing files
  • proper dimensions of the sidebar also on web assembly
Attachment
0
Simon

Devlog 04:

Rewrote the way how the contents of the file are saved in the C++ backend by giving them their own classes and finally implemented a proper editor in which multiple files can be opened and switched easily.
Also created the editor for TODO lists.

Finally I looked into the ui and fixed some smaller details to just create a better ux.

Attachment
Attachment
0
Simon

Devlog 03:
Added basic editing structure for my file / folder structure to create / rename / delete files and folders.
Additionally fixing the ui to make it consistent and getting changes in the note editor to be registered and saved in the C++ backend

Attachment
Attachment
Attachment
0
Simon

Devlog 02:
Added the basic project structure using Antigravity:
C++ backend subclassing QAbstractItemModel
QML Frontend with minimal functionallity

Getting this result needed a lot of knowledge around how qt handels models and what works and what does not, but after investing 30min into the implementation plan alone gemini did a great job on implementing all of the features.

For everyone who wants an idea how it works look at
https://github.com/simonpth/cirruspad/blob/main/CLASSES.md

The code is far from perfect and needs a bit of human polishing but it’s a good starting point.

Attachment
Attachment
Attachment
Attachment
Attachment
0
Simon

Devlog 01:

I finished project, hackclub and github setup and now everything is ready to start. This devlog also is there to finish the task on the welcome page!

Attachment
0