Geeks With Blogs
Johnny Kauffman Deriding bad software so you don't have to!

Summary

I ran into a visual issue using DirectX (in C# via SlimDX) in which the texture filtering was not aligning properly. This is difficult to describe in words, so read the fully explanation below. The solution is pretty simple, so I decided to post about it in hopes that it is use to another DirectX neophyte in the future.

 

The Problem

Like most normal people, in my spare time I work on an open-source emulator for the long-lost 3DO multiplayer video game system (see fourdo.com for all your 3DO emulation needs!).

The emulator’s user interface  uses Windows Forms (WinForms), and the first revisions of the emulator were just doing a simple blit to the screen using ((Graphics)g).DrawImage. This was unnecessary drain on the CPU, which is the key resource that make emulators thrive! Thus, at some point I enabled DirectX rendering which would draw the bitmaps to the screen instead, pushing that drawing operation onto the GPU’s shoulders. This was just done using two triangles via a trianglestrip, and a single texture for the screen’s image

Worked great! However, when using nearest-point sampling (a.k.a. Nearest Neighbor, or “None”) for image stretching, there was an oddity down the diagonal / hypotenuse of the polygons. To clarify, I have some sample images.

 

Happy UnHappy UnHappy_Visual

Original

After Nearest-Point

(glitch visualized)

What happened to this man? Well, Nearest Point filtering has shifted the bottom portion of his body causing a collapsed lung, paralysis, and slight indigestion.

The Explanation

This is due to floating point inaccuracies with the rasterization and texture mapping. Linear interpolation (smooth scaling) is not subject to these inaccuracies.  Microsoft has a good explanation of the cause and pushes you in the right direction:

http://msdn.microsoft.com/en-us/library/windows/desktop/bb147229(v=vs.85).aspx

The most obvious solution is to just not use Nearset-Point sampling. Generally everything uses at least linear interpolation; nobody would play a game these days without it. However, to the retro gaming goons like myself, these problems of olde bubble back to the surface. Sometimes we genuinely want those ugly sharp edged pixels!

The Solution

The previously-linked article suggests the following:

When you must use it, it is recommended that you offset texture coordinates slightly from the boundary positions to avoid artifacts.

To accomplish this, I first split my full-screen triangle strip into two literal triangle, and shifted the texture mapping in the second triangle. I was careful to make the shift amount less than the amount necessary to shift my image by a full pixel. I decided to shift about 10% a pixel, and my native image is always 1024 x 512. 1 / 1024 / 10 = 0.0001

vertexStream.WriteRange(new[]{
    new TexturedVertex(new Vector3(-1.0f, 1.0f, 0.0f),
        new Vector2(0.0f,       0.0f))
    ,new TexturedVertex(new Vector3( 1.0f,-1.0f, 0.0f),
        new Vector2(maximumX/2, maximumY/2))
    ,new TexturedVertex(new Vector3(-1.0f,-1.0f, 0.0f),
        new Vector2(0.0f,       maximumY/2))

    ,new TexturedVertex(new Vector3( 1.0f,-1.0f, 0.0f),
        new Vector2(maximumX/2 - .0001f, maximumY/2 + .0001f))
    ,new TexturedVertex(new Vector3(-1.0f, 1.0f, 0.0f),
        new Vector2(0.0f       - .0001f, 0          + .0001f))
    ,new TexturedVertex(new Vector3( 1.0f, 1.0f, 0.0f),
        new Vector2(maximumX/2 - .0001f, 0          + .0001f))
    });

This was enough to ensure that the texture mapping in the second polygon was not misaligned.

Posted on Monday, February 20, 2012 9:55 AM | Back to top


Comments on this post: A “near miss” using DirectX’s Nearest-Point Sampling

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © jkauffman | Powered by: GeeksWithBlogs.net