3

私は OpenGL プログラムを実行しており、ジオメトリを表示していますが、すべて「フラット」で、1 つの灰色のトーンであり、拡散シェーディングや鏡面反射はありません。

陰影なしの鳥居

写真は 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);

draw 関数で表示リストが呼び出される場所は次のとおりです。

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 ハック」の完全な .c ソース ファイルはこちらです。違いが生じる場合に備えて、このコードはxscreensaverのコンテキストにあります。

4

1 に答える 1

4

ご覧のとおり、ライティングの計算に使用される変換の後に法線ベクトルをglEnable(GL_NORMALIZE) 正規化します (固定関数パイプラインで)。これらの計算は、正しい結果を得るために単位長法線に依存しています。

法線ベクトルに適用される変換は、頂点ジオメトリに適用される変換と同じではないことに注意してください。OpenGL 2.1 仕様は、他の多くのリソースと同様に、変換について説明しています。ベクトルとして、法線は均一な表現を持ちます: [nx, ny, nz, 0]- 「無限」の点、および GL パイプラインで行列と 4 ベクトル操作を統合する数学的に洗練された方法。

もちろん、この正規化を自分で実行することもできます。トーラス ジオメトリはコンパイル済みの表示リストに対して 1 回しか生成されないため、その方が効率的です。

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可能な場合は、( ) がゼロ (またはいくつかのイプシロン) で除算されていることを確認してください。

于 2012-03-11T04:16:16.030 に答える