DDS and DXT format

If you are working on a game chances are you will work with DDS (DirectDrawSurface) files. DDS file is a standard format by Microsoft to store image/textures. It can store single image, mip maps, cube maps, etc2 and can have standard DXT compression technique.

If you want to understand various DXT variants (DXT1, DXT1a, DXT3, DXT5), you can check out:

The following library/tools are proven to be useful:

If you ever need to write your own source code, the following links can be your starting point (don’t just copy and paste, some of them have bugs):

Sep07

Reconstructing Position From Depth

Matt posted an excellent article about reconstructing position from depth. Check out his article here: http://mynameismjp.wordpress.com/2009/03/10/reconstructing-position-from-depth/

He has the following function to reconstruct View Space Position from Post Clip Space Position:

// Function for converting depth to view-space position
// in deferred pixel shader pass.  vTexCoord is a texture
// coordinate for a full-screen quad, such that x=0 is the
// left of the screen, and y=0 is the top of the screen.
float3 VSPositionFromDepth(float2 vTexCoord)
{
    // Get the depth value for this pixel
    float z = tex2D(DepthSampler, vTexCoord);

    // Get x/w and y/w from the viewport position
    float x = vTexCoord.x * 2 - 1;
    float y = (1 - vTexCoord.y) * 2 - 1;
    float4 vProjectedPos = float4(x, y, z, 1.0f);

    // Transform by the inverse projection matrix
    float4 vPositionVS = mul(vProjectedPos, g_matInvProjection);  

    // Divide by w to get the view-space position
    return vPositionVS.xyz / vPositionVS.w;  
}

The basic idea is that if we have a matrix that transfoms from View Space to Clip Space, we just take the inverse of that matrix and multiply it with the clip space position we should be able to get back the view space position. But my biggest question was why did we need to divide-by-w (in view space) at the end?

I thought the order is like this:

PosInClipSpace = PosInViewSpace * ProjMtx;
PosInPostClipSpace = PosInClipSpace / PosInClipSpace.w;

so, if we want to get back from PosInPostClipSpace to PosInViewSpace, we need to do this:

PosInClipSpace = PosInPostClipSpace * PosInClipSpace.w;
PosInViewSpace = PosInClipSpace * ProjMtx_INVERSE;

so, somehow we need to save the w in order to get back the position in View Space. Out of curiosity, I did the Inverse of Projection Matrix MANUALLY and work out the following:

PosInViewSpace0 = PosInPostClipSpace * ProjMtx_INVERSE;
PosInViewSpace = PosInViewSpace0 / PosInViewSpace0.w;

It turns out the MATH WORKS OUT! I can’t see why this is happening logically, but mathematically it’s correct! It’s amazing, I learned a new thing today!

My next question is, if I want to bring it to World Space instead of View Space, do I need 2 matrix multiplication steps such as the following:

PosInViewSpace0 = PosInPostClipSpace * ProjMtx_INVERSE;    // First Mtx Mult
PosInViewSpace = PosInViewSpace0 / PosInViewSpace0.w;
PosInWorldSpace= PosInViewSpace * ViewMtx_INVERSE;    // Second Mtx Mult

It turns out, I don’t need that. I can just multiply with ViewProjMtx_INVERSE and divide-by-w at the end, i.e.:

PosInWorldSpace0 = PosInPostClipSpace * ViewProjMtx_INVERSE;
PosInWorldSpace = PosInWorldSpace0 / PosInWorldSpace0.w;

This works because if you pay attention to ViewMtx_INVERSE, the fourth column is actually (0, 0, 0, 1) which basically doesn’t modify the w. That’s why you can do divide-by-w at the end and still get the correct result!

Feb22

C# (Empty) Method Stripping

When we develop games (or any apps really), we typically have at least two configurations: DEBUG and RELEASE. Furthermore, we usually add a bunch of debug code that should only be visible in DEBUG mode, but not in RELEASE (FINAL) mode.

I don’t know about you, but I am spoiled by C++ thinking that when we switch on the optimization, the compiler should strip empty method. However, having been in the game industry for a while, I have the mentality that we can’t really assume anything until we confirm it. So, I made a test creating an empty function and function with conditional attribute.

using System;
using System.Diagnostics;

namespace OptTest
{
    static class Debug
    {
        public static void EmptyFunction() { }

        [Conditional("DEBUG")]
        public static void DebugFunction()
        {
            Console.WriteLine("Debug Here");
        }
    }

    static class Program
    {
        static void Main(string[] args)
        {
            Debug.EmptyFunction();

            Debug.DebugFunction();
        }
    }
}

This is how the disassembly look like in DEBUG mode:

        static void Main(string[] args)
        {
00000000  mov         qword ptr [rsp+8],rcx
00000005  sub         rsp,28h
00000009  nop              
0000000a  mov         rax,7FF001B1DF8h
00000014  mov         eax,dword ptr [rax]
00000016  test        eax,eax
00000018  je          000000000000001F
0000001a  call        FFFFFFFFF9B384F0
0000001f  nop              
            Debug.EmptyFunction();
00000020  call        FFFFFFFFFFEC9A70
00000025  nop              

            Debug.DebugFunction();
00000026  call        FFFFFFFFFFEC9A78
0000002b  nop              
        }

Ok, everything works as expected in DEBUG mode, i.e. empty function and function with DEBUG conditional is not stripped. Let’s take a look the RELEASE mode assembly:

        static void Main(string[] args)
        {
            Debug.EmptyFunction();
00000000  mov         qword ptr [rsp+8],rcx
00000005  sub         rsp,28h
00000009  nop              
0000000a  mov         rax,7FF001C1DF8h
00000014  mov         eax,dword ptr [rax]
00000016  test        eax,eax
00000018  je          000000000000001F
0000001a  call        FFFFFFFFF9B28280
0000001f  call        FFFFFFFFFFEC9800   // Why is this still here???

            Debug.DebugFunction();
        }

To my surprise, C# compiler DOES NOT strip empty method!! Luckily, function with DEBUG conditional is stripped as expected. After further investigation, I found out that there are actually 2 compilers at work here: C# and JIT (Just-In-Time) compiler. C# compiler turns C# code to IL at compile time and JIT takes the IL and generates the native machine code at runtime. In addition, if you start your application from Visual Studio with the debugger attached (F5) then all the JIT optimizations will be disabled even if optimization is enabled.

In Writing High-Performance Managed Applications : A Primer, it explains how we can view the optimized JIT version of the code. After stepping through the code, it’s relieving to know that actually JIT strips out the empty method.

Jan17

C# Integer to String Builder

As many of you know, StringBuilder.Append(int) method creates a garbage. This is bad for XNA games that do this conversion every frame. In this article, I provide one implementation to convert int to string without creating garbage. I tried to be as efficient as possible; if you find better way to do this, please let me know.

public static class StringBuilderExtension
{
    private static char[] charToInt = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

    public static void Swap(this StringBuilder sb, int startIndex, int endIndex)
    {
        // Swap the integers
        Debug.Assert(endIndex >= startIndex);
        int count = (endIndex - startIndex + 1) / 2;
        for (int i = 0; i < count; ++i)
        {
            char temp = sb[startIndex + i];
            sb[startIndex + i] = sb[endIndex - i];
            sb[endIndex - i] = temp;
        }
    }

    public static void AppendNumber(this StringBuilder sb, int number)
    {
        // Save the current length as starting index
        int startIndex = sb.Length;

        // Handle negative
        bool isNegative;
        uint unumber;
        if (number < 0)
        {
            unumber = (uint)((number == int.MinValue) ? number : -number);
            isNegative = true;
        }
        else
        {
            unumber = (uint)number;
            isNegative = false;
        }

        // Convert
        do
        {
            sb.Append(charToInt[unumber % 10]);
            unumber /= 10;
        } while (unumber != 0);

        if (isNegative)
            sb.Append('-');

        sb.Swap(startIndex, sb.Length - 1);
    }

    public static void AppendNumber(this StringBuilder sb, uint unumber)
    {
        // Save the current length as starting index
        int startIndex = sb.Length;

        // Convert
        do
        {
            sb.Append(charToInt[unumber % 10]);
            unumber /= 10;
        } while (unumber != 0);

        sb.Swap(startIndex, sb.Length - 1);
    }
}

Jan17

Packing Data Format

During shader development, packing/unpacking from one format to another format is very common. Sometimes, the purpose is to support older graphics card and occasionally, it is more efficient to do so. Below are growing list of packing/unpacking methods in shader.

Packing Float to RGBA32

float4 packFloatToRGBA32(float f)
{
    const float4 pack = float4(1, 256, 65536, 16777216);
    return f * pack;
}

Unpacking RGBA32 to Float

float unpackRGBA32ToFloat(float4 rgba)
{
    const float4 unpack = float4(1.0f, 1.0f/256, 1.0f/65536, 1.0f/16777216);
    return dot(rgba, unpack);
}

Jan17

World, View and Projection Matrix Internals

This convention below is applicable to Direct3D and XNA matrices

World Matrix

Given a position and basis vectors right, up and look of an object, a world matrix can be formed by the following arrangement:

View Matrix

Given a position and basis vectors right, up and look of a viewer, a view matrix can be formed by the following arrangement:

Projection Matrix

Given field of view FOV, aspect ratio, near clip plane Zn and far clip plane Zf, a perspective projection matrix can be formed by the following arrangment:

Jan17

Median Filter Exploration

Background

One day, I was browsing through some concept arts and stopped at one stunning image. Basically, there’s “depth of field” on that image; however, it’s not the normal depth of field. Instead of blurred objects at far distance, you have “median filtered look” of objects at far distance. It led me to think: “hey, what about using median filter instead of gaussian filter?”

Implementing a trivial median filter has a big disadvantage that is it costs a lot more than gaussian filter. You need to sort the samples you take and look for the middle (median) value of that samples. Let say you take N samples, the fastest sorting algorithm is N log N (Of course, in this case I don’t include bucket/radix sort). Remember, we need to do this in GPU, so a complex algorithm like quick sort/merge sort/heap sort is out of question. You probably ended up with N*N sorting algorithm.

Pseudo Median Filter

As always, I googled to find an answer. I found this “Pseudo Median Filter” that’s faster than Median Filter and tries to mimic the original median filter effect. I found this from a forum in http://www.razyboard.com/system/morethread-cartoon-glsl-shader-pete_bernert-266904-2751605-0.html.

Basically, the algorithm is like this:

c00 c01 c02
c10 c11 c12
c20 c21 c22

Assuming the current pixel is c11, take the c11,c10,c12,c01,c21 colors and then re-calculate c11:

float3 mx = max( max(c10,c12), max(c01,c21) );
float3 mn = min( min(c10,c12), min(c01,c21) );
c11 = (c11+c10+c12+c01+c21-mx-mn)/3.0;

That yields the following result:

Pseudo Median Filter – Before Pseudo Median Filter – After
Psuedo Median Filter - Before Psuedo Median Filter - After

To me, it doesn’t look good enough. First, it looks more like a blur than a median filter. What I’m looking for is the “abstraction” of image when I apply median filter. This algorithm is no good; let’s move on.

Fast, Small Radius GPU Median Filter

My next research is to implement the “real” median filter. However, I’m not going to code the median filter; I’ll just google it. I found this page: http://graphics.cs.williams.edu/papers/MedianShaderX6/. I took their 5×5 median filter code, and here’s the result and comparison with gaussian blur.

Original What I Want (Photoshop Median w/ Radius = 4)
Original What I Want
Median Filter Gaussian Blur
Median Filter Gaussian Blur

And Yes! This is close to what I want. There are two defects:

  1. It’s quite slow. I apply the filter 5 times.
  2. I probably need bigger kernel size than just 5×5 in order to get more abstraction

Jan16

Converting Quaternion to Euler Angle

Overview

Conceptually, there are many ways to represent rotation in 3D game programming, the most common being QuaternionEuler AngleMatrix and Axis Angle. A lot of resources can be found on the web on each representation.

However, there are not so many “concrete” implementation on how to convert from quaternion to euler angle. This article will focus solely on this matter. It will discuss on what you need to know and give a working example code in XNA.

Convention

One problem in Euler angle is there are possibly more than one way to represent a rotation. Euler angle can be defined as three numbers (ex, ey, ez) whereby each number represent a rotation relative to its axis.

Problem arises when we need to construct a rotation matrix based on the Euler angle. We can construct a rotation matrix of an axis, i.e.:

XNA RotationX Matrix XNA RotationY Matrix XNA RotationZ Matrix

Derivation

To create a single rotation matrix, we need to know the order of multiplication. In XNA, the order is Z-X-Y, so the rotation matrix will be:

image
image
image
image

Your engine may adopt a different convention; thus it will lead to a different result.

From, the result above, we can get ex:

image

also ey:

image

and finally ez:

image

Using .NET reflection, we can know how XNA derive matrix from quaternion Q=(qx,qy,qz,qw) and thus we have all the information we need:

image
image
image
image
image

and finally, we can get the euler angle ex, ey, ez:

image
image
image

Special Case

There is a problem when ex=90 or ex=-90degree. Since cos(ex) will be 0, so M12 = M22 = M31 = M33 = 0 and yields ey and ez undefined. To handle this, let see how XNA converts Euler Angle to Quaternion:

image

When ex=90:

image

it yields

image

If we choose ez=0, then we get ey = 2 * atan2(qy, qw)

Similarly, when ex=-90:

image

it yields

image

If we choose ez=0, then we get ey = 2 * atan2(qy, qw).

Implementation So Far

Based on the theory above, we can write a function to convert from Quaternion to Euler Angle. This method guarantees if you transform point P to P’ by using quaternion Q, you can also apply rotation using euler angle E to transform P to P’.

(NOTE: This method does not guarantee that EulerToQuaternion(E) = Q).

public static Vector3 QuaternionToEuler2(Quaternion q)
{
    Vector3 euler;

    float sqx = q.X * q.X;
    float sqy = q.Y * q.Y;
    float sqz = q.Z * q.Z;
    float sqw = q.W * q.W;

    float unit = sqx + sqy + sqz + sqw;
    float test = (q.X * q.W - q.Y * q.Z);

    // Handle singularity
    if (test > 0.4999999f * unit)
    {
        euler.X = MathHelper.PiOver2;
        euler.Y = 2.0f * (float)System.Math.Atan2(q.Y, q.W);
        euler.Z = 0;
    }
    else if (test < -0.4999999f * unit)
    {
        euler.X = -MathHelper.PiOver2;
        euler.Y = 2.0f * (float)System.Math.Atan2(q.Y, q.W);
        euler.Z = 0;
    }
    else
    {
        float ey_Y = 2 * (q.X * q.Z + q.Y * q.W);
        float ey_X = 1 - 2 * (sqy + sqx);
        float ez_Y = 2 * (q.X * q.Y + q.Z * q.W);
        float ez_X = 1 - 2 * (sqx + sqz);
        euler.X = (float)System.Math.Asin(2 * test);
        euler.Y = (float)System.Math.Atan2(ey_Y, ey_X);
        euler.Z = (float)System.Math.Atan2(ez_Y, ez_X);
    }

    // Convert to degrees
    euler.X = MathHelper.ToDegrees(euler.X);
    euler.Y = MathHelper.ToDegrees(euler.Y);
    euler.Z = MathHelper.ToDegrees(euler.Z);

    return euler;
}

Antipodal Quaternion

As I have mentioned above, the Euler angle E obtained by the method above does not guarantee that converting it back to quaternion will yield Q. Using the method above, it may yield its antipodal, i.e. -Q. It is important to note that Antipodal quaternions, Q and −Q, represent the same rotation.

Thus we need some way to ensure property EulerToQuaternionQuaternionToEuler(Q) ) = Q. Unfortunately, I don’t know a good way to do this. I found a workaround by trying to add/subtract 360 from the Euler angle. If you find a better way, I would be happy to update this posting.

public static Vector3 QuaternionToEuler(Quaternion q)
{
    Vector3 euler;

    float sqx = q.X * q.X;
    float sqy = q.Y * q.Y;
    float sqz = q.Z * q.Z;
    float sqw = q.W * q.W;

    float unit = sqx + sqy + sqz + sqw;
    float test = (q.X * q.W - q.Y * q.Z);

    // Handle singularity
    if (test > 0.4999999f * unit)
    {
        euler.X = MathHelper.PiOver2;
        euler.Y = 2.0f * (float)System.Math.Atan2(q.Y, q.W);
        euler.Z = 0;
    }
    else if (test < -0.4999999f * unit)
    {
        euler.X = -MathHelper.PiOver2;
        euler.Y = 2.0f * (float)System.Math.Atan2(q.Y, q.W);
        euler.Z = 0;
    }
    else
    {
        float ey_Y = 2 * (q.X * q.Z + q.Y * q.W);
        float ey_X = 1 - 2 * (sqy + sqx);
        float ez_Y = 2 * (q.X * q.Y + q.Z * q.W);
        float ez_X = 1 - 2 * (sqx + sqz);
        euler.X = (float)System.Math.Asin(2 * test);
        euler.Y = (float)System.Math.Atan2(ey_Y, ey_X);
        euler.Z = (float)System.Math.Atan2(ez_Y, ez_X);
    }

    Quaternion qNeg = -q;
    Quaternion qTest;
    Quaternion.CreateFromYawPitchRoll(euler.Y, euler.X, euler.Z, out qTest);
    if (ExMath.Equals(ref qNeg, ref qTest))
    {
        if (euler.X < 0)
            euler.X += TwoPi;
        else
            euler.X -= TwoPi;

        Quaternion.CreateFromYawPitchRoll(euler.Y, euler.X, euler.Z, out qTest);
        if (ExMath.Equals(ref qNeg, ref qTest))
        {
            if (euler.Y < 0)
                euler.Y += TwoPi;
            else
                euler.Y -= TwoPi;
        }
    }

    // Convert to degrees
    euler.X = MathHelper.ToDegrees(euler.X);
    euler.Y = MathHelper.ToDegrees(euler.Y);
    euler.Z = MathHelper.ToDegrees(euler.Z);

    return euler;
}

Final Note

As a final note, the code above uses ExMath.Equals(ref Quaternion a, ref Quaternion b) which compares quaternion components with some epsilon:

public static bool Equals(ref Quaternion a, ref Quaternion b)
{
    return ((System.Math.Abs(a.X - b.X) < ExMath.Epsilon) &&
              (System.Math.Abs(a.Y - b.Y) < ExMath.Epsilon) &&
              (System.Math.Abs(a.Z - b.Z) < ExMath.Epsilon) &&
              (System.Math.Abs(a.W - b.W) < ExMath.Epsilon));
}

Jan16

The Gaussian Equation

The Equation

I believe you all have seen the famous 1D gaussian equation:

1D Gaussian Equation

Although for me it’s still a little bit cryptic. Basically, the function accepts 2 parameters:

  1. t is your data input
  2. sigma is the user controllable parameter

To understand this, pick a number for sigma and plot the graph, whereby t is the x-axis, and the function result is the y-axis.

1D Gaussian Equation Graph

Jan15

Hello TepNetwork!

Happy new year 2011! I know it’s a little bit too late but it’s better late than never right?

In this new year, I am unifying all (most) of my sites into TepNetwork. I am unifying all these websites:

  1. http://www.3dgametechnology.com
  2. http://wiki.3dgametechnology.com
  3. http://gsteph.blogspot.com

Although, I like to keep my “portfolio website” separate. So, I left http://stephanus.3dgametechnology.com as is. I will not be updating those website anymore. Unfortunately, I might lost some content from http://www.3dgametechnology.com because of some stupid mistake I made.

Anyway, this will be my main website, I hope you enjoy this site!

Jan15