2012-03-10 62 views
2

我有一个OpenGL程序运行,并显示几何形状,但它的所有“平”,一个灰色调,没有漫反射阴影或镜面反射:为什么我的漫反射/镜面照明不起作用?

Tori with no shading

图为三托里,各由四条带组成。我们应该看到阴影,但我们不知道。我究竟做错了什么?

这里是我设置的顶点和法线(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源文件是here。如果它有所作为,则此代码位于xscreensaver的上下文中。

+1

我打算理所当然地认为环面法线是正确的;四边形的缠绕顺序是什么?你需要使用'glFrontFace(mode)'将前置四边形设置为'GL_CW'还是'GL_CCW'?另外,法线的单位长度是多少? 'glEnable(GL_NORMALIZE)'或'putVert'中的DIY。 – 2012-03-10 17:28:06

+0

@BrettHale:嘿,我试过'glEnable(GL_NORMALIZE)',现在我得到了阴影!谢谢!把它放在答案中,我可以接受它!另外,我很好奇为什么这会产生变化。根据http://www.opengl.org/sdk/docs/man/xhtml/glNormal.xml,“用glNormal指定的法线不需要具有单位长度”。 – LarsH 2012-03-11 02:08:40

回答

2

拉尔斯,正如你所看到的,glEnable(GL_NORMALIZE)规范化(惊喜)用于照明计算(固定功能管线)转换之前的法向量。这些计算依赖于单位长度法线来获得正确的结果。

值得指出的是,应用于法向矢量的变换是而不是,与应用于顶点几何的变换相同。 OpenGL 2.1规范描述了转换,许多other资源。作为一个向量,法线具有齐次表示:[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)除以零(或某个epsilon),如果这是一种可能性。

+0

谢谢。我可以自己进行规范化,然后使用'glEnable(GL_RESCALE_NORMAL)',因为我在各个地方使用统一缩放。 – LarsH 2012-03-11 04:36:58

相关问题