XNA等距图块渲染问题

发布于 2024-10-05 02:51:25 字数 2517 浏览 5 评论 0原文

我目前正在开发 XNA 游戏原型。我正在尝试实现游戏世界的等距视图(或者是正投影?我不确定哪个是该投影的正确术语 - 请参阅图片)。 世界应该是一个由立方体瓷砖组成的基于瓷砖的世界(例如,类似于 Minecraft 的世界),我正在尝试使用精灵以 2D 形式渲染它。

所以我有一个精灵表,其中包含立方体的顶面、正面和侧面(可见侧面)。我使用 3 个单独的drawSprite 调用来绘制图块,一个用于顶部,一个用于侧面,一个用于正面,使用源矩形来选择我想要绘制的面,并使用目标矩形来设置屏幕上的位置将 3D 世界坐标转换为等距坐标(正交?)的公式。

(示例精灵: Sprite)

只要我绘制脸部,这个效果就很好,但是如果我尝试绘制每个块的细边缘(如每个图块网格)我可以看到我得到了一个随机渲染模式,其中一些线条被脸部本身覆盖,而另一些则没有。

请注意,对于我的世界表示,X 是从左到右,Y 是屏幕内到屏幕外,Z 是从上到下。

在此示例中,我仅处理顶面边缘。这是我得到的(图片):

alt text

我不明白为什么有些行显示,有些行显示不是。 我使用的渲染代码是(请注意,在本示例中,我仅绘制每个维度中的最顶层):

/// <summary>
/// Draws the world
/// </summary>
/// <param name="spriteBatch"></param>
public void draw(SpriteBatch spriteBatch)
{
    Texture2D tex = null;

    // DRAW TILES
    for (int z = numBlocks - 1; z >= 0; z--)
    {
        for (int y = 0; y < numBlocks; y++)
        {
            for (int x = numBlocks - 1; x >=0 ; x--)
            {

                myTextures.TryGetValue(myBlockManager.getBlockAt(x, y, z), out tex);
                if (tex != null)
                {
                    // TOP FACE
                    if (z == 0)
                    {
                        drawTop(spriteBatch, x, y, z, tex);
                        drawTop(spriteBatch, x, y, z, outlineTexture);
                    }

                    // FRONT FACE
                    if(y == numBlocks -1)
                        drawFront(spriteBatch, x, y, z, tex);

                    // SIDE FACE
                    if(x == 0)
                        drawSide(spriteBatch, x, y, z, tex);

                }
            }
        }
    }
}


private void drawTop(SpriteBatch spriteBatch, int x, int y, int z, Texture2D tex)
        {
            int pX = OffsetX + (int)(x * TEXTURE_TOP_X_OFFRIGHT + y * TEXTURE_SIDE_X);
            int pY = OffsetY + (int)(y * TEXTURE_TOP_Y + z * TEXTURE_FRONT_Y);
            topDestRect.X = pX;
            topDestRect.Y = pY;
            spriteBatch.Draw(tex, topDestRect, TEXTURE_TOP_RECT, Color.White);   
        }

我尝试使用不同的方法,在第一个循环之后创建第二个 3 层嵌套 for 循环,因此我保留顶部第一个循环中的面部绘制和第二个循环中的边缘突出显示(我知道,这是低效的,我也应该避免为每个图块调用方法来绘制它,但我只是想让它现在工作)。

结果在某种程度上更好,但仍然无法按预期工作,顶行丢失,请参见图片:

alt text

知道为什么我有这个问题吗?在第一种方法中,这可能是一种 z-fighting,但我正在以精确的顺​​序绘制精灵,所以它们不应该覆盖已经存在的内容吗?

谢谢大家

I'm currently working on a XNA game prototype. I'm trying to achieve a isometric view of the game world (or is it othographic?? I'm not sure which is the right term for this projection - see pictures).
The world should a tile-based world made of cubic tiles (e.g. similar to Minecraft's world), and I'm trying to render it in 2D by using sprites.

So I have a sprite sheet with the top face of the cube, the front face and the side (visible side) face. I draw the tiles using 3 separate calls to drawSprite, one for the top, one for the side, one for the front, using a source rectangle to pick the face I want to draw and a destination rectangle to set the position on the screen according to a formula to convert from 3D world coordinates to isometric (orthographic?).

(sample sprite:
Sprite)

This works good as long as I draw the faces, but if I try to draw fine edges of each block (as per a tile grid) I can see that I get a random rendering pattern in which some lines are overwritten by the face itself and some are not.

Please note that for my world representation, X is left to right, Y is inside screen to outside screen, and Z is up to down.

In this example I'm working only with top face-edges. Here is what I get (picture):

alt text

I don't understand why some of the lines are shown and some are not.
The rendering code I use is (note in this example I'm only drawing the topmost layers in each dimension):

/// <summary>
/// Draws the world
/// </summary>
/// <param name="spriteBatch"></param>
public void draw(SpriteBatch spriteBatch)
{
    Texture2D tex = null;

    // DRAW TILES
    for (int z = numBlocks - 1; z >= 0; z--)
    {
        for (int y = 0; y < numBlocks; y++)
        {
            for (int x = numBlocks - 1; x >=0 ; x--)
            {

                myTextures.TryGetValue(myBlockManager.getBlockAt(x, y, z), out tex);
                if (tex != null)
                {
                    // TOP FACE
                    if (z == 0)
                    {
                        drawTop(spriteBatch, x, y, z, tex);
                        drawTop(spriteBatch, x, y, z, outlineTexture);
                    }

                    // FRONT FACE
                    if(y == numBlocks -1)
                        drawFront(spriteBatch, x, y, z, tex);

                    // SIDE FACE
                    if(x == 0)
                        drawSide(spriteBatch, x, y, z, tex);

                }
            }
        }
    }
}


private void drawTop(SpriteBatch spriteBatch, int x, int y, int z, Texture2D tex)
        {
            int pX = OffsetX + (int)(x * TEXTURE_TOP_X_OFFRIGHT + y * TEXTURE_SIDE_X);
            int pY = OffsetY + (int)(y * TEXTURE_TOP_Y + z * TEXTURE_FRONT_Y);
            topDestRect.X = pX;
            topDestRect.Y = pY;
            spriteBatch.Draw(tex, topDestRect, TEXTURE_TOP_RECT, Color.White);   
        }

I tried using a different approach, creating a second 3-tiers nested for loop after the first one, so I keep the top face drawing in the first loop and the edge highlight in the second loop (I know, this is inefficient, I should also probably avoid having a method call for each tile to draw it, but I'm just trying to get it working for now).

The results are somehow better but still not working as expected, top rows are missing, see picture:

alt text

Any idea of why I'm having this problem? In the first approach it might be a sort of z-fighting, but I'm drawing sprites in a precise order so shouldn't they overwrite what's already there?

Thanks everyone

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

囍孤女 2024-10-12 02:51:25

哇,对不起,我是个白痴:)我用 SpriteBatch.begin(SpriteSortMode.BackToFront) 开始批处理,但我没有在绘图中使用任何 z 值。
我应该使用 SpriteSortMode.Deferred!现在工作正常。谢谢大家!

Whoa, sorry guys I'm an idiot :) I started the batch with SpriteBatch.begin(SpriteSortMode.BackToFront) but I didn't use any z-value in the draw.
I should have used SpriteSortMode.Deferred! It's now working fine. Thanks everyone!

醉生梦死 2024-10-12 02:51:25

尝试将源矩形和目标矩形的大小调整 1 或 2 个像素。我隐隐怀疑这与这些矩形作为要渲染区域的“轮廓”的处理方式以及一种相差一问题的方式有关。这不是专家的建议,只是程序员同事的直觉。

Try tweaking the sizes of your source and destination rectangles by 1 or 2 pixels. I have a sneaking suspicion this has something to do with the way these rectangles are handled as sort of 'outlines' of the area to be rendered and a sort of off-by-one problem. This is not expert advice, just a fellow coder's intuition.

一抹微笑 2024-10-12 02:51:25

看起来像是子像素精度或缩放问题。还要尝试确保您的纹理/图块宽度/高度是 2 的幂(32、64、128 等),因为这也可以使效果不那么糟糕。仅凭这些照片真的很难判断。

我不知道如何/是否缩放所有内容,但您应该尽可能避免舍入(尤其是在 drawTop() 方法内)。每次你舍入一些位置/坐标的机会很好时,你可能会增加错误/随机偏移。尝试使用双精度(或更好:浮点)坐标而不是整数。

Looks like a sub pixel precision or scaling issue. Also try to ensure your texture/tile width/height is a power of 2 (32, 64, 128, etc.) as that could make the effect less bad as well. It's really hard to tell just from those pictures.

I don't know how/if you scale everything, but you should try to avoid rounding wherever possible (especially inside your drawTop() method). Every time you round some position/coordinate chances are good you might increase the error/random offsets. Try to use double (or better: float) coordinates instead of integer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文