Skip to main content
GameDev.net gamedev.net
🔒 Locked

Blurry Texture

Started by schupf May 19, 2012 at 9:48 AM 12 replies 4.8k views
Original Post
schupf
schupf
Hello!

In my DirectX 9 application I want to render an UI button per textured quad. So I created a button texture of size 250x40 that looks like this:
1so3dj.png

I load the texture with this D3DX function:

HRESULT hr = D3DXCreateTextureFromFileEx(mRenderSystem->getDevice(),
"NewGameTex.png",
250, 40,
D3DX_DEFAULT, // Mip levels
0, // Usage
D3DFMT_UNKNOWN, // Format
D3DPOOL_MANAGED, // Pool
D3DX_DEFAULT, D3DX_DEFAULT, // Filter, Mip filter
0, NULL, NULL,
&mD3D9Texture);

I load the texture with its original size and create 8 mip maps (even though I do not use mip mapping).

Then I create a quad consisting of 4 vertices. I define the coordinates of the 4 vertices in screen space (i.e. (200, 100)), subtract 0.5 from both of them (cause of the DX9 texel offset) and convert them to Normalized Device Coordinates in [-1,1]

Finally I render the quad with activated Alpha Blending, Min and Mag Filter = Linear and Mip Filter = Point. The rendering result looks like this:
2ag13yh.jpg
As you can see the texture looks blurrier as in the original texture (especially the edge of the text looks blurry).

Do you have an idea why it looks so blurry and how I could fix it?

Thanks!
d h k
d h k
I've experienced the same with non power-of-two textures, try turning it into one.

Also you probably shouldn't create a mip map chain if you're not making use of it, pass 1 instead of D3DX_DEFAULT to disable mip map creation entirely!

Sounds like you're doing everything else (filters etc.) correctly.

Hope this helps!
schupf
schupf
Thanks for your answer! I changed mip map creation to 1 and increased the canvas of the texture from 250x40 to 256x256: I did not change anything. The texture is still blurry. What else could be the problem?
Will linear filtering for Min and Mag ALWAYS make the texture blurry, even if the screen space size of the polygon is exactly the same size as the texture?
d h k
d h k
I just went through the source of one of my projects where (as I mentioned) was facing the same problem and I used D3DSAMP_MINFILTER: D3DTEXF_POINT and D3DSAMP_MAGFILTER: D3DTEXF_POINT.

That gives me zero blurriness whatsoever!

EDIT: When you say you changed the the canvas, you're speaking in Photoshop terms meaning your button is still actually as big as it was before but you added transparent space around it to fill the power-of-two area? In that case I assume you remembered to change the size of the quad that you're drawing to the power-of-two dimensions? Just asking!
schupf
schupf

I just went through the source of one of my projects where (as I mentioned) was facing the same problem and I used D3DSAMP_MINFILTER: D3DTEXF_POINT and D3DSAMP_MAGFILTER: D3DTEXF_POINT.

That gives me zero blurriness whatsoever!

Thats true. But when I use Point Filter for Min and Mag Filter it still is not 100% the same as my original texture. This is the rendering result when I load as 250x40 (original size), no MipMapping and Point Filter for Min, Mag:
2zrgv9s.png
The texture is sharp now, but I can see a strange "blockyness" on the left edge of the letter "G". The rest looks fine. Why it doesn't look exactly like my original texture?


EDIT: When you say you changed the the canvas, you're speaking in Photoshop terms meaning your button is still actually as big as it was before but you added transparent space around it to fill the power-of-two area? In that case I assume you remembered to change the size of the quad that you're drawing to the power-of-two dimensions? Just asking! smile.png

Hehe, yes, thats why I used the term "Canvas" rather than "image size". The button area is still the same, I just increased the transparent area around the button to 256x256 (and also the quad size).

Is linear Min Mag filtering supposed to achieve such blurry results?
d h k
d h k
Looks correct to me except for the artifacts on the left side of the letter G, as you said. Could you post the code that sets up your projection matrix and the content of your vertex buffer (vertex position and uv coordinates)?
schupf
schupf
I have a standard projection matrix (nothing special there) and this is how I create the quad (Comments are in the code)

// Input = mTopLeftAbsPx = Top Left absolute Pixel position, i.e. (200, 100) and width and height of button quad
// The following 4 lines compute the 4 corner points in screen space.
Vec2u topLeft = mTopLeftAbsPx;
Vec2u topRight(topLeft.x + mWidthPx, topLeft.y);
Vec2u bottomRight(topRight.x, topRight.y + mHeightPx);
Vec2u bottomLeft(topLeft.x, topLeft.y + mHeightPx);

// Now I convert the 4 screen space positions to normalized device coordinates (the method is shown at the end)
Vec2 topLeftNDC = pixelToNDC(topLeft);
Vec2 topRightNDC = pixelToNDC(topRight);
Vec2 bottomRightNDC = pixelToNDC(bottomRight);
Vec2 bottomLeftNDC = pixelToNDC(bottomLeft);

// Finally I create my 4 vertices: Position are 4 dimensional homogeneous coordinates (ndcX, ndcY, 0, 1) and texture coordinates go from (0,0) (top left button corner)
// to (1,1) (bottom left)
VertexTransPosTex verts[] = {
{ Vec4(topLeftNDC.x, topLeftNDC.y, 0, 1), Vec2(0, 0) },
{ Vec4(topRightNDC.x, topRightNDC.y, 0, 1), Vec2(1, 0) },
{ Vec4(bottomRightNDC.x, bottomRightNDC.y, 0, 1), Vec2(1, 1) },
{ Vec4(bottomLeftNDC.x, bottomLeftNDC.y, 0, 1), Vec2(0, 1) },
};


// Code to transform from screen coordinate to NDC [-1,1]
Vec2 OverlayPanel::pixelToNDC(const Vec2u& pixelCoords) {
// Subtract (0.5, 0.5) because of texel/pixel boundary mismatch (half pixel offset)
Vec2 pixCoords = Vec2(pixelCoords.x, pixelCoords.y) - Vec2(0.5f, 0.5f);

float ndcX = static_cast<float>(pixCoords.x) / (mRootRenderTarget->getWidth() - 1); // Pixel => [0,1]
ndcX = 2 * ndcX - 1; // [0,1] => [-1,1]

float ndcY = static_cast<float>(pixCoords.y) / (mRootRenderTarget->getHeight() - 1); // Pixel => [0,1]
ndcY = -2 * ndcY + 1; // [0,1] => [-1,1] (axis swapped)

return Vec2(ndcX, ndcY);
}

Do you think there is an error in this code?
With point filtering I have a sharp texture but an ugly artifact at the "G" and with linear filtering I have no artifact but a blurry look
Hodgman
Hodgman
I don't think you need the "[font=courier new,courier,monospace]- 1[/font]"'s when dividing by RT size in [font=courier new,courier,monospace]pixelToNDC[/font]
d h k
d h k
I'm not quite sure why exactly you're doing all of this (that might very well be my ignorance, though), all I do is use D3DXMatrixOrthoLH to get an orthographic projection matrix as large as my resolution is, then I set up a world matrix for my button like this:


D3DXMATRIX t, s, world_matrix;
D3DXMatrixTranslation ( &t, 100.0f, 100.0f, 0.0f ); // have the buttons center be 100 units to the right and bottom away from the center of the screen
D3DXMatrixScaling ( &s, button_width / 2.0f, button_height / 2.0f, 1.0f );
world_matrix = s * t;
device->SetTransform ( D3DTS_WORLD, &world_matrix );


And then I render a unit size quad and that does the job. I don't know if it's an option for you to comment out that large portion of code you posted and simplify it in the manner I described here for testing purposes?

I can't really help you any further at this point, maybe somebody else can jump in!

EDIT: Hodgman to the rescue!
schupf
schupf

I don't think you need the "[font=courier new,courier,monospace]- 1[/font]"'s when dividing by RT size in [font=courier new,courier,monospace]pixelToNDC[/font]

Indeed, that fixed the artifact at the "G". Thanks! (Kinda strange though. For me it seems to be more logical to subtract -1, because when the window width is 600, the maximum coordinate is 599, thus 599/599 = 1. But 599/600 = 0,999. Hm....)

I am kinda shocked how bad the result is with Linear Filtering. Is it normal to use Point Filtering for HUD elements? I think its kinda unflexible. Sure, if my quad screen space size matches the texture size, everything is fine. But when I make the quad just slightly bigger (i.e. from 250x40 to 280x40), it will look bad).
I still would prefer linear filtering, but the bad results make it impossible. I still have the feeling I make something wrong...
Adam_42
Adam_42
You can avoid the need for point filtering by applying a half pixel offset as explained at http://msdn.microsoft.com/en-us/library/windows/desktop/bb219690%28v=vs.85%29.aspx

The need to do that goes away in DX10/11.
21st Century Moose
21st Century Moose
Half-pixel offset was already covered in the OP.
Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 
Madhed
Madhed
I think this is the problem you are having: http://drilian.com/2...-texel-offsets/
You have to make sure that one pixel maps exactly to the center of one texel all the time.
If I remember correctly they fixed this in later d3d versions.

Edit: oops! Should have payed more attention while reading the op
Hodgman
Hodgman
Indeed, that fixed the artifact at the "G". Thanks! (Kinda strange though. For me it seems to be more logical to subtract -1, because when the window width is 600, the maximum coordinate is 599, thus 599/599 = 1. But 599/600 = 0,999. Hm....)
If you visualise the pixels as squares, 0 is the left side of the leftmost pixel and 600 is the right side of the rightmost pixel. Your scale factor is the width of the whole grid, not the distance between the centres of the leftmost/rightmost pixels.
...I think..wink.png
I am kinda shocked how bad the result is with Linear Filtering. Is it normal to use Point Filtering for HUD elements? I think its kinda unflexible. Sure, if my quad screen space size matches the texture size, everything is fine. But when I make the quad just slightly bigger (i.e. from 250x40 to 280x40), it will look bad).[/quote]If your quads are lined up with screen-space pixels perfectly, and your quad sizes match your texture sizes, then point/linear filtering should give the exact same result.
If you're deliberately scaling elements, I'd definitely avoid point filtering.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.