Куб с использованием одного GL_TRIANGLE_STRIP

Можно ли нарисовать целый куб, используя только один GL_TRIANGLE_STRIP?

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

6 ответов

Решение

Для тех из вас, кто ленив (как и я), вот версия для копирования Роба Мейоффа "вставь-вставь";)

static const GLfloat cube_strip[] = {
    -1.f, 1.f, 1.f,     // Front-top-left
    1.f, 1.f, 1.f,      // Front-top-right
    -1.f, -1.f, 1.f,    // Front-bottom-left
    1.f, -1.f, 1.f,     // Front-bottom-right
    1.f, -1.f, -1.f,    // Back-bottom-right
    1.f, 1.f, 1.f,      // Front-top-right
    1.f, 1.f, -1.f,     // Back-top-right
    -1.f, 1.f, 1.f,     // Front-top-left
    -1.f, 1.f, -1.f,    // Back-top-left
    -1.f, -1.f, 1.f,    // Front-bottom-left
    -1.f, -1.f, -1.f,   // Back-bottom-left
    1.f, -1.f, -1.f,    // Back-bottom-right
    -1.f, 1.f, -1.f,    // Back-top-left
    1.f, 1.f, -1.f      // Back-top-right
};

Да, после небольшого количества экспериментов я нашел ответ сам. Представьте, что углы вашего куба окрашены попеременно в черный и белый цвета. Нарисуйте треугольный край вдоль каждой грани между двумя черными углами. Таким образом, диагонали образуют тетраэдр внутри куба. Для куба [0,1]³ возможная последовательность координат будет следующей:

Vertex  Triangle    Face
------+-----------+-----
0 0 0
0 1 0
1 0 0  000 010 100  **0
1 1 0  100 010 110  **0
1 1 1  100 110 111  1**
0 1 0  111 110 010  *1*
0 1 1  111 010 011  *1*
0 0 1  011 010 001  0**
1 1 1  011 001 111  **1
1 0 1  111 001 101  **1
1 0 0  111 101 100  1**
0 0 1  100 101 001  *0*
0 0 0  100 001 000  *0*
0 1 0  000 001 010  0**

Упомянутая выше бумага имеет треугольники, накрученные в неправильном направлении, однако есть простое исправление, обратный порядок вершин, и он станет лицевой стороной наружу (а не внутрь).

1 2 5 6 7 2 4 1 3 5 8 7 3 4

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

          static const std::array<float> cube_strip = {
        +0.5, +0.5, -0.5, // Back-top-right
        -0.5, +0.5, -0.5, // Back-top-left
        +0.5, -0.5, -0.5, // Back-bottom-right
        -0.5, -0.5, -0.5, // Back-bottom-left
        -0.5, -0.5, +0.5, // Front-bottom-left
        -0.5, +0.5, -0.5, // Back-top-left
        -0.5, +0.5, +0.5, // Front-top-left
        +0.5, +0.5, -0.5, // Back-top-right
        +0.5, +0.5, +0.5, // Front-top-right
        +0.5, -0.5, -0.5, // Back-bottom-right
        +0.5, -0.5, +0.5, // Front-bottom-right
        -0.5, -0.5, +0.5, // Front-bottom-left
        +0.5, +0.5, +0.5, // Front-top-right
        -0.5, +0.5, +0.5, // Front-top-left
    };

May be useful to some, here's a geometry shader that will take in a point and output a triangle strip of a unit cube

#version 410

layout(points) in;
layout(triangle_strip, max_vertices = 12) out;

uniform mat4 mvp;

void main() {
    vec4 center = gl_in[0].gl_Position;

    vec4 dx = mvp[0];
    vec4 dy = mvp[1];
    vec4 dz = mvp[2];

    vec4 p1 = center;
    vec4 p2 = center + dx;
    vec4 p3 = center + dy;
    vec4 p4 = p2 + dy;
    vec4 p5 = p1 + dz;
    vec4 p6 = p2 + dz;
    vec4 p7 = p3 + dz;
    vec4 p8 = p4 + dz;

    gl_Position = p7;
    EmitVertex();

    gl_Position = p8;
    EmitVertex();

    gl_Position = p5;
    EmitVertex();

    gl_Position = p6;
    EmitVertex();

    gl_Position = p2;
    EmitVertex();

    gl_Position = p8;
    EmitVertex();

    gl_Position = p4;
    EmitVertex();

    gl_Position = p7;
    EmitVertex();

    gl_Position = p3;
    EmitVertex();

    gl_Position = p5;
    EmitVertex();

    gl_Position = p1;
    EmitVertex();

    gl_Position = p2;
    EmitVertex();

    gl_Position = p3;
    EmitVertex();

    gl_Position = p4;
    EmitVertex();

}

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

Я проверил это с помощью WebGL, и куб имеет правильное отображение текстуры, но имеет особенности из-за того, что вам действительно нужны три координаты текстуры для каждого угла - по одной для каждой грани. Из-за этого вы можете использовать эти UV-развертки с бесшовной текстурой, но вы не можете «раскрасить» шесть сторон куба.

          const verticies = [
        -1, -1, -1, // 4
        +1, -1, -1, // 3
        -1, -1, +1, // 7
        +1, -1, +1, // 8
        +1, +1, +1, // 5
        +1, -1, -1, // 3
        +1, +1, -1, // 1
        -1, -1, -1, // 4
        -1, +1, -1, // 2
        -1, -1, +1, // 7
        -1, +1, +1, // 6
        +1, +1, +1, // 5
        -1, +1, -1, // 2
        +1, +1, -1, // 1
    ];

    const u0 = 0;
    const u1 = 1;

    const v0 = 0;
    const v1 = 1 / 3;
    const v2 = 2 / 3;
    const v3 = 1;

    const uvs = [
        u0, v1, // 4
        u0, v2, // 3
        u1, v1, // 7
        u1, v2, // 8
        u1, v3, // 5
        u0, v2, // 3
        u0, v3, // 1
        u0, v1, // 4
        u0, v0, // 2
        u1, v1, // 7
        u1, v0, // 6
        u1, v2, // 5
        u0, v0, // 2
        u0, v3, // 1
    ];
Другие вопросы по тегам