Как вы делаете примитивы в виде каркасов в OpenGL?

Как вы создаете примитивы в виде каркасов в OpenGL?

Ответ 1

glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

для включения,

glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

чтобы вернуться к нормальной работе.

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

Ответ 3

Предполагая, что в OpenGL 3 и выше используется перекрестно-совместимый контекст, вы можете использовать glPolygonMode, как упоминалось ранее, но обратите внимание, что строки с толщиной более 1px теперь устарели. Поэтому, пока вы можете рисовать треугольники как проволочные рамки, они должны быть очень тонкими. В OpenGL ES вы можете использовать GL_LINES с тем же ограничением.

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

Что вы можете сделать вместо этого, и что также будет работать в OpenGL ES, это использовать шейдер фрагмента. Подумайте о применении текстуры треугольника с проволочной рамкой к треугольнику. За исключением того, что текстуры не нужны, ее можно создать процедурно. Но достаточно разговоров, пусть код. Фрагментный шейдер:

in vec3 v_barycentric; // barycentric coordinate inside the triangle
uniform float f_thickness; // thickness of the rendered lines

void main()
{
    float f_closest_edge = min(v_barycentric.x,
        min(v_barycentric.y, v_barycentric.z)); // see to which edge this pixel is the closest
    float f_width = fwidth(f_closest_edge); // calculate derivative (divide f_thickness by this to have the line width constant in screen-space)
    float f_alpha = smoothstep(f_thickness, f_thickness + f_width, f_closest_edge); // calculate alpha
    gl_FragColor = vec4(vec3(.0), f_alpha);
}

И вершинный шейдер:

in vec4 v_pos; // position of the vertices
in vec3 v_bc; // barycentric coordinate inside the triangle

out vec3 v_barycentric; // barycentric coordinate inside the triangle

uniform mat4 t_mvp; // modeview-projection matrix

void main()
{
    gl_Position = t_mvp * v_pos;
    v_barycentric = v_bc; // just pass it on
}

Здесь барицентрические координаты просто (1, 0, 0), (0, 1, 0) и (0, 0, 1) для трех треугольных вершин (порядок не имеет значения, что делает упаковку в треугольные полосы потенциально проще).

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

Ответ 4

Самый простой способ - нарисовать примитивы как GL_LINE_STRIP.

glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();

Ответ 5

Если вы используете фиксированный конвейер (OpenGL < 3.3) или профиль совместимости, который вы можете использовать

//Turn on wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

//Draw the scene with polygons as lines (wireframe)
renderScene();

//Turn off wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

В этом случае вы можете изменить ширину линии, вызвав glLineWidth

В противном случае вам нужно изменить режим многоугольника внутри метода рисования (glDrawElements, glDrawArrays и т.д.), и вы можете получить некоторые приблизительные результаты, потому что ваши данные вершин для треугольников, и вы выводите строки. Для получения наилучших результатов рассмотрите использование Geometry shader или создайте новые данные для каркаса.

Ответ 6

Вы можете использовать библиотеки переполнения:

  • для сферы:

    glutWireSphere(radius,20,20);
    
  • для цилиндра:

    GLUquadric *quadratic = gluNewQuadric();
    gluQuadricDrawStyle(quadratic,GLU_LINE);
    gluCylinder(quadratic,1,1,1,12,1);
    
  • для куба:

    glutWireCube(1.5);
    

Ответ 7

В Modern OpenGL (OpenGL 3.2 и выше) вы можете использовать Geometry Shader для этого:

#version 330

layout (triangles) in;
layout (line_strip /*for lines, use "points" for points*/, max_vertices=3) out;

in vec2 texcoords_pass[]; //Texcoords from Vertex Shader
in vec3 normals_pass[]; //Normals from Vertex Shader

out vec3 normals; //Normals for Fragment Shader
out vec2 texcoords; //Texcoords for Fragment Shader

void main(void)
{
    int i;
    for (i = 0; i < gl_in.length(); i++)
    {
        texcoords=texcoords_pass[i]; //Pass through
        normals=normals_pass[i]; //Pass through
        gl_Position = gl_in[i].gl_Position; //Pass through
        EmitVertex();
    }
    EndPrimitive();
}

Уведомления:

Ответ 8

Если это OpenGL ES 2.0, с которым вы имеете дело, вы можете выбрать одну из констант режима рисования из

GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, для рисования линий,

GL_POINTS (если вам нужно рисовать только вершины) или

GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN и GL_TRIANGLES для рисования заполненных треугольников

как первый аргумент для

glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)

или

glDrawArrays(GLenum mode, GLint first, GLsizei count).

Ответ 9

Хороший и простой способ рисования линий с сглаживанием на цели рендеринга без сглаживания - рисовать прямоangularьники шириной 4 пикселя с текстурой 1x4 со значениями альфа-канала {0., 1., 1., 0.} и использовать линейную фильтрацию с отключенным mip-mapping. Это сделает линии толщиной 2 пикселя, но вы можете изменить текстуру для различной толщины. Это быстрее и проще, чем бариметрические вычисления.