Welcome, Guest. Please Login or Register.  • Help
SMF Underground
+ SHMUP-DEV » SHMUP DEV FORUMS » Assistance
|-+ Ugly bullet rendering artifacts

Pages: [1]   Go Down
0 Members and 1 Guest are viewing this topic. Topic Tools  
Read February 12, 2011, 01:40:01 PM #0
Tukun

Ugly bullet rendering artifacts

I didn't think I'd come back here again, but it looks like I still have some things to learn.
So far, I have a very good layout with everything. Memory is fine, framerate is always up and high, everything is dandy. But there's one little problem I can't fix no matter how I try to tackle it.
Quality.
For some reason, DirectX isn't mapping my bullets correctly. And even though I use the proper size and map everything correctly, it always ends up being distorted.
Here's what I mean. If any of you ever played it, Touhou's bullets quite bright and crystal clear. Every bullet is drawn pixel-to-pixel.
sample1
sample2
No matter where they are or what direction they're facing, it's always drawn perfectly. At first, I thought the distortion was a problem because of my bullets. But when I couldn't find the problem and decided to imitate the clearness using the bullets used by the Touhou game engine, here's what I got...
sample1
sample2

For some reason, it's never mapped pixel-to-pixel (or pixel-to-texel?). Increasing the resolution by upping the back buffer's width and height (and the size of the bullets along with it) lessens the problem, but never quite fixes it. And so here's my problem. Is there a way to directly map the bullets, so they don't get distorted? And for some reason, my algorithm to map the bullets's direction further distorts them from the original image. Unless it's facing 0, pi/2, pi, or 3pi/2, they get even more messy. Though this is the only means i have of making them point the right way. Here is the way I map them to the screen.
I changed some of my code so it's less lengthy and more readable.
Code:
float anng=D3DXToRadian(45);  float anngd=D3DXToRadian(135);
////I use the extra angles to add with the direction of the bullet to direct where
////the vertices will be drawn.
////adding/subtracting 45 degrees to the front and 135 to the back.
///because I'm using a circle to draw them out, they become a tad smaller. I use this
///to balance the difference ratio.

float xpos=bullets[i].xposition;
float ypos=bullets[i].yposition;
float halfs=bullets[i].imgdata.half; ///half of the height and width of that bullet.
float sizefix=sqrt(2.0); ///-
///because I'm using a circle to draw them out, they become a tad smaller. I use this
///to balance the difference ratio.
float uvLEFT=bullets[i].data.uvLEFTENDX;
float uvRIGHT=bullets[i].data.uvRIGHTENDX;
float uvTOP=bullets[i].data.uvTOPENDY;
float uvBOTTOM=bullets[i].data.BOTTOMENDY;
float dir=bullets[i].direction;
DWORD color=D3DCOLOR_ARGB(255,255,255,255);

///top left triangle
vertices2D[vertexcount+0]VERTEX2D(xpos+halfs*sizefix*cos(dir-anng,ypos+halfs*sizefix*sin(dir-anng),0,1,color,uvLEFT,uvTOP);
vertices2D[vertexcount+1]VERTEX2D(xpos+halfs*sizefix*cos(dir+anng,ypos+halfs*sizefix*sin(dir+anng),0,1,color,uvRIGHT,uvTOP);
vertices2D[vertexcount+2]VERTEX2D(xpos+halfs*sizefix*cos(dir-anngd,ypos+halfs*sizefix*sin(dir-anngd),0,1,color,uvLEFT,uvBOTTOM);

///bottom right triangle
vertices2D[vertexcount+3]VERTEX2D(xpos+halfs*sizefix*cos(dir-anngd,ypos+halfs*sizefix*sin(dir-anngd),0,1,color,uvLEFT,uvBOTTOM);
vertices2D[vertexcount+4]VERTEX2D(xpos+halfs*sizefix*cos(dir+anng,ypos+halfs*sizefix*sin(dir+anng),0,1,color,uvRIGHT,uvTOP);
vertices2D[vertexcount+5]VERTEX2D(xpos+halfs*sizefix*cos(dir+anngd,ypos+halfs*sizefix*sin(dir+anngd),0,1,color,uvRIGHT,uvBOTTOM);

vertexcount+=6;
///

And this is the flexible vertex format I'm using.
Code:
CUSTOM2DFVF D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1
struct VERTEX2D{

float x,y,z,rhw;
DWORD color;
float U, V;
VERTEX2D();
VERTEX2D(float nx, float ny, float nz, float nrhw, DWORD ncolor, float nU, float nV);

};

I know my mapping is perfect, the size of the bullets are the same. What's causing this distortion?
For the curious, here is the bullet sheet used by both the game and the one I used to for the test.

EDIT:@Hornet600S I need to rotate the triangles to get the bullet pointing in the right direction. If I wanted missles or knives instead of round bullets, then they'd all face the same direction no matter which direction they're fired at or going toward. That's why I use sin/cos to rotate them about a circle.
EDIT::Thanks. It helped alot, but the problem persists. The pixels stay in place now, but for some reason they now blend together with whatever is behind it. The true color of these bullets is pure red.
EDIT:::I took a look at what I could find, but it didn't work for me. I tried everything. decreasing the uv coordinates by half, decreasing the xy vertex coordinates by half, using a math function to floor the vertices and then decrease the coordinates by half. No dice. As long as the bullet is moving, there's always going to be some kind of color-soothing, and this gets very annoying, especially when I want certain pixels to stand out- like the transparency behind the etama bullets I posted above. The soothing makes it look blurry, which I hate with a passion.
If someone can take the time to make that single bullet to move and rasterize perfectly so it never "blends", and show me how they do it, I'd really appreciate it. I've been trying to do this all day for the past two days.
« Last Edit: February 12, 2011, 06:40:09 PM by Tukun »
Offline  
Read February 12, 2011, 02:43:42 PM #1
Hornet600S

Ugly bullet rendering artifacts

@Tukun
From what I see you are rotating your bullet-triangles. Why do you do that? It's a round bullet picture anyway, why rotate a circle? If you rotate such a texture it will naturally map not-so-well on the screen as if you leave it unrotated.
Just remove all this sin/cos stuff in your triangle-creation-code for your round bullets.

EDIT:
Quote
I need to rotate the triangles to get the bullet pointing in the right direction.
Yes, but don't do that with round bullets. Make a special case for that or add a flag to your bullet data to be able to draw bullets without rotation. I'm pretty positive this will fix your issue.
And as a side-effect: removing those trig-functions for bullets-that-dont-need-rotation will speed up your code.

EDIT2:
Quote
they now blend together with whatever is behind it. The true color of these bullets is pure red
That's normal - and a different "problem". That happens if you draw polygons "between the lines". If the GPU is fed with coordinates that after projecting to the screen result in pixels that have no "exact" screen-coordinate like x=10, y=20 but instead x=10.3, y=20.7. Then the GPU will distribute the color to more than one pixel on the screen.

If you really want to avoid that you could for example setup an orthographic view in screen-coordinates and take care that your coordinates are always rounded before sending them to the GPU (note: there are many other ways to get that result, but that would need too much typing Wink search for "pixel-perfect directx" or similar).

Usually you shouldn't care: that "color-smoothing" has its positive sides: you can move your bullets much smoother by using sub-pixels.

Btw.: you probably should also increase the texture resolution of you bullets, so you don't see the pixels that much. All those GPU side-effects are much more noticable with very low-res textures.
« Last Edit: February 14, 2011, 07:02:08 AM by Hornet600S »

"When the Amiga came out, everyone at Apple was scared as hell."
(Jean-Louis Gassée - Head of Macintosh development at Apple)
Offline  
Read February 13, 2011, 04:00:57 PM #2
kdmiller3

Re: Ugly bullet rendering artifacts

In addition to aligning your bullets with the screen and quantizing them to integer values, apply a half-pixel shift (-0.5, -0.5) to line up texture samples with screen pixels.  That will make them sharp and clear even with MSAA turned on.  Smiley
Offline  
Read February 13, 2011, 06:55:36 PM #3
Tukun

Re: Ugly bullet rendering artifacts

In addition to aligning your bullets with the screen and quantizing them to integer values, apply a half-pixel shift (-0.5, -0.5) to line up texture samples with screen pixels.  That will make them sharp and clear even with MSAA turned on.  Smiley

What good does it do to use decimals with integer values? I've tried using a math function to floor the float type and adding (-0.5,-0.5), but it didn't seem to do much good. I've done even more looking around the web, and found out about the adjustwindowrect() function to fix it. This gave me much better results. I'm satisfied with it.
sample

Though it does fix the round bullets which always point one direction, it makes a new problem- the bullets that face a direction.
sample
I use an algorithm to draw the vertices about a circle in the X/Y coordinates on the screen. The angle I use is the angle offset of the vertex from the bullet's direction. For example, if the bullet is facing up, I'd make the upper-left vertex like so...
Code:
bullet.xpos+bullet.halfsize*cos(bullet.direction+ToRadian(-45))*sqrt(2),
bullet.ypos+bullet.halfsize*sin(bullet.direction+ToRadian(-45))*sqrt(2),
bullet.data.uvLEFT,
bullet.data.uvTOP)
This works perfectly fine and pixel-perfect for bullets that are facing straight up, down, left, or right. But for all of the bullet in-between, like those around 45degrees, not so much. I'm ususally very much against using filters because they make things look blurry, especially small things like bullets. What would be the best way to tackle this problem? Is it unavoidable? I know using filters requires me to make another DrawPrimitive function, and there's the other case that I have to change my blending properties, which would require me to make another DrawPrimitive, all in the same frame. What can I do?
« Last Edit: February 13, 2011, 07:03:18 PM by Tukun »
Offline  
Read February 14, 2011, 07:00:35 AM #4
Hornet600S

Re: Ugly bullet rendering artifacts

Quote
What good does it do to use decimals with integer values?
Think of a pixel being a square with its own size. If you send a plain integer value to the GPU it will probably (depending on your matrix setup) put the emphasis on one of the pixel's corners. By adding/subtracting 0.5 as kdmiller3 said you essentially tell the GPU to target the pixel's center.

Though you shouldn't add that to every vertex but instead shift the world by 0.5 before drawing. That way you have to use fraction-less values for your vertices and all should be good.

Quote
Though it does fix the round bullets which always point one direction, it makes a new problem- the bullets that face a direction.

Now, that's a different problem:
it comes from your low-res texture being rotated. Just open your favorite painting-program, load that texture and rotate it. You will get ugly artefacts, especially when turning off all filtering.

The thing is: let's asume your bullet is 16x16 pixels on screen if drawn unrotated. And let's also asume that your texture is 16x16 pixels. Now if you rotate that thingy by 45 deg that quad spans more than 16 pixels at its widest point, namely about 23 pixels (sqrt(2)*16). So the GPU has no choice, it must stretch your image. And since 22 is no perfect multiple of 16 some pixels will be doubled, some not (or filtered if filtering is on).

You should increase your texture size to 32x32 and see what happens. And/or activate bilinear filtering.
You could also put some effort into creating a texture-atlas containing pre-rotated versions of your bullets, handcrafted like in the good old days, though that will of course limit you to a fixed number of degree-variants.
« Last Edit: February 14, 2011, 09:00:10 AM by Hornet600S »

"When the Amiga came out, everyone at Apple was scared as hell."
(Jean-Louis Gassée - Head of Macintosh development at Apple)
Offline  
Read February 14, 2011, 02:16:53 PM #5
Tukun

Re: Ugly bullet rendering artifacts

The thing is: let's asume your bullet is 16x16 pixels on screen if drawn unrotated. And let's also asume that your texture is 16x16 pixels. Now if you rotate that thingy by 45 deg that quad spans more than 16 pixels at its widest point, namely about 23 pixels (sqrt(2)*16). So the GPU has no choice, it must stretch your image. And since 22 is no perfect multiple of 16 some pixels will be doubled, some not (or filtered if filtering is on).

So that's what the cause of it is? Wow, that is annoying...
On a side note, thanks for the tip, making it larger certainly did help. I've taken the time to play with it quite a bit, and learned that I actually don't need to make it larger. I've learned that the linear filter doesn't work for textures that are already pixel-perfect, on the screen so keeping it on won't be a problem anymore.
But one other thing I've noticed. This is probably my last problem with bullets.
Z-buffers. I want the first bullets spawned behind the later bullets. But this is an easy problem to tackle I think. Anyway, thanks for the help.
Offline  
Read February 15, 2011, 09:19:41 AM #6
relsoft

Re: Ugly bullet rendering artifacts

The thing is: let's asume your bullet is 16x16 pixels on screen if drawn unrotated. And let's also asume that your texture is 16x16 pixels. Now if you rotate that thingy by 45 deg that quad spans more than 16 pixels at its widest point, namely about 23 pixels (sqrt(2)*16). So the GPU has no choice, it must stretch your image. And since 22 is no perfect multiple of 16 some pixels will be doubled, some not (or filtered if filtering is on).

So that's what the cause of it is? Wow, that is annoying...
On a side note, thanks for the tip, making it larger certainly did help. I've taken the time to play with it quite a bit, and learned that I actually don't need to make it larger. I've learned that the linear filter doesn't work for textures that are already pixel-perfect, on the screen so keeping it on won't be a problem anymore.
But one other thing I've noticed. This is probably my last problem with bullets.
Z-buffers. I want the first bullets spawned behind the later bullets. But this is an easy problem to tackle I think. Anyway, thanks for the help.

In OpenGL, you can just disable depth testing and call it a day. I'm pretty sure there is a d3d equivalent.

Your etama.png spritesheet won't work well with bilinear filtering on.  Some of the bullets are too close to each other that it would sometimes "bleed".



Hello
Offline  
Read February 15, 2011, 03:46:34 PM #7
kdmiller3

Re: Ugly bullet rendering artifacts

I was coming at this from a 3D renderer with a 2D overlay, so the half-pixel shift was a special-purpose operation.  If your whole game is 2D and pixel-aligned, then applying the shift in the camera transform works too.

Rotating the sprite polygon breaks the alignment between screen pixels and sprite texels so it looks blurry (with linear sampling) or blocky (with point sampling).  Pre-rotated bullet sprites let you keep perfect pixel alignment at the cost of a bit of texture space and artist time.  On the plus side, game developers have done it this way for eyars so you'll be in good company.  Smiley

If you want to imitate the scaling and rotation features of advanced sprite hardware like the Sega Saturn and ST-V, use point sampling.  Non-integer scale factors and rotation angles not divisible by 90 degrees will look strange so you'll want to save those for special effects and large objects that you can't afford to pre-rotate.
Offline  
Read February 15, 2011, 04:38:46 PM #8
kdmiller3

Re: Ugly bullet rendering artifacts

A good way to check that you have things right is to draw a 2x2 pixel sprite.  An off-by-one error in the texture coordinates or screen rectangle will be extremely obvious at that size.  Smiley

The most reliable way to generate your vertex positions is to quantize the upper-left corner position and then generate the other three by adding the integer width and height to it: (x, y), (x+w, y), (x+w, y+h), (x, y+h).  The same holds for the texture coordinates after dividing sprite width and height by the texture width and height.  (The rasterizer's top-left filling convention means your rightmost column and bottommost row need to be one past what you want to draw.  I've gotten burned by that before...)
« Last Edit: February 15, 2011, 04:44:46 PM by kdmiller3 »
Offline  
Pages: [1]   Go Up
Jump to:  

Page created in 0.16 seconds with 17 queries.