2012-03-10 60 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

相關問題