在MonoGame中使用“Clamp”模式时看到“Wrap”纹理(图片incl)

时间:2016-01-06 06:11:25

标签: xna monogame spritebatch

我正在使用精灵批处理在我的MonoGame项目中渲染一个平铺地图。

以下是渲染代码:

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Black);

        SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, CameraManager.pInstance.pFinalTransform);

        foreach( TmxLayer Layer in mCurrentTileMap.Layers)
        {
            for (int y = 0; y < mCurrentTileMap.Height; y++)
            {
                for (int x = 0; x < mCurrentTileMap.Width; x++)
                {
                    TmxLayerTile Tile = Layer.Tiles[mCurrentTileMap.Width * y + x];
                    int TileID = -1;
                    Texture2D Texture = FindTileMapTextureForTileID(Tile.Gid, out TileID);
                    if (TileID > 0)
                    {
                        int atlasX = TileID % (Texture.Width / TileSize);
                        int atlasY = TileID / (Texture.Width / TileSize);

                        SpriteEffects FX = SpriteEffects.None;
                        if (Tile.HorizontalFlip)
                        {
                            FX = SpriteEffects.FlipHorizontally;
                        }

                        SpriteBatch.Draw(Texture, new Vector2(x * TileSize, y * TileSize), new Microsoft.Xna.Framework.Rectangle(atlasX * TileSize, atlasY * TileSize, TileSize, TileSize), Color.White, 0, Vector2.Zero, 1, FX, 0);
                    }
                }
            }
        }

以下是我认为重要的代码行:

SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, 
  null, null, null, CameraManager.pInstance.pFinalTransform);

SpriteBatch.Draw(Texture, new Vector2(x * TileSize, y * TileSize), 
  new Microsoft.Xna.Framework.Rectangle(atlasX * TileSize, atlasY * TileSize, TileSize, TileSize), 
  Color.White, 0, Vector2.Zero, 1, FX, 0);

如您所见,我正在使用SamplerState.PointClamp。然而,当我在世界各地移动时,我偶尔会看到这个类的东西;在某些瓷砖下方,您可以看到一行像素,即精灵地图集中位于其下方的像素。

Enlarge to see issue better 点击放大以清楚地看到问题......

我很确定这种情况正在发生,因为应用于sprite批处理(CameraManager.pInstance.pFinalTransform)的转换正在使用浮点运算。如果我强行将该变换的比例部分钳制为整数,则不会出现问题。然而,这样做会导致非常抖动的相机移动(我的游戏非常放大,因此每个像素在显示器上约为10个像素),因此这不是一个好的解决方案。

关于如何避免这种影响的任何想法?

以下是源纹理精灵表的外观,供参考。

enter image description here

1 个答案:

答案 0 :(得分:1)

  

我很确定这种情况正在发生,因为应用于sprite批处理的转换(CameraManager.pInstance.pFinalTransform)正在使用浮点运算。

是的,这听起来很对。当地图图块被相机缩放后,我们在MonoGame.Extended中编写了Tiled地图渲染器时遇到了类似的问题。

解决方案是首先将未缩放的地图渲染为db.tapwiser.find({"custID" : "12345"}, {}, {}).count();,然后在第二遍中缩放整个事物。这样您就不会缩放每个单独的图块,而是整个地图。

您可以在TiledMap class

中查看MonoGame.Extended的工作原理

在您的情况下,代码可能如下所示:

db.tapwiser.find({"custID" : "6789"}, {}, {}).count();

请注意,我已将相机转换移至第二个RenderTarget2D调用并引入了新的private readonly RenderTarget2D _renderTarget; protected override void Draw(GameTime gameTime) { GraphicsDevice.SetRenderTarget(_renderTarget); GraphicsDevice.Clear(Color.Black); SpriteBatch.Begin(sortMode: SpriteSortMode.Deferred, samplerState: SamplerState.PointClamp); foreach( TmxLayer Layer in mCurrentTileMap.Layers) { for (int y = 0; y < mCurrentTileMap.Height; y++) { for (int x = 0; x < mCurrentTileMap.Width; x++) { TmxLayerTile Tile = Layer.Tiles[mCurrentTileMap.Width * y + x]; int TileID = -1; Texture2D Texture = FindTileMapTextureForTileID(Tile.Gid, out TileID); if (TileID > 0) { int atlasX = TileID % (Texture.Width / TileSize); int atlasY = TileID / (Texture.Width / TileSize); SpriteEffects FX = SpriteEffects.None; if (Tile.HorizontalFlip) { FX = SpriteEffects.FlipHorizontally; } SpriteBatch.Draw(Texture, new Vector2(x * TileSize, y * TileSize), new Microsoft.Xna.Framework.Rectangle(atlasX * TileSize, atlasY * TileSize, TileSize, TileSize), Color.White, 0, Vector2.Zero, 1, FX, 0); } } } } SpriteBatch.End(); GraphicsDevice.SetRenderTarget(null); SpriteBatch.Begin(sortMode: SpriteSortMode.Immediate, blendState: BlendState.NonPremultiplied, samplerState: SamplerState.PointClamp, transformMatrix: CameraManager.pInstance.pFinalTransform); SpriteBatch.Draw(_renderTarget, Vector2.Zero, Color.White); SpriteBatch.End(); } 成员变量。在调用SpriteBatch.Begin之前,不要忘记在某处声明_renderTarget。像这样:

_renderTarget

它需要足够大才能渲染你的地图。理想情况下,它会被优化为仅渲染地图的可见部分,但这是另一个故事。