문제

OpenGL 프로그램을 실행하고 있는데 형상이 표시되지만 확산 음영이나 정반사 없이 모두 "평평한" 회색 톤입니다.

Tori with no shading

그림에는 3개의 토리가 있으며 각각은 쿼드 스트립으로 만들어졌습니다.우리는 음영을 보아야 하는데 그렇지 않습니다.내가 도대체 ​​뭘 잘못하고있는 겁니까?

다음은 정점과 법선을 설정하는 코드입니다(draw_torus() 표시 목록을 작성하기 위해 호출됩니다):

/* WrapTorus, adapted from
    http://www.math.ucsd.edu/~sbuss/MathCG/OpenGLsoft/WrapTorus/WrapTorus.html
    by Sam Buss */

/*
 * Issue vertex command for segment number j of wrap number i.
 * Normal added by Lars Huttar.
 * slices1 = numWraps; slices2 = numPerWrap.
 */
void putVert(float i, float j, float slices1, float slices2, float majR, float minR) {
    float wrapFrac = j / slices2;
    /* phi is rotation about the circle of revolution */
    float phi = PI2 * wrapFrac;
    /* theta is rotation about the origin, in the xz plane. */
    float theta = PI2 * (i + wrapFrac) / slices1;
    float y = minR * (float)sin(phi);
    float r = majR + minR * (float)cos(phi);
    float x = (float)sin(theta) * r;
    float z = (float)cos(theta) * r;
    /* normal vector points to (x,y,z) from: */
    float xb = (float)sin(theta) * majR;
    float zb = (float)cos(theta) * majR;
    glNormal3f(x - xb, y, z - zb);
    glVertex3f(x, y, z);
}

static void draw_torus(int numPerWrap, int numWraps, float majR, float minR) {
    int i, j;
    glBegin( GL_QUAD_STRIP );
    for (i=0; i < numWraps; i++ ) {
        for (j=0; j < numPerWrap; j++) {
            putVert((float)i, (float)j, (float)numWraps, (float)numPerWrap, majR, minR);
            putVert((float)(i + 1), (float)j, (float)numWraps, (float)numPerWrap, majR, minR);
        }
    }
    putVert(0.0, 0.0, (float)numWraps, (float)numPerWrap, majR, minR);
    putVert(1.0, 0.0, (float)numWraps, (float)numPerWrap, majR, minR);
    glEnd();
}

꼭지점 순서에 문제가 있나요?

다음은 표시 목록이 작성되는 init 함수의 일부입니다.

GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat color[4] = { 0.5, 0.6, 0.7, 1.0 };
    ...

glShadeModel(GL_SMOOTH);

torusDL = glGenLists (1);
glNewList(torusDL, GL_COMPILE);
setMaterial(color, white, 100);
draw_torus(8, 45, 1.0, 0.05);
glEndList();

여기서 setMaterial()은 다음 작업을 수행합니다.

static void setMaterial(const GLfloat color[3], const GLfloat hlite[3], int shininess) {
    glColor3fv(color);
    glMaterialfv(GL_FRONT, GL_SPECULAR, hlite);
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
    glMateriali(GL_FRONT, GL_SHININESS, shininess); /* [0,128] */
}

초기화 중에도 수행되는 조명은 다음과 같습니다.

  GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
  GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
  GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
  GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
  GLfloat color[4] = {0.20, 0.20, 0.20, 1.00};
  GLfloat spec[4]  = {0.30, 0.30, 0.30, 1.00};
  GLfloat shiny    = 8.0;

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);

  glLightfv(GL_LIGHT0, GL_POSITION, pos);
  glLightfv(GL_LIGHT0, GL_AMBIENT,  amb);
  glLightfv(GL_LIGHT0, GL_DIFFUSE,  dif);
  glLightfv(GL_LIGHT0, GL_SPECULAR, spc);

  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
  glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,            spec);
  glMaterialf  (GL_FRONT_AND_BACK, GL_SHININESS,           shiny);

그리기 함수에서 표시 목록이 호출되는 위치는 다음과 같습니다.

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix();
glLoadIdentity();       

glScalef(3.5, 3.5, 3.5);

for (i = 0; i < ac->nrings; i++) {
    glScalef(0.8, 0.8, 0.8);
    glRotatef(...);
    glCallList(torusDL);
}

glFlush();
glPopMatrix();
glXSwapBuffers(dpy, window);

이 "glx hack"의 전체 .c 소스 파일은 다음과 같습니다. 여기.차이가 있는 경우 이 코드는 다음과 같은 맥락에 있습니다. x화면 보호기.

도움이 되었습니까?

해결책

라스, 당신이 본 것처럼 glEnable(GL_NORMALIZE) (고정 기능 파이프라인에서) 조명 계산에 사용되는 변환에 앞서 법선 벡터를 정규화(놀랍게)합니다.이러한 계산은 올바른 결과를 위해 단위 길이 법선에 의존합니다.

법선 벡터에 적용되는 변환은 다음과 같다는 점을 지적할 가치가 있습니다. ~ 아니다 정점 기하학에 적용된 변환과 동일합니다.OpenGL 2.1 사양은 많은 경우와 마찬가지로 변환을 설명합니다. 다른 자원.벡터로서 법선은 동질적인 표현을 갖습니다. [nx, ny, nz, 0] - '무한대' 지점이며 GL 파이프라인에서 행렬과 4-벡터 연산을 통합하는 수학적으로 우아한 방법입니다.

물론 이 정규화를 직접 수행할 수도 있으며, 미리 컴파일된 표시 목록에 대해 토러스 형상이 한 번만 생성되므로 그렇게 하는 것이 더 효율적일 수 있습니다.

nx = x - b, ny = y, nz = z - zb;
nl = 1.0f / sqrtf(nx * nx + ny * ny + nz * nz);
glNormal3f(nx * nl, ny * nl, nz * nl);

반드시 확인하세요(nl) 0(또는 일부 엡실론)으로 나누는 경우 가능합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top