Hi everyone,
First of all, let me introduce myself: my name is Grégoire, I'm a PhD student in mathematics. I spent most of my teenage years developping video-games (well, at least prototypes). Maybe some of you knew me from the French section for Holyspirit, which used to be my main project:
After a while, the motivation left me and I kind of stopped developping things (mainly to do more mathematics).
However, I'm now nostalgic of that time, and I recently decided to start again doing stuff (which is not good for my thesis, but heh). So, here I am to tell you about my new project !
The projectOriginSix years ago, I started working on a some kind of 2.5D shading engine (i.e. old-school prerendered 3D assets but with dynamic, "mordern" lighting effects), using the SFML. It looked like this:
Not very good looking, alright.
Hence, in order to do video-games again, I decided to start by first developping a new 2.5D shading engine, still with the SFML and OpenGL. So here I'm to present what I'm working on, hoping to get some feedbacks and ideas how to improve it.
Generalities and progressTechnical specifications:- C++
- SFML/OpenGL
- Deferred Rendering
- PBR Shading
- Isometric/2.5D assets
Before going into technical explanations, let me put some nice looking screenshots, so that you can see what it looks like right now:
And moving:
Basic conceptThe idea is very simple (and not original, there are other examples on youtube, also Pillars of Eternity use some kind of similar technology) and is the following: a lot (well at least I think) of 3D engines use a method called "deferred shading". It consists in doing all lighting computations in the final step of rendering, so that we do not need to compute lighting for obstructed fragments (i.e. pixels hidden by other objects). Concretly, what they do is to render all geometry of the scene in 4 differents buffers which will contain all the necessary informations to compute lighting of the final visible fragment (the one closer to the camera if you want). Those buffers consists in the albedo (i.e. diffuse color), orientation of the surface (some kind of normal map for the whole screen), material (like specularity) and position. I invite you to go take a look here for more explanations :
https://learnopengl.com/Advanced-Lighting/Deferred-ShadingNow, what we have to do is replace the part we render the scene in the 4 buffers by rendering 2.5D isometric prerenderred assets. Of course, it means we have to prerender all 4 passes, like this:
Then in the scene, we get something that look like this:
Albedo:
Normal:
Heightmap (in 2.5D we only need the height, the position being given by the coordinnate of the fragment and the camera):
Material:
Note that the asset I use for the building is not PBR, so I just putted an uniform roughness.
Moreover, I use OpenGL depth buffer to determine if a fragment is obstructed by another, so that I can intersect 2.5D objects like if they were in 3D. This will allow me to render complex scenes without having to cut things in multiple parts (like I used to do with Holyspirit for example).
Then, using those 4 buffer, I can dynamically light the scene, add SSAO (Screen Space Ambient Occlusion, i.e. shadowing the corners using the screen geometry), add bloom, etc. In order to make the engine as modern as possible, I decided to implement PBR Shading (i.e. Physically Based Rendering). Those are methods more advanced than the classical Bliin-Phong model, inspired by the physic of our world. They were mainly developped by Disney (for their animation movies) and Epic Games (for the UT4), I think. They allow to get a really nice realistic result and they make the creation of assets more intuitive (material are defined by their "roughness" and "metallicity"). Just by playing with those 2 parameters we can get these kind of results:
I invite you to read the following tutorial to learn more about it:
https://learnopengl.com/PBR/TheoryWhat the engine can do now:- Render the geometry of the scene with 3D intersection of objects using their heightmap
- Lighting of the scene using PBR methods
- Directionnal shadow casting using the visible geometry of the assets
- Dynamic shadow casting for omni lights using invisible simplified 3D geometry added to the scene (good for buildings, wall, ...)
- SSAO
- SSR
- Bloom
- Two layers of rendering, allowing basic transparency (mainly for antialiasing)
- Optimization for static objects using tiling (I'll explain this in another post)
Most of the "classical effects" were done by following and adapting the content from here:
https://learnopengl.com/GoalsIn the short termThere is still a lot of things to do to improve the architecture of the engine, add basic fonctionnalities (animated objects for example) and optimization (e.g. optimize lighting and shadowing). I also plan to do rain, with wetness effect for exposed zones (with a similar tech than what I do for directionnal shadows). I'm also thinking about adding 3D mesh in the scene (maybe for the characters, because prerendering all animations is really costly in terms of textures, eating a lot of ram and disk space) and for animated foliages. I'll add screen spaces decals, for blood rendering for example, and particles for smoke. I would also like to add terrain editing using heightmaps. I'm also thinking about adding screen space physics simulation for particles.
And if you have other ideas, I'm listening.
In the long termI plan to use the engine in an indie open-source game (not Holyspirit 2). But the project is not mature enough for me to talk about it right now.
And why not 3D ?The first answer that comes to my mind is very simple: I can't do low-poly 3D mesh. But I can do messy hight-poly things. Hence it means I can make my own assets.
Moreover, I really like the old-school look that the 2.5D iso gives.
Finally, it's really fun to develop, and it allows to do interesting optimizations (but it's more costly than simple 3D or classical 2D).
What about the sources ?You can find them here
https://github.com/gregouar/ALAG. However, they are still a bit messy so you should be careful before using anything from there. Also, I must warn you that I use a modified version of SFML where I add a new class: MultipleRenderTexture, allowing me to do multiple render targets in an SFML-like framework (but it's probably not really well done and maybe Laurent will be mad to see what I did
).