OpenGL diffuse/specular 光不在多边形上渲染(仅环境光​​)

OpenGL diffuse/specular light not rendering (only ambient) on polygons

我已经尽我所能设置了照明,但所有呈现的都是环境照明。它似乎适用于 glutSolidSphere 和 glutSolidCube 等内置形状,但不适用于我手动编码的多边形。

我花了几个小时查看教程和 Whosebug,但无法自行解决。

我错过了什么?我正在使用 Netbeans (Windows)、C++、FreeGlut。

图片:3D Airplane

#include <GL/glut.h>
#include <GL/glext.h>
​
GLfloat pos0 [] = {0,1,0,0},
        white[] = {1,1,1};
​
void render(){
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  glNormal3f(0,1,0);
  glScaled(4,4,4);
  glRotated(30,1,0,0);
  glRotated(60,0,1,0);
  glRotated(10,0,0,-1);
  glTranslated(0,0,-.2);
  glBegin(GL_QUADS);
    #define V glVertex3f
    // body
    glColor3f(.7,.5,.3);
    V(0,   0, 0); V(  1,.06,.05); V(  1,.10,.05); V(0, .15, 0);
    V(0,   0, 0); V(  1,.06,.05); V(  1,.05,.10); V(0,-.03,.1);
    V(0,-.03,.1); V(  1,.05,.10); V(  1,.06,.15); V(0,   0,.2);
    V(0,   0,.2); V(  1,.06,.15); V(  1,.10,.15); V(0, .15,.2);
    V(0, .15,.2); V(  1,.10,.15); V(  1,.11,.10); V(0, .17,.1);
    V(0, .17,.1); V(  1,.11,.10); V(  1,.10,.05); V(0, .15, 0);
    V(0,   0, 0); V(-.5,.03,.07); V(-.5,.06,.07); V(0, .15, 0);
    V(0,   0, 0); V(-.5,.03,.07); V(-.5,.02,.10); V(0,-.03,.1);
    V(0,-.03,.1); V(-.5,.02,.10); V(-.5,.03,.13); V(0,   0,.2);
    V(0,   0,.2); V(-.5,.03,.13); V(-.5,.06,.13); V(0, .15,.2);
    V(0, .15,.2); V(-.5,.06,.13); V(-.5,.07,.10); V(0, .17,.1);
    V(0, .17,.1); V(-.5,.07,.10); V(-.5,.06,.07); V(0, .15, 0);
    // wings
    glColor3f(.5,.5,.5);
    V(-.1,.06, .1); V(.3,.06, .1); V(.4,.10, .7); V( .2,.10, .7);
    V(-.1,.10, .1); V(.3,.10, .1); V(.4,.11, .7); V( .2,.11, .7);
    V(-.1,.06, .1); V(.2,.10, .7); V(.2,.11, .7); V(-.1,.10, .1);
    V( .3,.06, .1); V(.4,.10, .7); V(.3,.10, .1); V( .4,.11, .7);
    V( .4,.10, .7); V(.2,.10, .7); V(.4,.11, .7); V( .2,.11, .7);
    V(-.1,.06, .1); V(.3,.06, .1); V(.4,.10,-.5); V( .2,.10,-.5);
    V(-.1,.10, .1); V(.3,.10, .1); V(.4,.11,-.5); V( .2,.11,-.5);
    V(-.1,.06, .1); V(.2,.10,-.5); V(.2,.11,-.5); V(-.1,.10, .1);
    V( .3,.06, .1); V(.4,.10,-.5); V(.3,.10, .1); V( .4,.11,-.5);
    V( .4,.10,-.5); V(.2,.10,-.5); V(.4,.11,-.5); V( .2,.11,-.5);
    // tail
    V(.6,.06, .10); V(.8,.06, .10); V(.9,.10, .40); V(.8,.10, .40);
    V(.6,.10, .10); V(.8,.10, .10); V(.9,.11, .40); V(.8,.11, .40);
    V(.6,.06, .10); V(.8,.10, .40); V(.8,.11, .40); V(.6,.10, .10);
    V(.8,.06, .10); V(.9,.10, .40); V(.9,.11, .40); V(.8,.10, .10);
    V(.9,.10, .40); V(.8,.10, .40); V(.8,.11, .40); V(.9,.11, .40);
    V(.6,.06, .10); V(.8,.06, .10); V(.9,.10,-.20); V(.8,.10,-.20);
    V(.6,.10, .10); V(.8,.10, .10); V(.9,.11,-.20); V(.8,.11,-.20);
    V(.6,.06, .10); V(.8,.10,-.20); V(.8,.11,-.20); V(.6,.10, .10);
    V(.8,.06, .10); V(.9,.10,-.20); V(.9,.11,-.20); V(.8,.10, .10);
    V(.9,.10,-.20); V(.8,.10,-.20); V(.8,.11,-.20); V(.9,.11,-.20);
    V(.7,.10, .09); V(.9,.10, .09); V( 1,.30, .09); V(.9,.30, .09);
    V(.7,.10, .11); V(.9,.10, .11); V( 1,.30, .11); V(.9,.30, .11);
    V(.7,.10, .09); V(.9,.30, .09); V(.9,.10, .11); V(.7,.10, .11);
    V(.9,.10, .09); V( 1,.30, .09); V( 1,.30, .11); V(.9,.10, .11);
    V( 1,.30, .09); V(.9,.30, .09); V(.9,.30, .11); V( 1,.30, .11);
  glEnd();
  glFlush();
}
int main(int argc,char** argv){
  // setup window
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH|GLUT_MULTISAMPLE);
  glutInitWindowSize(800,600);
  glutCreateWindow("3D Airplane");
  glClearColor(0,0,0,1);

  // setup perspective
  glMatrixMode(GL_PROJECTION);
  glFrustum(-2,2, -1.5,1.5, 3,25);
  glMatrixMode(GL_MODELVIEW);
  gluLookAt(0,0,4, 0,0,0, 0,1,0);
  glViewport(0,0,800,600);
  glEnable(GL_DEPTH_TEST);

  // setup lighting
  glLightfv(GL_LIGHT0,GL_POSITION,pos0 );
  glLightfv(GL_LIGHT0,GL_DIFFUSE ,white);
  glEnable (GL_LIGHT0);
  glEnable (GL_LIGHTING);
  glEnable (GL_COLOR_MATERIAL);

  glutDisplayFunc(render);
  glutMainLoop();
}

编辑:我编写了一个名为 calcNormal 的法线计算函数,并将我的 glVertex 调用转换为四边形顶点数组...

GLfloat* calcNormal(GLfloat* a,GLfloat* b,GLfloat* c){
  // define target plane
  GLfloat u[] = {b[0]-a[0], b[1]-a[1], b[2]-a[2]};
  GLfloat v[] = {c[0]-a[0], c[1]-a[1], c[2]-a[2]};
  // calculate cross product
  static GLfloat cp[] = { u[1]*v[2] - u[2]*v[1], 
                          u[2]*v[0] - u[0]*v[2], 
                          u[0]*v[1] - u[1]*v[0] };
  // normalize
  GLfloat length = sqrt(cp[0]*cp[0] + cp[1]*cp[1] + cp[2]*cp[2]);
  for(int i=0;i<3;i++) cp[i] /= length;
  return cp;
}
render(){
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  glColor3f(.7,.5,.3);
  glPushMatrix();
  glScaled(3,3,3);
  glRotated(30,1,0,0);
  glRotated(60,0,1,0);
  glRotated(10,0,0,-1);
  glTranslatef(x,y,z);

  for(GLint* quad:planeQuads){
    #define PV planeVertices
    glNormal3fv(calcNormal(PV[quad[0]],PV[quad[1]],PV[quad[2]]));
    glBegin(GL_QUADS);
      glVertex3fv(PV[quad[0]]);
      glVertex3fv(PV[quad[1]]);
      glVertex3fv(PV[quad[2]]);
      glVertex3fv(PV[quad[3]]);
    glEnd();
  }
  glPopMatrix();
  glFlush();
}

...但它仍然没有渲染漫射光,即使我现在为每个多边形设置 glNormal。

我的 poly/vertex 结构现在看起来像这样:

// polygon arrays
GLint planeQuads[37][4] = {
  { 9,15,17,11}, { 9,15,14, 8}, { 8,14,16,10}, {10,16,18,12}, {12,18,19,13}, {13,19,17,11}, // rear body
  { 9, 1, 3,11}, { 9, 1, 0, 8}, { 8, 0, 2,10}, {10, 2, 4,12}, {12, 4, 5,13}, {13, 5, 3,11}, // front body
  { 6,17,20,14}, { 7,19,22,16}, { 6,14,16, 7}, {17,20,19,22}, {20,14,22,16}, // left wing
  { 6,17,23,18}, { 7,19,21,15}, { 6,18,17, 7}, {17,23,19,21}, {23,18,21,15}, // right wing
  {24,28,37,31}, {25,30,39,33}, {24,31,33,25}, {28,37,39,30}, {37,31,33,39}, // left fin
  {24,28,34,29}, {25,30,38,32}, {24,29,32,25}, {28,34,38,30}, {34,29,32,38}, // right fin
  {26,35,48,40}, {27,36,49,41}, {26,40,36,27}, {35,48,49,36}, {48,40,41,49}  // tail
};

// vertex arrays
GLfloat planeVertices[50][3] = {
  {-.5,0.02,0.10}, {-.5,0.03,0.07}, {-.5,0.03,0.13}, {-.5,0.06,0.07}, {-.5,0.06,0.13},
  {-.5,0.07,0.10}, {-.1,0.06,0.10}, {-.1,0.10,0.10}, {0.0,-.03,0.10}, {0.0,0.00,0.00},
  {0.0,0.00,0.20}, {0.0,0.15,0.00}, {0.0,0.15,0.20}, {0.0,0.17,0.10}, {0.2,0.10,-.50},
  {0.2,0.10,0.70}, {0.2,0.11,-.50}, {0.2,0.11,0.70}, {0.3,0.06,0.10}, {0.3,0.10,0.10},
  {0.4,0.10,-.50}, {0.4,0.10,0.70}, {0.4,0.11,-.50}, {0.4,0.11,0.70}, {0.6,0.06,0.10},
  {0.6,0.10,0.10}, {0.7,0.10,0.09}, {0.7,0.10,0.11}, {0.8,0.06,0.10}, {0.8,0.10,-.20},
  {0.8,0.10,0.10}, {0.8,0.10,0.40}, {0.8,0.11,-.20}, {0.8,0.11,0.40}, {0.9,0.10,-.20},
  {0.9,0.10,0.09}, {0.9,0.10,0.11}, {0.9,0.10,0.40}, {0.9,0.11,-.20}, {0.9,0.11,0.40},
  {0.9,0.30,0.09}, {0.9,0.30,0.11}, {1.0,0.05,0.10}, {1.0,0.06,0.05}, {1.0,0.06,0.15},
  {1.0,0.10,0.05}, {1.0,0.10,0.15}, {1.0,0.11,0.10}, {1.0,0.30,0.09}, {1.0,0.30,0.11}
};

如果将唯一的法向量形式 glNormal3f(0,1,0) 更改为 glNormal3f(0,-1,0),这会使场景变暗,您可以看到您的设置总体上有效。

但是,您必须设置垂直于几何体的面(甚至顶点)的法向量。所以你必须为每个面或顶点坐标设置一个法向量。

漫射光是通过Dot product的光向量和mesh的法向量属性计算出来的。对于定向光,整个场景的光向量是相同的。如果法向量对于整个几何体是恒定的,那么点积的结果对于整个几何体也是恒定的,因此光也是。
另见 GLSL fixed function fragment program replacement


您的代码中存在一个基本错误。静态变量只初始化一次:

static GLfloat cp[] = { u[1]*v[2] - u[2]*v[1], 
                       u[2]*v[0] - u[0]*v[2], 
                       u[0]*v[1] - u[1]*v[0] };

每次调用函数时都必须为变量赋值:

static GLfloat cp[3];
cp[0] = u[1]*v[2] - u[2]*v[1]; 
cp[1] = u[2]*v[0] - u[0]*v[2]; 
cp[2] = u[0]*v[1] - u[1]*v[0];  

计算法向量时,必须确保法向量指向网格外。 反转法向量以查看向量的方向如何影响光线。

GLfloat* calcNormal(GLfloat* a,GLfloat* b,GLfloat* c){
    // define target plane
    GLfloat u[] = {b[0]-a[0], b[1]-a[1], b[2]-a[2]};
    GLfloat v[] = {c[0]-a[0], c[1]-a[1], c[2]-a[2]};
    // calculate cross product
    static GLfloat cp[3];
    cp[0] = u[1]*v[2] - u[2]*v[1]; 
    cp[1] = u[2]*v[0] - u[0]*v[2]; 
    cp[2] = u[0]*v[1] - u[1]*v[0];
    // normalize
    GLfloat length = sqrt(cp[0]*cp[0] + cp[1]*cp[1] + cp[2]*cp[2]);
    for(int i=0;i<3;i++) cp[i] /= -length; // <- invert the normal vector
    return cp;
}

由于法向量是通过三角形图元两条边的叉积计算的,法向量的方向取决于图元的缠绕顺序。这意味着所有基元的缠绕顺序必须相同。


如果缠绕顺序不同,这意味着一些原语是顺时针的而另一些是逆时针的,那么你可以尝试通过设置来补偿这个(参见glLightModel

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

在这种情况下,正面和背面的 material 参数必须相等。 (参见 glMaterial)。