OpenGL : 왜 glNormal로 법선을 설정해야합니까?


19

OpenGL의 기본 사항을 배우고 있지만 glNormal정점의 법선을 설정 하라는 호출이 왜 필요한지 궁금 합니다.

다음과 같이 간단한 삼각형을 만들면 :

glBegin(GL_TRIANGLES);
    glVertex3f(0,0,0);
    glVertex3f(1,0,0);
    glVertex3f(0,1,0);
glEnd();

기하 기본형의 유형에 의해 법선이 암시 적으로 정의되어서는 안됩니까? 표준을 설정하지 않으면 OpenGL이 계산합니까?


7
이 코드는 더 이상 사용되지 않는 고정 함수 파이프 라인을 사용하고 있으며 현대 OpenGL에서는 법선과 정점이 둘 다 일반적인 정점 속성이라는 것을 지적하고 싶습니다.
Bartek Banachewicz 2014 년

4
즉시 모드를 사용하지 마십시오. 더 이상 사용되지 않습니다. 현대 3D 그래픽 프로그래밍 학습을 적극 권장 합니다.
rightfold

3
즉각적인 모드 사용에 대한 의견은 여기와 완전히 관련이 없다고 생각합니다. 그렇습니다. 사용해서는 안되지만, 질문의 요점은 바로 모드, 정점 배열, VBO, 일반 속성, 고정 속성 또는 토스트 비트에 관계없이 동일하게 유지됩니다.
Maximus Minimus

1
자동으로 결정되지 않는 이유는 조명을 매우 다각형으로 만들었 기 때문입니다 (더 나은 단어가없는 경우). 이것이 의미하는 바는 삼각형의 모든 정점이 동일한 법선 값을가집니다. 평평한 표면의 경우 이것이 예상 할 수 있지만, 사람의 얼굴 모델이있는 경우 얼굴의 각 삼각형은 동일한 조명 값을가집니다 (다각형을 쉽게 볼 수 있음). 자신의 법선 값을 지정하면 훨씬 매끄럽게 보일 수 있습니다 (일반적으로 현재 정점을 포함하는 모든 삼각형의 법선 값을 평균하여 법선을 찾습니다).
Benjamin Danger Johnson

답변:


30

glNormal사이에 여러 번 호출 glBegin/End하면 기본이 아닌 정점마다 법선을 설정할 수 있습니다.

glBegin(GL_TRIANGLES);
    glNormal3f(0,0,1);
    glVertex3f(0,0,0);
    glNormal3f(0,0,1);
    glVertex3f(1,0,0);
    glNormal3f(0,0,1);
    glVertex3f(0,1,0);
glEnd();

여러 삼각형으로 구성된 더 복잡한 메쉬의 경우 한 정점의 법선이 삼각형의 법선뿐만 아니라 주변 지오메트리의 다른 삼각형에 의존하기를 원합니다.

다음은 동일한 형상의 예입니다.

  • 왼쪽 정점 법선 -면의 각 꼭지점이 서로 다른 법선을 갖습니다 (이 구의 경우 모든 법선이 중심에서 바깥 쪽을 가리킴).
  • 오른쪽 면당 법선 -각 꼭짓점은 동일한 법선 값을 얻습니다 (한 번만 지정하거나 기본 법선 값을 사용하기 때문에 (0,0,1)).

왼쪽의 정점 별 법선, 오른쪽의 얼굴 별 법선

기본 음영 모델 ( GL_SMOOTH)을 사용하면면 정점의 법선이면에 보간됩니다. 를 들어 당 정점 법선 음영 부드럽게 분야에서이 결과는하지만위한 당면 법선 당신은 특성 측면 표정으로 끝낸다.


4

아니요, GL은 표준을 계산하지 않습니다. 정상적인 것이 무엇인지 알 수 없습니다. 프리미티브는 래스터 화 (및 다른 장소) 이외의 것을 의미하지 않습니다. GL은 어떤면 (삼각형)이 정점을 공유하는지 모릅니다 (런타임에서이를 계산하는 것은 다른 데이터 구조를 사용하지 않고 매우 비쌉니다).

일반적인 정점을 찾고 법선을 계산하려면 메쉬의 "삼각 국"을 전처리해야합니다. 이것은 게임이 속도로 실행되기 전에 수행되어야합니다.

모서리에 공유 정점이있는 딱딱한 가장자리와 같은 경우도 있지만, 법선이 올바르게 켜지도록 별도의 법선을 원합니다. GL / D3D 렌더링 모델에서는 각각 별도의 법선을 가진 두 개의 별도 정점이 (동일한 위치에) 필요합니다.

UV와 텍스처 매핑에도이 모든 것이 필요합니다.


3

짧은 대답은 당신이 실제로 없다는 것입니다 모두에서 정상을 설정할 수 있습니다. 법선 벡터는 OpenGL 조명을 수행하는 경우 (또는 그에 따라 달라질 수있는 다른 계산)에만 적용되지만 적용되지 않는 경우 (또는 라이트 맵과 같은 다른 방법을 사용하는 경우) ) 그러면 모든 glNormal 호출을 행복하게 생략 할 수 있습니다.

따라서 glNormal을 지정하는 것이 합리적이며 좀 더 살펴 본다고 가정 해 봅시다.

glNormal은 기본 또는 정점마다 지정할 수 있습니다. 프리미티브 당 법선을 사용한다는 것은 프리미티브면의 각 정점에 대한 모든 노멀이 같은 방향으로 존재한다는 것입니다. 때로는 이것이 당신이 원하는 것이지만 때로는 그렇지 않습니다-꼭지점 법선이 유용한 곳은 각 꼭지점이 자신의 얼굴을 가질 수 있다는 것입니다.

구의 고전적인 예를 들어보십시오. 구의 각 삼각형이 같은 법선을 가졌다면 최종 결과는 상당히 깎아 질 것입니다. 그것은 아마도 당신이 원하는 것이 아니며, 부드러운 음영을 원합니다. 그래서 당신이하는 일은 공통 정점을 공유하는 각 삼각형의 법선을 평균화하고 부드러운 음영 결과를 얻는 것입니다.


2

glNormal확산 번개 를 사용하는 방법에 대한 세부 정보를 보여주는 최소 예제 입니다 .

display함수 의 주석은 각 삼각형의 의미를 설명합니다.

여기에 이미지 설명을 입력하십시오

#include <stdlib.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

/* Triangle on the x-y plane. */
static void draw_triangle() {
    glBegin(GL_TRIANGLES);
    glVertex3f( 0.0f,  1.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, 0.0f);
    glVertex3f( 1.0f, -1.0f, 0.0f);
    glEnd();
}

/* A triangle tilted 45 degrees manually. */
static void draw_triangle_45() {
    glBegin(GL_TRIANGLES);
    glVertex3f( 0.0f,  1.0f, -1.0f);
    glVertex3f(-1.0f, -1.0f,  0.0f);
    glVertex3f( 1.0f, -1.0f,  0.0f);
    glEnd();
}

static void display(void) {
    glColor3f(1.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glPushMatrix();

    /*
    Triangle perpendicular to the light.
    0,0,1 also happens to be the default normal if we hadn't specified one.
    */
    glNormal3f(0.0f, 0.0f, 1.0f);
    draw_triangle();

    /*
    This triangle is as bright as the previous one.
    This is not photorealistic, where it should be less bright.
    */
    glTranslatef(2.0f, 0.0f, 0.0f);
    draw_triangle_45();

    /*
    Same as previous triangle, but with the normal set
    to the photorealistic value of 45, making it less bright.

    Note that the norm of this normal vector is not 1,
    but we are fine since we are using `glEnable(GL_NORMALIZE)`.
    */
    glTranslatef(2.0f, 0.0f, 0.0f);
    glNormal3f(0.0f, 1.0f, 1.0f);
    draw_triangle_45();

    /*
    This triangle is rotated 45 degrees with a glRotate.
    It should be as bright as the previous one,
    even though we set the normal to 0,0,1.
    So glRotate also affects the normal!
    */
    glTranslatef(2.0f, 0.0f, 0.0f);
    glNormal3f(0.0, 0.0, 1.0);
    glRotatef(45.0, -1.0, 0.0, 0.0);
    draw_triangle();

    glPopMatrix();
    glFlush();
}

static void init(void) {
    GLfloat light0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
    /* Plane wave coming from +z infinity. */
    GLfloat light0_position[] = {0.0, 0.0, 1.0, 0.0};
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_SMOOTH);
    glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glColorMaterial(GL_FRONT, GL_DIFFUSE);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_NORMALIZE);
}

static void reshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 7.0, -1.0, 1.0, -1.5, 1.5);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(800, 200);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return EXIT_SUCCESS;
}

이론

OpenGL에서 각 정점에는 고유 한 법선 벡터가 있습니다.

법선 벡터는 정점의 밝기를 결정한 다음 삼각형의 밝기를 결정하는 데 사용됩니다.

표면이 빛에 직각 일 때 평행 표면보다 밝습니다.

glNormal 다음의 모든 정점에 사용되는 현재 법선 벡터를 설정합니다.

우리 모두 glNormal가 하기 전에 법선의 초기 값 은 0,0,1입니다.

법선 벡터 는 표준 1을 가져야합니다. 그렇지 않으면 색이 변합니다! glScale또한 법선의 길이를 변경합니다! glEnable(GL_NORMALIZE);OpenGL이 자동으로 표준을 1로 설정합니다. 이 GIF 는 아름답게 보여줍니다.

서지:


좋은 대답이지만 왜 오래된 질문과 오래된 기술에 초점을 맞추고 있습니까?
Vaillancourt

@AlexandreVaillancourt 감사합니다! 오래된 질문 : 왜 :-) 오래된 기술 : 오늘날 더 좋은 방법은 무엇입니까?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

현대 OpenGL은 glNormal을 지정하는 대신 버퍼 객체를 사용한다고 생각합니다.
Vaillancourt

1
실제로, glNormal과 glVertex 등은 현대 OpenGL에서 사라졌으며 그 전에 얼마 전에 사용되지 않았습니다 ... 그들은 실제로이 질문을 받았을 때에도 더 이상 사용되지 않습니다.

0

코더에 따라 일부 기능을 구현하려면 glNormal이 필요합니다. 예를 들어 법선을 만들어 하드 가장자리를 유지하려고 할 수 있습니다.


4
아마도 대답을 약간 향상시키고 싶을 것입니다.
Bartek Banachewicz

1
내 대답을 개선하려면 약점을 지적해야합니다. 그래도 자세히 설명 할 수 있습니다. xblax가 생각하는 데 사용 된 것처럼, 각각의 법선은 같은 방식으로 계산되어야합니다. 각 픽셀과 얼굴의 보간 법선의 차이에도 불구하고. 주제에 대해 조금 더 살펴 보겠습니다.
AB.

1
때때로 당신은 어려운 가장자리를 유지하고 더 독특하게 할 수 있습니다. 다음은 일부 샘플 이미지입니다. titan.cs.ukzn.ac.za/opengl/opengl-d5/trant.sgi.com/opengl/… PS. 이중 게시에 대해 죄송합니다. 저는 SE 인터페이스
AB를

"편집"버튼이 있습니다.
Bartek Banachewicz

1
5 분
AB
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.