Warning: Ignoring warnings is bad for you.

May 20, 2013

Warnings matters.

Programmers might ignore warnings. Both in compilation and in run time.

A warning is not a compilation error, so why are they important?

Think of a warning as increased risk for a horrible crash.

Not only do you want to pay attention to warnings(compilation or run time), you would also want to log warnings yourself. In the case you are developing a framework.

I am working on a new game and my framework works on both the PC and Android.

In the PC version everything worked fine, but in the Android version the collision detection didn’t work.

When I am loading a mesh I am copying its vertex position data so I could use it for collision and physics.

However, on the Android version I was releasing this data in order to save up memory. I also added a method named ‘SetKeep’ to mark a mesh as one that I don’t want to release its physics related data.

I wasn’t working on the Android port of my framework for some time and I completely forgot that I am releasing the collision data on Android but greedily keep it on the PC. That is why it worked on the PC but not on Android.

I just couldn’t understand why my collision data was empty.

A simple log warning mentioning that I am trying to access the collision data without keeping it first would have saved me a lot of time.

Shotgun Practice! Quick game dev.

May 17, 2013

It took me only a few days to create this small Android game, and to my surprise it is actually a fun game.

I figured I won’t learn how to design games if it takes me 2 years to finish each game. In addition it’s a lot more exciting and motivating to release a game to the Android app store.

So without further ado, please download and try Shotgun Practice(it’s free!):

ShotgunIcon144

std::vector resize bug

April 19, 2013

There is a certain bug that I keep making again and again.

In C++ there is a standard template library data structure called vector.

It is a data structure that gives you random access to it’s content, much like an array.

A vector can be of variable length and there are several ways to initialize and change it’s size. One of the methods to change it’s size is std::vector::resize.

The advantage of resize is that it can be used after the ctr. But there is a subtle point that needs to be considered.

When you resize std::vector it doesn’t necesseraly call the dtr of it’s content.

The most common issue of this for me is when I want to load new data to std::vector not realizing the old data is still there. Imagine we have std::vector<std::list<unsigned int> >.

After resizing the lists in this case might not be empty.

In order to make sure your vector is empty you should call std::vector::clear first.

Flashlight gameplay test.

March 17, 2013

I got back to working on Shoe String Shooter, a PC game using DirectX11.

I was testing gameplay with flash lights. The reason behind it is that flash light allow you to see to a longer distance but they also reveal your position. Another possibility is that the flash light is going to blind your enemy if he looks into it directly.

Another reason is probably that I would like to fiddle with making better lighting for my game.

In the meantime, here is a youtube video demonstrating flash lights in multiplayer.

 

Pointing\Touching objects in a 3D game for the mobile.

February 3, 2013

If you are making a 3D game for a mobile device you are likely to handle a screen touch input.

In a 2D game, converting the screen touch coordinates into the game position is simple enough.

However, in a 3D game there is more to consider.

When you want the user to click a 3D object in your game, there are several ways to do that.

You can project the object’s position to the screen coordinates and test if the touch position is close to the projected object position.

Or you can convert the touch screen coordinates into a 3D position inside the game’s world coordinates.

I will focus on the second method since it also allows for dragging objects and setting an object’s position.

From Touch to 3D

In order to calculate a 3D position corresponding to our touch screen coordinates, we will need to store the 3D camera\view’s inverted View and Projection matrices separately.

The view and projection matrices are used to project a 3D object into the 2D screen as it would be seen from a camera.

The View matrix of the camera place the 3D object relative to the camera’s origin, and the Projection matrix will project the 3D object into the camera’s “film” or the 2D receiver screen\chip.

What we are going to do is the inverse operation. We will take a coordinate on the camera’s 2D screen\film and find a corresponding 3D position that would have been projected into the camera screen had we did the normal projection from 3D to 2D.

Lets look at some code:

			Graphics2D::Position CalcTouch(double x, double y)
			{
				Graphics2D::Position p2 = InvProj.MulPosNormal(Graphics2D::Position(x/320., -(y/512.), 0));
				Graphics2D::Position p3 = InvProj.MulPosNormal(Graphics2D::Position(x/320., -(y/512.), 1));
				Graphics2D::Position n = (p3-p2).Normalize();
				p2 = InvView.MulPos(p2);
				p3 = InvView.MulPos(p3);
				n = InvView.MulDir(n);
				n = n/n.y;
				p2 = p2-n*p2.Dot(Graphics2D::Position(0, 1, 0));
				return p2;
			}

The function above accepts a 2D coordinate(x and y) and returns a Graphics2D::Position, which is actually a 3D coordinates in my framework.

At first we convert (x, y) into 2 screen space vertices and inverse project them to get 3D vertices(stored into p2 and p3).

The reason we inverse project two vertices is that we want to get a position and a direction(a 3D ray).

After getting the position and direction relative to the camera’s origin, we multiply them by the inverse View matrix to get the position and direction in world space coordinates.

We now have the ray we want but we want to select or drag an object. For that we are intersecting the ray with the plane of our choice(in our case the xz world space plane) and we get our desired 3D point.

After getting the 3D point we can set the object to that position or we can compare the object’s position to that point to see if the player selected that object.

Boosting the FPS: GC (Part 1)

December 25, 2012

I was getting annoying long stutters on the render rate of my 3D Android RPG game Heroes Of Honesty(http://www.PompiPompi.net).

It was weird to me because normally I would see most frames time were bellow 33ms which means I would need to get at least a solid 30 FPS. As can be seen in this diagram:

Frames bellow 33ms

After a few more measurements and profiling, I realized what was one of the issues responsible for this stutter. It turns out the Garbage Collector implementation on Android for Java is not very good.

You can see, in the following diagram, there are gaps in the GLThread(the render thread) whenever the GC kicks in:

GC Stutters

(Notice the GC kicks in about every 300ms in the diagram above)

GC saves programmers the hassle of managing memory allocation and release. However, the more you allocate memory at run time the harder the GC will have to work to clean after you. So in order to prevent the GC from working hard we need to minimize the amount of allocations we make.

We do this by “recycling” memory. We use a memory pool, a chunk of pre allocated memory or an array of pre allocated memory we allocate once and reuse many times for different data.

Let’s say you need to set a Projection matrix to an OpenGLES2.0 shader. You might allocate the matrix before each time you send it, it might be even inside a render loop used for many different 3D objects.

Instead of allocating the matrix for each object, we can allocate it once outside the loop and reuse the same memory chunk for all the 3D objects in the render list.

After minimizing some of the memory allocations in the render thread, I got the following results:

Better performance of GC with memory recycling.

Notice the GC occurs once every 800 ms.

There is another issue. What I have shown up until now was a scene with static resources. I couldn’t load the whole map of Heroes Of Honesty into memory, so I had to dynamically load map patches only when they are required.

This means that in some of the frames I put an extra effort in loading resources into VBOs. I also happen to allocate a lot of memory in the process of generating the index and vertex data before sending them to the GPU.

The following diagram shows what happens when we are in the middle of dynamically loading resources:

Dynamic resource loading and GC

On the left side of the diagram you can see there is a big gap between the two times the GC get to work. However, on the right side the GC is being called many times.

Notice that not all of the stalls are due to the GC’s fault, some of it is because of the extra work we need to do to actually generate the dynamic resource.(more on that on the second part)

The following diagram shows the performance after using memory pools and recycling memory for the index and vertex buffers that need to be dealt while loading a dynamic resource:

GC performance is now better with dynamic resources

In the diagram above you can see the GC doesn’t work any harder when dynamic resources are being created. You can see where resources are being create because the GetMesh method is marked with little wedges.

Notice that there are still gaps in the render thread and we will still get stutters even though we solved the GC issue.

For the sake of completion here is a closer look at the frames timelines while loading dynamic resources:

Single thread resource loading.

In the diagram, a “normal” render frame would consist of a mostly black part and a pink part. The black part is mostly the OpenGLES draw calls, and the pink part is the game logic update. Currently they are both done in the same render thread.

Some frames have a green part, the green part is CPU time “wasted” on loading the resource. As you can see the many green parts make the frame time longer and thus the frame rate will drop once in a while.

You may also notice that the GC doesn’t do work this whole time. In the next part I will explain how I improved the render thread’s rate and the overall performance(with multi threading).

Improving Animations’ Key Frame Performance on the CPU

December 22, 2012

For my 3D Android RPG game Heroes Of Honesty(http://www.PompiPompi.net/) I was making 3D animated characters.

There are numerous ways to animate a 3D characters and one of the ways is to have an artist set animation key frames.

A key frame is a state of an object or bone of the character set in a specific time of the animation timeline. By setting many key frames you can animate the characters into all sort of pre made behaviors.

When drawing an animated character in a 3D game, you would select a specific time in the animation timeline and calculate the posture of the character in that specific time. The posture is then calculated by the nearest keyframes in the timeline and interpolate two adjacent key frames if there is no key frame at that specific time.

How would you find which key frame is the closest to the frame time?

Linear search

Since the keyframes are ordered from the earliest to the latest we can go from the beginning to the end, one step at a time, and stop when we find the first key frame that is bigger than our current frame time.

This sort of search has O(n) complexity and it is pretty slow when we have a lot of key frames.

We might have many key frames if our animation software bakes the keyframes for things such as Inverse Kinematics.

Binary search

We can do better than linear search.

Since our key frames are ordered in the time line from small to big, we can do a binary search.

The binary search algorithm always check half of the relevant key frames. If we know a specific key frame is bigger than our frame time then all the key frames above it are irrelevant for us. We then continue to check the second half of the first half(the quarter) we found is relevant and so on.

The following code is a binary search in C++:

	unsigned int
	Mesh::AnimationNode::CoreFindPosition (aiNodeAnim * n, unsigned int First, unsigned int Last, double t)
	{
		if (First+1>=Last)
			return First;
		unsigned int Index = (Last+First)/2;
		if (n->mPositionKeys[Index].mTime==t)
			return Index;
		if (n->mPositionKeys[Index].mTime<t)
			return CoreFindPosition(n, Index, Last, t);
		return CoreFindPosition(n, First, Index, t);
	}

For the binary search we get a complexity of O(log(n)).

Baked Search

We can do even better. Our game render rate is limited. Most games run at no more than 60 Frames Per Second. This means that at the very least the animation time steps would be 16.67 ms.

We can create an array that will be the size of the animation timeline divided by the rendering frame time(16.67 ms). This array will have indices to the nearest key frame to the frame time each entry represents.

Now in order to find the closest key frames we simply access one array cell that corresponds to the animation’s frame time and get the index of the closest key frame.

This algorithm is of O(1) complexity.

Full baking?

A character usually consists a hierarchy of objects that compose all the parts of the character. In order to animate the character we need to find each object’s relative position key frame, and then calculate its absolute position up to the root object.

Instead of baking indices of key frames in the baked search, we can bake the absolute position of the object in that specific time. Since the rendering FPS is limited, we can bake the absolute position dense enough so we won’t need to interpolate.

This will save us all the hierarchical calculation of the animation tree. However, this way we won’t be able to mix this specific animation with other animation or mix it with dynamic elements such as rag doll animation.

3D Graphics Quality and Floating Point Accuracy on Android

December 21, 2012

I am working on a 3D RPG game for the Android called Heroes Of Honesty http://www.PompiPompi.net.

My Galaxy Note Android phone got less than 16M concurrent colors. I am not sure how many, maybe 64K colors, maybe a bit more. The point is that on 3D graphics, gradients look a bit coarse color wise.
There is nothing much you can do about it, this is a hardware limitation although you might be able to choose a different color palette.

However, there is another issue. Floating point accuracy.

There is a limitation to floating point accuracy on the programmable shaders of GLES2.0, and you can even reduce the accuracy on compile time.
This might cause artifacts, and it might be worse than you realize.

The following images were taking from my Galaxy Note phone. You will notice that the top image’s gradients are more coarse. This is exactly the same scene.

Bad Float Accuracy

Good Float Accuracy

You can see the gradients on the fog at the back, and also if you look carefully at the ground you will see at the top picture that it’s more jagged.

So why does this happen? This is the exact same scene.

When drawing a 3D scene you need to set the position of the objects to draw and the position of the camera and light sources.

At this scene the characters are somewhere on the world map away from its center. This mean I am setting the camera look at 3D coordinate to something such as (-1000, 0, 1000).
The character on the center is at the same position of the camera look at coordinate, so it’s position is also set to (1000, 0, -1000).

What if we would draw the same scene, but now we move all the objects, camera and light source so the main player will be at position (0, 0, 0). It doesn’t matter for the scene since we always look from the viewpoint of the camera.

It turns out that doing this improve the floating point accuracy.

Since positioning the camera and characters at (1000, 0, -1000) makes the floating point contain a large number(1000), all the calculations relative to it are done relative to a big number. Therefore there are fewer bits in the floating point assigned to the smaller values.

Such smaller values might be the vertex coordinates of the character’s mesh, but now instead of being 1000.01 they are 0.01 which leaves more room for accuracy.

The top image is rendered when everything is placed relative to the map’s center, and the bottom image is rendered when everything is placed relative to the character’s center.

Announcing “Heroes Of Honesty”

November 24, 2012

For several months I have been developing a new game called “Heroes Of Honesty”.

It is a 3D Android RPG game with a possible build for the PC.

The game plays like a classic RPG with tactical battles. The name of the game is meaningful to the story.

Once the game is complete, I will be releasing a series of articles about how I improved the game’s performance for the Android.

I am not going to reveal too many details about the game before the date of release.

If you are curious about the game you can subscribe to the newsletter list, follow me on twitter or subscribe to the RSS feeds.

The game’s website is http://www.PompiPompi.net/

A Work In Progress screenshot that will give you a glimpse of the game:

Work In Progress

GLES 2 and unsigned byte attribute (ivec4?)

November 11, 2012

I was trying to have a VBO with bone indices in my Android GLES2 3D game.

The issue is that most of the vertex buffer contains float while the indices only require unsigned bytes.

At first I was just using floats as indices for the bones but I wanted to do better. So I made a vertex buffer that have both floats and unsigned chars.

In order to tell GLES2.0 you want 4 indices of unsigned chars you need to call:

GLES20.glVertexAttribPointer(
Shader.INDICES_POS,
4,
GLES20.GL_UNSIGNED_BYTE,
false,
mStride,
offset);

You will need to make sure you pass a ByteBuffer with the correct format to GLES2 with GLES20.glBufferData.

Lastly, and this is the tricky part and reason why I wrote this article. How to refer to unsigned bytes attributes inside the GLSL shader code?

Well it turns out GLES2.0 does not have ivec4 which is a vector of 4 ints. However, in GLES2.0 you can use “attribute vec4″ for unsigned bytes even though the bytes are not 32 bit floats.

This will result in a float data type but you can convert it into int using int(YourVar).


Follow

Get every new post delivered to your Inbox.