Проблема с рендерингом изометрических листов XNA

В настоящее время я работаю над прототипом игры XNA. Я пытаюсь получить изометрический вид игрового мира (или это отографический? Я не уверен, какой термин подходит для этой проекции - см. Рисунки). Мир должен представлять собой мир, основанный на плитках, состоящий из кубических плиток (например, похожий на мир Minecraft), и я пытаюсь визуализировать его в 2D с помощью спрайтов.

Итак, у меня есть лист спрайтов с верхней гранью куба, передней гранью и боковой (видимой стороной) гранью. Я рисую плитки, используя 3 отдельных вызова drawSprite, один для верхней части, один для стороны, один для передней части, используя исходный прямоугольник, чтобы выбрать лицо, которое я хочу нарисовать, и целевой прямоугольник, чтобы установить положение на экране в соответствии с в формулу для преобразования трехмерных мировых координат в изометрические (орфографические?).

(образец спрайта: 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);   
        }

Я попытался использовать другой подход, создав второй трехуровневый вложенный цикл for после первого, поэтому я сохраняю рисунок верхней грани в первом цикле и выделение края во втором цикле (я знаю, это неэффективно, я должен также, вероятно, избегайте вызова метода для каждой плитки, чтобы нарисовать ее, но я просто пытаюсь заставить ее работать).

Результаты несколько лучше, но все еще не работают должным образом, верхние строки отсутствуют, см. Рисунок:

alt text

Есть идеи, почему у меня эта проблема? При первом подходе это может быть своего рода z-борьба, но я рисую спрайты в точном порядке, так что не должны ли они перезаписывать то, что уже есть?

Всем спасибо


person Marco83    schedule 30.11.2010    source источник


Ответы (3)


Ого, извините, ребята, я идиот :) Я начал партию с SpriteBatch.begin (SpriteSortMode.BackToFront), но я не использовал z-значение в розыгрыше. Я должен был использовать SpriteSortMode.Deferred! Теперь все работает нормально. Всем спасибо!

person Marco83    schedule 30.11.2010

Попробуйте изменить размеры исходного и конечного прямоугольников на 1 или 2 пикселя. У меня есть скрытое подозрение, что это как-то связано с тем, как эти прямоугольники обрабатываются как своего рода «очертания» области, которая должна быть отрисована, и что-то вроде отдельной проблемы. Это не совет эксперта, а интуиция товарища-программиста.

person DGH    schedule 30.11.2010

Похоже на проблему с субпиксельной точностью или масштабированием. Также постарайтесь убедиться, что ширина / высота вашей текстуры / плитки равна степени 2 (32, 64, 128 и т. Д.), Так как это также может сделать эффект менее плохим. Это действительно сложно сказать по фотографиям.

Я не знаю, как / если вы все масштабируете, но вы должны стараться по возможности избегать округления (особенно внутри вашего drawTop() метода). Каждый раз, когда вы округляете некоторые шансы на положение / координату, вы можете увеличивать ошибку / случайные смещения. Попробуйте использовать двойные (или лучше: float) координаты вместо целых.

person Mario    schedule 30.11.2010
comment
Прямо сейчас я использую масштаб 1: 1, если я его изменяю, я использую некоторые артефакты в определенных масштабах (т.е. блоки пропускают пиксель в данной строке), но в остальном все нормально. Также кажется, что происхождение прямоугольника может быть установлено только на значение int? - person Marco83; 01.12.2010
comment
Никогда не использовал его (сконцентрируйтесь в основном на простом DirectX и OpenGL), но если он принимает координаты экрана / пиксели, целые числа в порядке. Просто не округляйте их при вычислении (перед их передачей). - person Mario; 01.12.2010