【问题标题】:Java 2D Rendering Ripple ArtifactsJava 2D 渲染波纹工件
【发布时间】:2013-08-16 11:59:15
【问题描述】:

我正在使用 Java 开发一个等距 2D 游戏,我注意到屏幕上有一个网格线,渲染似乎水平和垂直重复一个像素。这是一个屏幕截图来说明我的意思:

我检查了我的 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( );

Screen 类 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;
    }
}

【问题讨论】:

    标签: java graphics 2d


    【解决方案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_WIDTHintCANVAS_HEIGHT。当您绘制图形时,它会放大它。它不使用任何类型的插值进行缩放,只是从源中选择最近的像素;因此您会定期看到重复的行或列。

    您在检查源数据时看不到这一点,因为它不存在于源数据中,它是呈现数据时在输出中引入的工件。

    打印出图像和面板尺寸,您会发现差异。从我看到的重复行数来看(我看到 10 个水平和 10 个垂直),我猜你会发现 getWidth()intCANVAS_WIDTH 多 10 个,高度也一样。

    您可以改为将m_imgImage 的尺寸传递给.drawImage()。这将消除伪影,但会在右侧和底部留下空隙,因为图像小于组件。

    如果您的Graphics 实际上是Graphics2D,您可以将KEY_INTERPOLATION 渲染提示设置为在缩放时使用插值(它可能不遵守该提示):

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

    如果您确实希望准确绘制图像、不缩放且两侧没有间隙,请在主窗口上禁用调整大小并设置大小以匹配图像。

    【讨论】:

      猜你喜欢
      • 2019-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多