Drawing an image using sub-pixel level accuracy using Graphics2D

前端 未结 4 1311
北荒
北荒 2021-02-15 14:48

I am currently attempting to draw images on the screen at a regular rate like in a video game.

Unfortunately, because of the rate at which the image is moving, some fram

4条回答
  •  刺人心
    刺人心 (楼主)
    2021-02-15 15:22

    You can composite the image yourself using sub-pixel accuracy, but it's more work on your part. Simple bilinear interpolation should work well enough for a game. Below is psuedo-C++ code for doing it.

    Normally, to draw a sprite at location (a,b), you'd do something like this:

    for (x = a; x < a + sprite.width; x++)
    {
        for (y = b; y < b + sprite.height; y++)
        {
            *dstPixel = alphaBlend (*dstPixel, *spritePixel);
            dstPixel++;
            spritePixel++;
        }
        dstPixel += destLineDiff; // Move to start of next destination line
        spritePixel += spriteLineDiff; // Move to start of next sprite line
    }
    

    To do sub-pixel rendering, you do the same loop, but account for the sub-pixel offset like so:

    float xOffset = a - floor (a);
    float yOffset = b - floor (b);
    for (x = floor(a), spriteX = 0; x < floor(a) + sprite.width + 1; x++, spriteX++)
    {
        for (y = floor(b), spriteY = 0; y < floor (b) + sprite.height + 1; y++, spriteY++)
        {
            spriteInterp = bilinearInterp (sprite, spriteX + xOffset, spriteY + yOffset);
            *dstPixel = alphaBlend (*dstPixel, spriteInterp);
            dstPixel++;
            spritePixel++;
        }
        dstPixel += destLineDiff; // Move to start of next destination line
        spritePixel += spriteLineDiff; // Move to start of next sprite line
    }
    

    The bilinearInterp() function would look something like this:

    Pixel bilinearInterp (Sprite* sprite, float x, float y)
    {
        // Interpolate the upper row of pixels
        Pixel* topPtr = sprite->dataPtr + ((floor (y) + 1) * sprite->rowBytes) + floor(x) * sizeof (Pixel);
        Pixel* bottomPtr = sprite->dataPtr + (floor (y) * sprite->rowBytes) + floor (x) * sizeof (Pixel);
    
        float xOffset = x - floor (x);
        float yOffset = y - floor (y);
    
        Pixel top = *topPtr + ((*(topPtr + 1) - *topPtr) * xOffset;
        Pixel bottom = *bottomPtr + ((*(bottomPtr + 1) - *bottomPtr) * xOffset;
        return bottom + (top - bottom) * yOffset;
    }
    

    This should use no additional memory, but will take additional time to render.

提交回复
热议问题