Почему мое диффузное / зеркальное освещение не работает?

StackOverflow https://stackoverflow.com//questions/9644238

  •  10-12-2019
  •  | 
  •  

Вопрос

У меня работает программа OpenGL, и она отображает геометрию, но это все «квартиру», один серый тон, без диффузного затенения или зеркального отражения:

Tori без затенения

На фото три торы, каждый из которых из четырех полос. Мы должны увидеть затенение, но мы не делаем. Что я делаю не так?

Вот код, в котором я устанавливаю вершины и нормали (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);
.

Полный исходный файл .c для этого «HALK GLX» - здесь . В случае, если это имеет значение, этот код находится в контексте xscreensaver .

Это было полезно?

Решение

Lars, as you've seen, glEnable(GL_NORMALIZE) normalizes (surprise) the normal vectors prior to the transformations used for lighting calculations (in fixed-function pipelines). These calculations rely on unit length normals for correct results.

It's worth pointing out that the transforms applied to normal vectors are not the same as the transforms applied to vertex geometry. The OpenGL 2.1 specification describes the transform, as do many other resources. As a vector, a normal has the homogeneous representation: [nx, ny, nz, 0] - a point at 'infinity', and a mathematically elegant way to unify matrix and 4-vector operations in the GL pipeline.

Of course, you could perform this normalization yourself, and it may be more efficient to do so, as your torus geometry is only generated once for a pre-compiled display list:

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

Be sure to check (nl) for division by zero (or some epsilon), if that's a possibility.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top