All posts by giawa

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

Journal Entry 54 – Mesh Optimizations

I have been busy! The first thing I spent some time working on was the user interface in the editor. My goal was to get a few buttons down, and have the editor a bit easier to use by showing the state of some of the functions (such as symmetry). I snagged some open source icons and then got to work. I wrote up a small Button class which inherits UIElement. Here’s the result, which has highlighting on mouse enter/etc.

The editor now contains a very basic user interface, complete with a tooltip at the top of the screen!
The editor now contains a very basic user interface, complete with a tooltip at the top of the screen!

Here’s an example of how a Button works:

// add buttons to correspond to the keys
Button newButton = new Button(new Texture("tex/icons/document-new-8.png"));
newButton.RelativeTo = Corner.BottomLeft;
newButton.Position = new Point(30, 0);
newButton.OnMouseClick = new OnMouse((sender, eventArgs) => VoxelManager.CurrentManager.VoxelChunks[0].Destroy());
newButton.OnMouseEnter = new OnMouse((sender, eventArgs) => EditorOnEnter(newButton, "Create New Chunk (Ctrl+N)"));
newButton.OnMouseLeave = new OnMouse((sender, eventArgs) => EditorOnLeave(newButton));
UserInterface.AddElement(newButton);

Then I got a message from a friend, and she recommended trying out some texturing on the terrain. Her idea was to put patches and other textures (usually square-ish). I thought about this a bit, and tried to decide how to implement it. Up until now, the engine has only worked to remove faces, and hasn’t done a lot of work to combine those faces. You may remember that I did write a greedy algorithm before, but then I removed that algorithm in favour of supporting SSAO, perlin noise and other features more easily. Anyways, I decided to tackle the greedy algorithm today so that I could add patches.

The new mesh optimization adds a visual appeal via textures and also makes the game much faster!
The new mesh optimization adds a visual appeal via textures and also makes the game much faster!

I am not going for a 100% optimized mesh, because there is visual appeal to making large ‘squares’. So, I first try to fit as many large squares as possible, and then move from there. The next step is to fit in strips in different directions, and then finally I am only left with the single voxel faces that cannot be optimized. The new mesh optimization reduces the vertex count by more than 50%! Woot!

Nearly everything benefited from the new mesh optimization, including the ground clutter.
Nearly everything benefited from the new mesh optimization, including the ground clutter.

What about that patchwork? I implemented UV co-ordinates, which weren’t support prior to today. This allows me to assign textures to the meshes. Here’s the terrain with a single texture applied. I’m going to play with the graphic style to see how it looks with multiple textures, or if I should stay with a single texture per terrain type, etc.

Here's our hero in a new land full of textures patches, but still familiar with shadows, ambient occlusion and the other visuals that he has come to expect.
Here’s our hero in a new land full of textures patches, but still familiar with shadows, ambient occlusion and the other visuals that he has come to expect.
Another angle in the editor, showing off the optimization that occurs on all faces (not just faces pointing upwards).
Another angle in the editor, showing off the optimization that occurs on all faces (not just faces pointing upwards).

I’m sure that I will be experimenting lots over the next few days. I hope to have a more polished graphical style (including some different terrain colors, etc) within the next few days. I’ll keep you posted!

Giawa

PS: That terrain clutter is loaded in via JSON, which I mentioned before. However, here’s sort of what it looks like. You’ll be able to assign your own models, and customize the game with your own fruits/veggies/items/etc. Want to share with your friends? No problem!

[
{"ID":61444,"Name":"Clutter Fern","ChunkPath":"fern.zvc","Scale":0.1},
{"ID":61445,"Name":"Clutter Flower 1","ChunkPath":"flower1.zvc","Scale":0.1},
{"ID":61446,"Name":"Clutter Flower 2","ChunkPath":"flower2.zvc","Scale":0.1}
]