Question

J'ai un programme OpenGL exécuté et affiche la géométrie, mais tout est tout "plat", un ton gris, sans ombrage diffus ou réflexion spéculaire:

Tori sans ombrage

La photo est trois Tori, chacune de quadriques. Nous devrions voir l'ombrage, mais nous ne le faisons pas. Qu'est-ce que je fais mal?

Voici le code où je définit les sommets et les normales (draw_torus() est appelé pour créer une liste d'affichage):

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

Y a-t-il quelque chose qui ne va pas avec l'ordre des sommets?

Voici la partie de la fonction init où la liste d'affichage est construite:

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

où setmaterial () fait juste:

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] */
}

Voici l'éclairage qui est également fait lors de l'initialisation:

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

Voici l'endroit où la liste d'affichage est appelée, dans la fonction de tirage:

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

Le fichier source complet de cette "HACK" est ici . Si cela fait une différence, ce code est dans le contexte de XScreensaver .

Était-ce utile?

La solution

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top