Playing around with real time raytracing and non-photorealistic rendering for the contest subission of the Computer Graphics course University of Groningen 2020. There were two categories for the competition: OpenGL realtime rendering, and ray tracing. Since this is a ray tracer running in real time with OpenGL, this was a submission for both contest categories, and it won 1st place in the ray tracing category, and 2nd place in the OpenGL category.
Made by s3301419 and s3324818.
This program..
- Is a massive performance hog. You will definitely need a decent dedicated graphics card in order to run this smoothly.
- Requires at least OpenGL 4.3 (2012 or newer hardware) since we use shader storage buffers.
- Relies on a good OpenGL driver to compile our shaders. Some open-source linux drivers that we tested couldn't do this, if you are trying to get this to run and getting complaints about register allocation then this problem is happening to you.
With those uh.. minor quirks.. out of the way, I think our results speak for themselves.
We obviously get very nice reflections from the ray-tracing. The ray-tracer supports 3 basic shapes: planes, spheres, and voxels. Ray tracing is the first of our 2 render passes, and it is obviously very expensive - especially since we don't have any spatial acceleration structures (yet), so every ray is tested against every object every frame. To mitigate some of this cost, we normally render to a small 256 x 256 texture. This is later upsampled to the whole screen in the second render pass. On (very) powerfull hardware this intermediary texture can be made larger, thats why the screenshots look so crisp and nice.
Same as the reflections, the nice dynamic shadows are a result of the ray-tracing. We use basic Phong lighting to light the scene, nothing special. Take a look at the shader code.
Portals are the star of this show. We introduced them as soon as we realized how easy it would be to move and distort rays as they hit objects. There are always 2 portals in the scene, an orange portal and a blue portal, when we detect a ray hitting a portal we simply teleport the ray to the other portal and we keep on tracing it - easy. The same is done for the camera, when the camera collides with the portal it is teletorted to the corresponding portal. And, ofcourse, portals are recursive.
Since the ray tracing output texture is very low-res, we thought we could use some paint to cover up the edges! After a trip to the Groningen Museum we got inspired by some of Johan Dijkstra's paintings and so we looked for some shaders on Shadertoy. We found this shader made by Florian Berger. It looks great! The only problem is that its extremely slow - even slower than the ray tracing.. So we optimized it heavily and removed all but the necessary features to get a very similar effect. This painting shader is applied during the second rendering pass, however the painting effect is disabled by default. You can enable it by uncommenting the early return statement in the fragment shader
We made a simple datastructure that synchronizes data between the CPU and GPU. Using that, modifying the scene at runtime is trivial. Objects and lights can be added to scene using point and click editing at runtime - that's how we made the default scene.
We re-used the ray tracing code from the shader in our gameplay code to implement player collisions with the environment. We then added gravity and got a relatively fun first person platforming game out of it. Ofcourse, we also implemented camera portal-travel, and you can shoot the portals anywhere!
We keep track of changes made to the shader files during runtime. When you change a shader, it will immediately be recompiled and injected into the program at runtime, so you can instantly get feedback on what changed. This makes it very easy and fun to experiment with our shaders while running - try it out for yourself. For example, the painting shader is disabled by default from the paintfrag.glsl
file. If you comment out the return
statement near the beggning of main
the painting effect will be enabled. Note that we don't do this for the Qt port.
This program was originally designed without Qt. We have used the one week of the extended deadline to implent a Qt port so that we can adhere by the competition rules. You can find a zip file containing the full Qt project here. The Qt port is provided only in order to adhere to the guidelines of the competition. If you want to actually try to compile or run this program WE STRONGLY ADVISE AGAINST USING THE QT PORT.
Not only does the Qt port perform worse than the original GLFW version, but the controls and frame timings are also off due to how Qt deals with these things. The original application feels much smoother and runs faster, although the Qt port still works and has equivalent functionality. The code for the original GLFW application is much cleaner as the Qt port was duct-taped together and was not the main target - do not look at the Qt code if you want to learn from the code.
download the Visual Studio project file in the /bin
directory. Everything should already be set-up.
Make sure to install GLFW with your package manager, or you can use the libraries provided in the /lib
directory. You will need to statically link against the appropriate library for your operating system.
$ g++ -O2 src/*.cpp -lm -lglfw
$ clang++ -O2 src/*.cpp -lm -lglfw
Version of GLFW for Windows, Linux, and Mac are provided in the /lib
directory.
A zip file containing the full Qt project files is provided here. Everything should already be set up.
- C++03 compiler
- OpenGL 4.3 capable GPU
- Decent GPU drivers
- Decently powerful computer
Just run the executable you compiled and make sure the /shaders
and /textures
directories are in the same directory as the executable. Also make sure not to rename or delete any of the files.
If you couldn't get the code to compile for whatever reason you can try running the pre-compiled exectables in the /bin
directory. One is for 64-bit windows, and the other is for 64-bit linux.
- GLFW for opening a window and creating an OpenGL context (not used in the Qt port).
- GLAD for loading OpenGL functions (not used in the Qt port).
- Bmath for math.
- STB Image for opening .png files (not used in the Qt port).
- Qt because it was mandated for the competition.
You can move around with WASD, and look around with the mouse. You can jump with SPACE and also double jump if you jump while in the air. Left-click and Right-click will place the two portals to the surface you are looking at.
You can press B to go into build-mode. While in build mode you aren't affected by gravity, and you don't collide with the geometry. Instead you can press SPACE to go up, and CTRL to go down. Left-click will place a block instead of a portal. You can choose the material of the block being placed with the Scroll-wheel or numbers 0..9. Pressing P will take you out of build mode. You can press ESC at any time to close the game.
Have fun! :)
And, if you are interested in shaders you should check out our other repository featuring a beautiful real-time particle simulation implented using GPU compute shaders.