Java 2D-рендеринг Ripple Артефакты

Я работаю над изометрической 2D-игрой на Java и заметил, что на экране есть сетка из линий, где рендеринг, кажется, повторяет пиксель по горизонтали и вертикали. Вот скриншот, чтобы показать, что я имею в виду:

Скриншот

Я проверил цикл в своем методе Render и сравнил значение цвета каждого пикселя с предыдущим значением в массиве, чтобы увидеть, есть ли в строке два черных пикселя, и таких случаев не обнаружено. Я в недоумении, что может быть причиной такого эффекта. Что я могу сделать, чтобы исправить это? Вот соответствующий код:

Переменные класса игры:

private BufferedImage m_imgImage = new BufferedImage( intCANVAS_WIDTH, intCANVAS_HEIGHT, BufferedImage.TYPE_INT_RGB );
private int[ ] m_aintPixels = ( ( DataBufferInt ) m_imgImage.getRaster( ).getDataBuffer( ) ).getData( );

Метод рендеринга игрового класса:

// Object to organize data on the canvas
BufferStrategy bfsBufferStrategy = getBufferStrategy( );

if( bfsBufferStrategy == null )
{
    createBufferStrategy( 3 );
    return;
}

for( int intY = 0; intY < intCANVAS_HEIGHT; intY += 1 )
{
    for( int intX = 0; intX < intCANVAS_WIDTH; intX += 1 )
    {
        m_aintPixels[ intX + ( intY * intCANVAS_WIDTH ) ] = m_Screen.m_aintPixels[ intX + ( intY * m_Screen.m_intWidth ) ];
    }
}

Graphics gfxGraphics = bfsBufferStrategy.getDrawGraphics( );
gfxGraphics.drawImage( m_imgImage, 0, 0, getWidth( ), getHeight( ), null );


gfxGraphics.dispose( );
bfsBufferStrategy.show( );

Метод Render класса экрана для заполнения массива пикселей:

// Render a tile with the specified tile ID
public void RenderTile( int intPositionX, int intPositionY, CSpriteSheet SpriteSheet, int intTileID )
{

    int intPixelIndex = 0;
    int intSheetX = 0;
    int intSheetY = 0;
    int intTileOffsetX = 0;
    int intTileOffsetY = 0;
    int intPixelColor = 0;

    // Center the Tile
    intPositionX -= m_intOffsetX;
    intPositionY -= m_intOffsetY;

    intSheetX = ( intTileID % SpriteSheet.m_intTileColumns ) * CTile.TILE_WIDTH;
    intSheetY = ( intTileID / SpriteSheet.m_intTileRows ) * CTile.TILE_HEIGHT;

    intPixelIndex = intPositionX + ( intPositionY * m_intWidth );

    // Rows
    for( int intTileRow = intSheetY; intTileRow != ( intSheetY + CTile.TILE_HEIGHT ); intTileRow += 1 )
    {
        // Columns
        for( int intTileColumn = intSheetX; intTileColumn != ( intSheetX + CTile.TILE_WIDTH ); intTileColumn += 1 )
        {
            intPixelColor = SpriteSheet.m_aintPixels[ intTileColumn + ( intTileRow * m_SpriteSheet.m_intWidth ) ];

            // Boundary checking
            if( intPositionX + intTileOffsetX >= 0 && intPositionX + intTileOffsetX < m_intWidth &&
            intPositionY + intTileOffsetY >= 0 && intPositionY + intTileOffsetY < m_intHeight &&
            CColor.Transparent( intPixelColor ) == false )
            {

                m_aintPixels[ intPixelIndex ] = SpriteSheet.m_aintPixels[ intTileColumn + ( intTileRow * m_SpriteSheet.m_intWidth ) ];
            }

            // Increment
            intTileOffsetX += 1;
            intPixelIndex += 1;
        }

        // Increment
        intTileOffsetY += 1;
        intPixelIndex += m_intWidth - ( CTile.TILE_WIDTH );
        intTileOffsetX = 0;
    }
}

person Joe Boris    schedule 16.08.2013    source источник


Ответы (1)


Это классический артефакт неинтерполированного масштабирования. У вас есть:

private BufferedImage m_imgImage = new BufferedImage( intCANVAS_WIDTH, intCANVAS_HEIGHT, BufferedImage.TYPE_INT_RGB );
...
gfxGraphics.drawImage( m_imgImage, 0, 0, getWidth( ), getHeight( ), null );

Эффект, который вы видите, заключается в том, что getWidth() и getHeight() немного больше, чем intCANVAS_WIDTH и intCANVAS_HEIGHT. Когда вы рисуете графику, она масштабируется в большем размере. Он не использует какую-либо интерполяцию для масштабирования, просто выбирает ближайший пиксель из источника; поэтому вы видите повторяющиеся строки или столбцы через равные промежутки времени.

Вы не видите этого при проверке исходных данных, потому что его нет в ваших исходных данных, это артефакт, представленный в выводе при визуализации данных.

Распечатайте изображение и размеры панели, и вы увидите разницу. Судя по количеству повторяющихся строк, которые я вижу (я вижу 10 горизонтальных и 10 вертикальных), я думаю, вы обнаружите, что getWidth() на 10 больше, чем intCANVAS_WIDTH, и то же самое по высоте.

Вместо этого вы можете передать размеры от m_imgImage до .drawImage(). Это избавит от артефакта, но оставит зазор справа и снизу, так как изображение меньше, чем компонент.

Если ваш Graphics на самом деле является Graphics2D, вы можете установить KEY_INTERPOLATION подсказка рендеринга для использования интерполяции при масштабировании (он может не подчиняться этой подсказке):

Graphics2D g = (Graphics2D)gfxGraphics;
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

Если вы действительно хотите, чтобы изображение отрисовывалось ровно, без масштабирования и без зазоров по бокам, то отключите изменение размера в главном окне и установите размер, соответствующий изображению.

person Jason C    schedule 16.08.2013