简体   繁体   中英

Pixel perfect rendering in XNA

I have a 2D game in XNA which has a scrolling camera. Unfortunately, when screen is moved, I can see some artifacts - mostly blur and additional lines on the screen.

I thought about changing coordinates before drawing (approximating with Ceiling() or Floor() consistently), but this seems a little inefficient. Is this the only way?

I use SpriteBatch for rendering.

This is my drawing method from Camera:

Vector2D works on doubles, Vector2 works on floats (used by XNA), Srpite is just a class with data for spriteBatch.Draw .

public void DrawSprite(Sprite toDraw)
{
    Vector2D drawingPostion;
    Vector2 drawingPos;
    drawingPostion = toDraw.Position - transform.Position;
    drawingPos.X = (float) drawingPostion.X*UnitToPixels;
    drawingPos.Y = (float) drawingPostion.Y*UnitToPixels;

    spriteBatch.Draw(toDraw.Texture, drawingPos, toDraw.Source, toDraw.Color,
        toDraw.Rotation, toDraw.Origin, toDraw.Scale, toDraw.Effects, toDraw.LayerDepth + zsortingValue);
}

My idea is to do this:

drawingPos.X = (float) Math.Floor(drawingPostion.X*UnitToPixels);
drawingPos.Y = (float) Math.Floor(drawingPostion.Y*UnitToPixels);

And it solves the problem. I think I can accept it this way. But are there any other options?

GraphicsDevice.SamplerStates[0] = SamplerState.PointWrap; 

This isn't so much a problem with your camera as it is the sampler. Using a Point Sampler state tells the video card to take a single point color sample directly from the texture depending on the position. Other default modes like LinearWrap and LinearClamp will interpolate between texels (pixels on your source texture) and give it a very mushy, blurred look. If you're going for pixel-graphics, you need Point sampling.

With linear interpolation, if you have red and white next to each other in your texture, and it samples between the two (by some aspect of the camera), you will get pink. With point sampling, you get either red or white. Nothing in between.

Yes it is possible... try something this...

bool redrawSprite = false;
Sprite toDraw;

void MainRenderer()
{
   if (redrawSprite)
   {
      DrawSprite(toDraw);
      redrawSprite = false;
   }
}

void ManualRefresh()
{
   "Create or set your sprite and set it to 'toDraw'"
   redrawSprite = true;
}

This way you will let main loop do the work like is intended.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM