The word “bullshit” is probably an exaggeration, although I honestly dislike it like everyone else does ( At least to my understanding ). What I’m talking about is the glorious exams, not university exams just regular high school exams. But that part is over now, and I’m more or less satisfied with the result. Now, since that part is over, I got lots of time to code and stuff…
Just since the beginning of the exams to now, I’ve been rewriting my engine. And got pretty much everything implemented. The performance was the main goal. The previous version of my engine ran at ~100 fps at half of the screen resolution, the newely written engine runs at ~120 fps at full HD resolution (i.e. 1920 x 1080). Now this is a big thing because I’ve got a lot of post processing effects that really torture the gpu bandwith, such as volumetric scattering, so the resolution seriously affects the frame time. And together with that the architecture of the new system is seriously better together with the new material system that I wrote about in my last entry ( It has been upgraded a bit from that point )
There’s still lots of small optimizations to do, and still lots of unfinished “new” features. But one of the main things I changed is the way my voxelization system works. Every single time a new mesh/object/whateverpeoplecallit has been added the scene the mesh is voxelized without any transformation applied to a “cache” buffer, this cache buffer is added to some list of a sort. Then there’s the main cache buffer that represents the final voxel structure around the camera. So each frame ( through a compute shader ) all voxel caches are iterated through, then each cell of the caches are first transformed by the current transformation matrix of the mesh ( As each cache represents a mesh without any transformations ) and then fitted inside the main voxel cache ( With some magic stuff that speeds this up ). The awesome thing about this is that every single time the camera is moved / the mesh is moved, scaled or even rotated there no need to revoxelize the mesh at all ( Less frame time, yay ).
Although I chose to disable screen space reflections as IMHO there were too many artifacts which were too noticeable. So in the meantime I have a secret next gen way to perform pixel perfect indirect specular reflections ( I WISH )
Currently, all effects combined minus the ssr, showing off volume shadows. Nothing fancy.
.
.
Oversaturated example of the diffuse gi:
.
.
Dynamic filling of the voxel cache, oriented around the player:
.
.
So while playing around, I found this “mega nature pack” in the Unreal Engine 4 marketplace. So I purchased the package and started messing around, just programmer art . Now all this shows is that I have some serious work to do with my shading model, and I need to invest some time into some cheap subsurface scattering… Btw in the image below the normals are messed up, so the lighting appears weird in some points. And the volumetric scattering is disabled, since it also desaturates the image a bit ( For valid reasons ).
.
.
So I tried messing around with the normals and used the SV_IsFrontFace to determine the direction of the normal on the leaf, and got something like this: ( Volumetric scattering disabled ) ( Btw, quality is lost due to gifs! I love dem gifs ) ( Ignore the red monkey )
.
.
The following is the shader used for the tree, which is written by the user: ( Heavily commented )
.
Shader { // Include the CG Data Layouts #include "cg_layout.hlsl" // Define the return types of the shader // This stage is really important to allow the parser // to create the geometry shader for voxelization // and also if the user has created his own geometry shader, so that it can figure // out a way to voxelize the mesh properly, in this way the user // can use ALL stages of the pipeline (VS, HS, DS, GS, PS) without // voxelization not being possible. // The only problem is well, he has to write the stuff below: ( Even more if he used more stages ) #set CG_RVSHADER Vertex // Set the return type of vertex shader #set vert CG_VSHADER // [Opt] Set the name of the vertex shader instead of writing CG_VSHADER #set pix CG_PSHADER // [Opt] Set the name of the pixel shader instead of writing CG_PSHADER // This is his stuff // He can do whatever he wants! Texture2D T_Diffuse : register(t0); Texture2D T_Normal : register(t1); // Basic VS -> PS Structure // This structure inherits the "base" vertex, stuff that the engine can crunch on struct Vertex : CG_VERTEXBASE { // Empty }; // Now include some routines that's needed on the end of all stages #include "cg_material.hlsl" // Vertex shader Vertex vert(CG_ILAYOUT IN) { // Zero set vertex Vertex o = (Vertex)0; // Just let the engine process it // Although we could do it outselves, but there's no need CG_VSPROCESS(o, IN); // Return "encoded" version CG_VSRETURN(o); } // Pixel Shader // In this case the return type is FORCED! As it's a deferred setup CG_GBUFFER pix(Vertex v, bool IsFrontFace : SV_IsFrontFace) { // Basic structure containing info about the surface Surface surf; // Sample color float4 diff = CG_TEX(T_Diffuse, v.CG_TEXCOORD); // Simple alpha test for vegetation // We want it to clip at .a = 0.5 so add a small offset clip(diff.a - 0.5001); // Fill out the surface information surf.diffuse = diff; surf.normal = CG_NORMALMAP( // Do some simple normal mapping T_Normal, v.CG_TEXCOORD, v.CG_NORMAL * ((IsFrontFace) ? 1 : -1), // Flip the normal if backside for leaves v.CG_TANGENT, v.CG_BINORMAL ); surf.subsurface = 1; // I've got a simple version of some sss, but it's not very good yet. surf.thickness = 0.1; // For the sss surf.specular = 0.35; surf.anisotropic = 0.2; surf.clearcoat = 0; surf.metallic = 0; surf.roughness = 0.65; surf.emission = 0; // Return "encoded" version // Aka compress the data into the gbuffer! CG_PSRETURN(v, surf); } };
.
So in the progress of all of this, I’m trying to fit in some SMAA and color correction. And the moment I looked into color correction using LUT, I face palmed, because how the hell did I not think of that!? ( Not in a negative way, it’s just so simple and elegant and pure awesome! ) So messing around with that and spending 5 hours on a loading problem which turned out to be too simple, it returns some kewl results: ( Just messing around )
.
.
So that’s more or less it. I’ll keep improving my engine, working on stuff and more stuff. I think I’ll leave the diffuse gi system where it is for a while, since it works pretty well and produces pretty results, now I need to work on some specular gi stuff since I really don’t have a robust system for that yet that doesn’t produce ugly artifacts.
See you next time people of the awesome GDNet grounds! ( GDNet -> GameDev.net )
-Migi0027