Вершинные массивы OpenGL и ошибка рисования GL_TRIANGLE_STRIP - PullRequest
1 голос
/ 02 февраля 2012

Я реализую карту высот с помощью GL_TRIANGLE_STRIPS и привязок Java LWJGL OpenGL. Когда я рисую 'direct', используя 'GL_BEGIN / GL_END', это работает отлично, но когда карта высот слишком большая, она работает медленно.

Поскольку я хочу перейти к использованию VBO, я сейчас учусь, как использовать Vertex Array. Вот где у меня проблема, чертеж просто неправильный. Кажется, что последний треугольник полосы возвращается к первому. Пешит картинка лучше:

Хороший рисунок: Good direct drawing

Рисование массива неверных вершин: Bad vertex array drawing

Мой код следующий для нормального рисования:

public void renderDirect() {
    //adapt the camera to the map
    float scale = 5.0f / Math.max(w - 1, l - 1);
    GL11.glScalef(scale, scale, scale);
    GL11.glTranslatef(-(float) (w - 1) / 2, 0.0f, -(float) (l - 1) / 2);

    //choose map color
    GL11.glColor3f(0.3f, 0.9f, 0.0f);

    for (int z = 0; z < l - 1; z++) {
        //Makes OpenGL draw a triangle at every three consecutive vertices
        GL11.glBegin(GL11.GL_TRIANGLE_STRIP);
        for (int x = 0; x < w; x++) {
            Vector3f normal = getNormal(x, z);
            GL11.glNormal3f(normal.getX(), normal.getY(), normal.getZ());
            GL11.glVertex3f(x, getHeight(x, z), z);
            normal = getNormal(x, z + 1);
            GL11.glNormal3f(normal.getX(), normal.getY(), normal.getZ());
            GL11.glVertex3f(x, getHeight(x, z + 1), z + 1);
        }
        glEnd();
    }
}

Мой код следующий для рисования массива вершин:

private void loadArrays(){
    //calculate the length of the buffers
    bLength = (l-1) * w * 6;
    //create the normal and vertex buffer array's
    dataBuffer = BufferUtils.createFloatBuffer(bLength*2);
    cBuffer = BufferUtils.createFloatBuffer(bLength);

    for (int z = 0; z < l - 1; z++) {
        //Fill up the buffers
        for (int x = 0; x < w; x++) {
            Vector3f normal = getNormal(x, z);
            dataBuffer.put(x).put(getHeight(x,z)).put(z);
            dataBuffer.put(normal.getX()).put(normal.getY()).put(normal.getZ());
            normal = getNormal(x, z + 1);
            dataBuffer.put(x).put(getHeight(x,z+1)).put(z+1);
            dataBuffer.put(normal.getX()).put(normal.getY()).put(normal.getZ());              
        }
    } 
}

int stride = 6*4;
public void renderDirect() {
    //adapt the camera to the map
    float scale = 5.0f / Math.max(w - 1, l - 1);
    GL11.glScalef(scale, scale, scale);
    GL11.glTranslatef(-(float) (w - 1) / 2, 0.0f, -(float) (l - 1) / 2);

    //choose map color
    GL11.glColor3f(0.3f, 0.9f, 0.0f);

    //Draw the vertex arrays
    glEnableClientState(GL_VERTEX_ARRAY);      
    glEnableClientState(GL_NORMAL_ARRAY); 

    dataBuffer.position(0);
    glVertexPointer(3, stride, dataBuffer);
    dataBuffer.position(3);
    glNormalPointer(stride,dataBuffer);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, bLength/3);    

    glDisableClientState(GL_VERTEX_ARRAY);      
    glDisableClientState(GL_NORMAL_ARRAY);
}    

Что я делаю не так?

Ответы [ 2 ]

3 голосов
/ 02 февраля 2012

Конкатенирующие треугольные полосы друг к другу, как это, не будут работать так, как вы ожидаете.

Либо вызовите glDrawArrays() в цикле, настраивая параметры first и count, чтобы нарисовать исходный N треугольные полосы или добавьте вырожденные треугольники в конец каждой строки, чтобы сбросить начальную позицию полосы.

Или просто используйте GL_TRIANGLES:)

0 голосов
/ 05 марта 2012

Другое решение, которое может сэкономить вам много времени, если количество последовательно нарисованных треугольников в вашей полосе достаточно велико, это следующее:

При рендеринге треугольных полос вы предоставляете поток информации о вершинах в OpenGL ион отображает треугольник для каждой новой вершины (например, последовательность ABCDEF дает вам треугольники ABC, BCD, CDE, DEF).Теперь это всегда будет одна полоса (именно поэтому она называется GL_TRIANGLE_STRIP, а не именами во множественном числе).

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

Недопустимый многоугольник - это тот, у которого нет поверхности.Вы можете создать недопустимый полигон, указав идентичные точки, такие как ABB или ABA.Насколько я знаю, такой многоугольник будет отбракован довольно рано в процессе разработки, и поэтому он не дает вам больших накладных расходов.Теперь к вашей конкретной проблеме.Предположим, у вас есть пробел (обозначенный вертикальной чертой), такой как «ABC | DEF».Измените ваш поток так, чтобы он выглядел так: «ABCCEEDEF».Эта мерзость дает вам треугольники ABC, BCC, CCE, CEE, EDE, DEF.Если вы учитываете раннее отклонение недействительных, вы получаете ABC и DEF - именно то, что вы хотели.

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

В любом случае, если вам нужно построить разрыв, просто вы можете сделать это, указав неверный треугольник

...