Journal Entry 59 – Better late than never?

Happy December everyone! I’ve had a pretty crazy week, which is why my blog postings haven’t been happening. I do have some cool progress to share. The first news (that you may have already read on Twiter) is that I have some help with creating the art assets in the game! Hopefully there will be some cool stuff to show off soon :D I have been back and forth with her quite a bit to fix issues with the client she is using. She is using a Mac, which meant that I had to go back and support the Mac operating system. Since I am using C# and OpenGL, it isn’t a far stretch to get Mac support via Mono. However, there are some issues to overcome.

The first issue is regarding shaders. Mac OS X only supports up to #version 120 of GLSL. Since all of my code is written with newer versions of GLSL, I need some way to fallback to the older version for the Mac. Well, it turns out I am only really using the newer versions of GLSL for speeding up certain things and making life easier (for example – Uniform blocks). I ended up writing a C# method that can convert pretty much 100% of my GLSL code into Mac OS X compliant code with a few simple string operations. I then need to do a bit more work on the Mac for setting my camera and other functions that take advantage of the newer version of GLSL.

One of the first scenes I got up and running on the Mac OS X using Mono+OpenGL.  All of the normal editor functionality is available to use on either Mac or PC (or Linux, too!).
One of the first scenes I got up and running on the Mac OS X using Mono+OpenGL. All of the normal editor functionality is available to use on either Mac or PC (or Linux, too!).
Here I've added full multiplayer support and server/client connectivity to the Mac client.  It didn't take too long to get up and running around with friends in-game.
Here I’ve added full multiplayer support and server/client connectivity to the Mac client. It didn’t take too long to get up and running around with friends in-game.

Next, I wanted to tackle a few visual aspects. It is tough to render dense forest, since I cannot draw easily across Voxel Chunk boundaries. You might already see from the first screenshot that this issue has been addressed with the latest builds. Here’s a crazy jungle!

Adjacent chunks get certain information about their neighbour, which allows trees and other objects to be seamlessly connected across chunk boundaries.
Adjacent chunks get certain information about their neighbour, which allows trees and other objects to be seamlessly connected across chunk boundaries.

It gets even crazier once you are under the tree canopy, with all of the shadows and dense trunks/leafs/clutter.

Things look pretty clear above the canopy, but below is a different story.  Real jungle biomes will need all sorts of cool and bushy ground clutter too.
Things look pretty clear above the canopy, but below is a different story. Real jungle biomes will need all sorts of cool and bushy ground clutter too.

Finally, I did a bit of work on the stability of the client, optimization and some lighting! I’m working on making sure that lit objects actually have some specularity. Here’s a preview of what’s in the works:

I've turned off the normal lighting (aside from basic ambient lighting) and instead am relying upon the 'gem' in this stone to cast light.  Specularity has been added to make the light sort of 'glow'.
I’ve turned off the normal lighting (aside from basic ambient lighting) and instead am relying upon the ‘gem’ in this stone to cast light. Specularity has been added to make the light sort of ‘glow’.

Anyways, that’s it for now! I just wanted to let everyone know I’m still working on stuff.

Giawa

PS: I got a new computer, which is why all of the new screenshots are Windows 8.1. Takes some getting used to, but I’m loving the speed of the processor.

Journal Entry 58 – NPC Characters

I hacked around for a little bit today on starting up support for non-player characters. I would like to be able to have procedurally generated quests, storylines, histories, etc for many of the characters in the game. However, to start, I need to display them in the world and move them around reliably. They need to be affected by the same collision detection that affects the main player, and they need to be able to figure out how to get from one place to another. The first thing to do is to load a new player into the game:

Our main character and an NPC can now co-exist in the same world.  Check out the video below for some basic point+click path finding.
Our main character and an NPC can now co-exist in the same world. Check out the video below for some basic point+click path finding.

I then modified the code to have gravity and collisions affect the movement of the character. Finally, I used the methods I had already written for server communication to queue up movement for the NPC character.

Tomorrow I’ll be finishing up my conversion of A* pathfinding over to the voxel data structure. More soon,

Giawa

Journal Entry 57 – Character Centered Haze

I was late getting home tonight, so there isn’t too much to report. I cleaned up the rendering thread quite a bit, and moved a lot of the random code that I’ve left behind. This leaves about 5 lines of code to actually render everything on the screen. I’m doing this housekeeping because I am writing a second rendering path, which is deferred shading. I’d like to be able to render (potentially) hundreds of lights, and this is the only way I’ll get any sort of performance out of the engine with that sort of lighting. Hopefully I’ll have some cool screenshots to show over the next few days! Until then, I did get a bit of other work done.

Until tonight, all of the terrain fading (fog of war, haze, etc) was calculated via the fragment depth, which means that it was all from the point of view of the camera. This caused clutter and the terrain to fade out/in as you the camera was moved. I’ve now decoupled the haze from the camera, and have bound it instead of the player. This requires sending position data of the player each frame, but it isn’t too bad. Here’s how the new code looks as the world is loaded in:

This is how the terrain looks when it is only partially loaded in.  The character is now centered in the haze, which is a lot more convincing.  The fog is then pushes back as more chunks are loaded (which takes only a few seconds).
This is how the terrain looks when it is only partially loaded in. The character is now centered in the haze, which is a lot more convincing. The fog is then pushes back as more chunks are loaded (which takes only a few seconds).

Once the world is loaded in, and the clutter distance is set, the clutter will stay centered around the main player. This was pretty straight forward to accomplish in the shader with a player position uniform. Here’s a video of the new haze in action!

Cheers,

Giawa

Journal Entry 56 – User Preferences

I didn’t get too much time tonight, as I am working on the flooring of one of my bedrooms. However, I did get to tackle one item on my TODO list. I’ve been meaning to have a preferences file to save any settings. So, I’m simply using JSON to write out a preference file. The preferences contains information on draw distance, vsync, fullscreen, and other common options. Here’s some of the properties:

public enum Quality
{
    High,
    Medium,
    Low,
    Off
}
 
public Quality DrawDistance { get; set; }
 
public Quality ClutterDistance { get; set; }
 
public int Height { get; set; }
 
public int Width { get; set; }
 
public bool VSync { get; set; }
 
public bool Fullscreen { get; set; }

This allows the user to tailor the program to their computer specifications, and limit the amount of drawing that occurs. Here’s an example of the program running with all of the settings cranked pretty much to their lowest:

With the graphics settings at lowest, even the more modest computers should have no problem rendering the scene.  However, modest computers will have to deal with close-in fog and sparse ground clutter.
With the graphics settings at lowest, even the more modest computers should have no problem rendering the scene. However, modest computers will have to deal with close-in fog and sparse ground clutter.

Notice the sparsity of the clutter, and the low rendering distance of the terrain. Now here’s max settings:

On the opposite end of the spectrum, here's the world rendered at the highest graphics settings.  This includes denser ground clutter, further draw distances and more!
On the opposite end of the spectrum, here’s the world rendered at the highest graphics settings. This includes denser ground clutter, further draw distances and more!

Notice that the frame rate is still limited to 60fps. We can now disable this with the VSync option, which gives the following performance on my older computer. I’ll probably have to offer even higher graphics settings in the future!

If, for some reason, vertical synchronization (v-sync) is not your cup of tea, it is now an option in the settings.
If, for some reason, vertical synchronization (v-sync) is not your cup of tea, it is now an option in the settings.

The settings files looks something like this:

{"DrawDistance":"Medium","ClutterDistance":"Medium","Height":720,"Width":1280,"VSync":true,"Fullscreen":false,"ZNear":0.1,"ZFar":1000}

That’s it for now! It did take some time to connect up all of the Preferences, so I think this was a pretty good accomplishment for tonight. More soon,

Giawa

Journal Entry 55 – Wind and Recording

I spent a bit of tonight working on the voxel engine, but unfortunately my priority had to be on consulting work. I decided to have a bit of fun with wind, and making it roll across the terrain. To do this, I needed something suitable to blow about in the wind. I always picture rolling plains of wheat, so I decided to make some wheat.

I created some simple wheat to place on the terrain and blow around with my shader generated wind.
I created some simple wheat to place on the terrain and blow around with my shader generated wind.

I then applied this wheat to the terrain, and applied it often! I also moved the wind calculations completely over to a shader, which was lots of fun. I just make a simple ‘skew’ matrix and then apply it to the vertex positions.

// calculate the skew matrix
mat4 wind_matrix = mat4(1.0);
wind_matrix[1].x = tan(rad / 3);
 
// get the position, normal and light position
vertex_position = (model_matrix * wind_matrix * vec4(floor(in_position), 1)).xyz;

By manipulating the value of ‘rad’ with respect to position, I can now make the wind roll across the terrain. Here’s a picture of it in action (which doesn’t really give it full justice).

Can you spot my character?  The wind blows across the terrain, making the effect look more like real wind!  Soooo pretty, and the picture doesn't do it justice.  Check out the video of the wind in action below.
Can you spot my character? The wind blows across the terrain, making the effect look more like real wind! Soooo pretty, and the picture doesn’t do it justice. Check out the video of the wind in action below.

I then spent some time on figuring out how to make perfectly smooth videos. My computer is *really* old. It is an old school Core 2 Duo E8500, and I’m in dire need of an upgrade. However, I need to make do with what I have for now, so I wrote up some quick code to write out each frame to a .png file. It works by simply reading the pixels and writing them to a Bitmap. I make sure to lock the bitmap bits to make for quick copying.

int[] pixels = new int[Width * Height];
Gl.ReadPixels(0, 0, Width, Height, PixelFormat.Rgba, PixelType.Byte, pixels);
 
// we need to process the pixels a bit to deal with the format difference between OpenGL and .NET
for (int i = 0; i < pixels.Length; i++)
{
    int p = pixels[i];
    int r = p & 0xff;
    int g = (p >> 8) & 0xff;
    int b = (p >> 16) & 0xff;
    pixels[i] = (r << 16 | g << 8 | b) << 1;
}
 
// create a new bitmap object of the correct height and width and then lock the data for quick access
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(Width, Height);
var data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, Width, Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
Marshal.Copy(pixels, 0, data.Scan0, pixels.Length);
bitmap.UnlockBits(data);
 
// bitmaps are flipped in the y direction, so flip it back
bitmap.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipY);
 
// write the frame out to a file
bitmap.Save("F:/capture/frame" + frameID++ + ".png", System.Drawing.Imaging.ImageFormat.Png);

I then recombine the frames back together to create a nice and smooth video. Here’s an example of a video recorded in this manner:

Until next time!

Giawa