Programing

OpenGL에서 프리미티브를 와이어 프레임으로 어떻게 렌더링합니까?

lottogame 2020. 5. 6. 20:51
반응형

OpenGL에서 프리미티브를 와이어 프레임으로 어떻게 렌더링합니까?


OpenGL에서 프리미티브를 와이어 프레임으로 어떻게 렌더링합니까?


glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

스위치를 켜려면

glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

정상으로 돌아갑니다.

텍스처 매핑 및 조명과 같은 기능이 활성화되어 있으면 와이어 프레임 라인에 계속 적용되어 이상하게 보일 수 있습니다.


에서 http://cone3d.gamedev.net/cgi-bin/index.pl?page=tutorials/ogladv/tut5

// Turn on wireframe mode
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);

// Draw the box
DrawBox();

// Turn off wireframe mode
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);

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)세 개의 삼각형의 정점 (순서는, 정말 중요합니까 잠재적으로 쉽게 삼각형 스트립으로 포장하게된다).

The obvious disadvantage of this approach is that it will eat some texture coordinates and you need to modify your vertex array. Could be solved with a very simple geometry shader but I'd still suspect it will be slower than just feeding the GPU with more data.


The easiest way is to draw the primitives as GL_LINE_STRIP.

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

If you are using the fixed pipeline (OpenGL < 3.3) or the compatibility profile you can use

//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);

In this case you can change the line width by calling glLineWidth

Otherwise you need to change the polygon mode inside your draw method (glDrawElements, glDrawArrays, etc) and you may end up with some rough results because your vertex data is for triangles and you are outputting lines. For best results consider using a Geometry shader or creating new data for the wireframe.


You can use glut libraries like this:

  1. for a sphere:

    glutWireSphere(radius,20,20);
    
  2. for a Cylinder:

    GLUquadric *quadratic = gluNewQuadric();
    gluQuadricDrawStyle(quadratic,GLU_LINE);
    gluCylinder(quadratic,1,1,1,12,1);
    
  3. for a Cube:

    glutWireCube(1.5);
    

In Modern OpenGL(OpenGL 3.2 and higher), you could use a Geometry Shader for this :

#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();
}

Notices :


If it's OpenGL ES 2.0 you're dealing with, you can choose one of draw mode constants from

GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, to draw lines,

GL_POINTS (if you need to draw only vertices), or

GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, and GL_TRIANGLES to draw filled triangles

as first argument to your

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

or

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

참고URL : https://stackoverflow.com/questions/137629/how-do-you-render-primitives-as-wireframes-in-opengl

반응형