OpenGL中的光照技術(翻譯)


Lighting:https://www.evl.uic.edu/julian/cs488/2005-11-03/index.html

光照

OpenGL中的光照(Linghting)是很重要的,為什么重要?請看下圖

上圖中左圖是有光照的效果,右圖是沒有光照的效果。

有光照的好處:

  • 給人更多關於曲率和深度的視覺感受
  • 給人更明顯的3D效果

 

隱藏面清除

在照明和着色中,深度信息和法向量變得非常重要。

舊的painter算法是這樣的:

while (1) {

get_viewing_point_from_mouse_position();

glClear(GL_COLOR_BUFFER_BIT);

draw_3d_object_A();

draw_3d_object_B();

}

這樣的話,一個對象可能會遮擋另一個對象

隱藏面清除通過使用Z-buffer(深度緩存)來實現

 

請看如下的代碼示例:

glutInitDisplayMode ( GLUT_DEPTH | ... );

glEnable ( GL_DEPTH_TEST );

...

while(1) {

glClear( GLCOLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

get_viewing_point_from_mouse_position();

draw_3d_object_A();

draw_3d_object_B();

}

 

光照組成

  • 環境光(Ambient

    光從各個方向均勻地到達。事實上,光散射太大,我們無法確定它的方向

  • 散射光(Diffuse

    來自點光源的光線將被漫射反射(即在遠離表面的所有方向上均勻地重新選擇)

  • 鏡面光(Specular

    從點光源發出的光線將被鏡面反射(即以鏡面形式反射,如從光亮的表面反射)。

    

  •     放射光(Emissive

    在沒有入射光的情況下,表面的發射率控制着表面發出的光的數量。從一個表面發出的光不能作為照亮其他表面的光源;相反,它只影響觀察者看到的顏色。

多個燈光組件結果

    

 

光照和材料的RGB

    RGB values for light and material have different meanings

    For light: light colors(intensities)

    (R, G, B) = (1, 1, 0) -> yellow light

    For material: reflected proportions

 (R, G, B) = (1, 0.5, 0) -> the material reflects all the incoming red light, half the incoming green light, and nonn of the incoming blue light.

    ( LR*MR, LG*MG, LB*MB )

    Multiple light source: Light1 + Light2

    ( R1+R2, G1+G2, B1+B2 )

    If the result is greater than 1.0, clamp to 1.0

 

光照例子    

為所有對象的每個頂點定義法向量。這些法線確定對象相對於光源的方向。(在我們的示例中,法線定義為glutsolidSphere()的一部分)

  • Needs unit normal vector
  • void glEnable(GL_NORMALIZE)
  • void glEnable(GL_RESCALE_NORMAL)

Create, select, and position one or more light sources.

可以創建最多8中不同的光源(GL_LIGHT0 to GL_LIGHT7),但是光源多了會導致更多的計算復雜性。

創建並選擇照明模型Light Mode),該模型定義全局環境光的級別和視點的有效位置(用於照明計算)。

為場景中的對象定義材質屬性。

 

#include <gl/glut.h>

#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")

 

/* Initialize material property, light source, lighting model,

* and depth buffer.

*/

void init(void)

{

GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };

GLfloat mat_shininess[] = { 50.0 };

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

GLfloat light[] = { 1.0, 0.2, 0.2 };

GLfloat lmodel_ambient[] = { 0.1, 0.1, 0.1, 1.0 };

glClearColor (0.0, 0.0, 0.0, 0.0);

glShadeModel (GL_SMOOTH);

 

glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);

glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

 

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glLightfv(GL_LIGHT0, GL_DIFFUSE, light );

glLightfv(GL_LIGHT0, GL_SPECULAR, light );

glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);

 

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glEnable(GL_DEPTH_TEST);

}

 

void display(void)

{

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glutSolidSphere (1.0, 20, 16);

glFlush ();

}

 

void reshape (int w, int h)

{

glViewport (0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity();

if (w <= h)

glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,

1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);

else

glOrtho (-1.5*(GLfloat)w/(GLfloat)h,

1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

 

int main(int argc, char** argv)

{

glutInit(&argc, argv);

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

glutInitWindowSize (500, 500);

glutInitWindowPosition (100, 100);

glutCreateWindow (argv[0]);

init ();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutMainLoop();

return 0;

}

 

 

光照API

void glLight{if}(GLenum light, GLenum pname, TYPE param);

void glLight{if}v(GLenum light, GLenum pname, TYPE *param);

Creates the light specified by light, which can be GL_LIGHT0, GL_LIGHT1, ... , or GL_LIGHT7. The characteristic of the light being set is defined by pname, which specifies a named parameter (see Table below). param indicates the values to which the pname characteristic is set; it's a pointer to a group of values if the vector version is used, or the value itself if the nonvector version is used. The nonvector version can be used to set only single-valued light characteristics.

 

衰減(定義光衰減的強度)

對於現實世界中的燈光,燈光強度隨着與燈光的距離的增加而降低。由於定向光無限遠,因此在距離上衰減其強度是沒有意義的,因此對定向光禁用衰減。但是,您可能希望減弱來自位置光的光。OpenGL通過將光源的貢獻乘以衰減因子來衰減光源:

d = distance between the light's position and the vertex

kc = GL_CONSTANT_ATTENUATION

kl = GL_LINEAR_ATTENUATION

kq = GL_QUADRATIC_ATTENUATION

By default, kc = 1.0, kl = kq = 0.0.

可以為這些參數指定不同的值:

    glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0); 
    glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0); 
    glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5); 

 

聚光燈(默認gl_spot_cutoff=180

glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0); 

GLfloat spot_direction[] = { -1.0, -1.0, 0.0 }; 

glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);

 

        

可以設置多個光源

GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; 
GLfloat light1_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; 
GLfloat light1_specular[] = { 1.0, 1.0, 1.0, 1.0 }; 
GLfloat light1_position[] = { -2.0, 2.0, 1.0, 1.0 }; 
GLfloat spot_direction[] = { -1.0, -1.0, 0.0 }; 

 

glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient); 
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse); 
glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular); 
glLightfv(GL_LIGHT1, GL_POSITION, light1_position); 
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5); 
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5); 
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.2); 

 

glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0); 
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction); 
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.0); 

 

glEnable(GL_LIGHT1); 

 

 

光源位置(Position)

  • 定向光——光源無限遠(W=0
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; 
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
位置的第四個分量是0.0,表示光是定向光。
默認情況下,GL_POSITION是(0010),它定義了方向光。(xyz)是它的方向。
  • 位置光——有限距離光源(W不是0

 GLfloat light_position[] = { 5.0, 10.0, 2.0, 1.0 }; 
 glLightfv(GL_LIGHT0, GL_POSITION, light_position);

 位置由模型視圖矩陣轉換並存儲在眼睛坐標系中(即相對於眼睛)。

 請注意,默認情況下(即不調用gluLookat()),相機(眼睛)位於原點,指向負Z軸。

 默認情況下,位置光源向所有方向輻射。

 

移動光源

  • 固定光源

glViewport (0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity();

if (w <= h)

  glOrtho (-1.5, 1.5, -1.5*h/w, 1.5*h/w, -10.0, 10.0);

else

  glOrtho (-1.5*w/h, 1.5*w/h, -1.5, 1.5, -10.0, 10.0);

glMatrixMode (GL_MODELVIEW);

glLoadIdentity();

/* later in init() */

GLfloat light_position[] = { 1.0, 1.0, 1.0, 1.0 };

glLightfv(GL_LIGHT0, GL_POSITION, position);

 

  • 光源的獨立移動

旋轉或平移燈光位置:燈光相對於靜止物體移動。

static GLdouble spin;

void display(void)

{

GLfloat light_position[] = { 0.0, 0.0, 1.5, 1.0 };

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 

glPushMatrix();

gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

glPushMatrix();

glRotated(spin, 1.0, 0.0, 0.0);

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glPopMatrix();

glutSolidTorus (0.275, 0.85, 8, 15);

glPopMatrix();

glFlush();

}

 

        

 

通過模型變換(Model)來移動光源例子:

#include <GL/glut.h> 

#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")

static int spin = 0;

void init(void)

{

  glClearColor (0.0, 0.0, 0.0, 0.0);

  glShadeModel (GL_SMOOTH);

  glEnable(GL_LIGHTING);

  glEnable(GL_LIGHT0);

  glEnable(GL_DEPTH_TEST);

}

 

/* Here is where the light position is reset after the modeling

* transformation (glRotated) is called. This places the

* light at a new position in world coordinates. The cube

* represents the position of the light.

*/

void display(void)

{

GLfloat position[] = { 0.0, 0.0, 1.5, 1.0 };

 

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix ();

glTranslatef (0.0, 0.0, -5.0);

 

glPushMatrix ();

glRotated ((GLdouble) spin, 1.0, 0.0, 0.0);

glLightfv (GL_LIGHT0, GL_POSITION, position);

 

glTranslated (0.0, 0.0, 1.5);

glDisable (GL_LIGHTING);

glColor3f (0.0, 1.0, 1.0);

glutWireCube (0.1);                    // 模擬光源

glEnable (GL_LIGHTING);

glPopMatrix ();

 

glutSolidTorus (0.275, 0.85, 8, 15);

glPopMatrix ();

glFlush ();

}

 

void reshape (int w, int h)

{

glViewport (0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity();

gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

 

void mouse(int button, int state, int x, int y)

{

switch (button) {

case GLUT_LEFT_BUTTON:

if (state == GLUT_DOWN) {

spin = (spin + 30) % 360;

glutPostRedisplay();

}

break;

default:

break;

}

}

int main(int argc, char** argv)

{

glutInit(&argc, argv);

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

glutInitWindowSize (500, 500);

glutInitWindowPosition (100, 100);

glutCreateWindow (argv[0]);

init ();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutMouseFunc(mouse);

glutMainLoop();

return 0;

}

    光源隨視點移動

  要創建隨視點移動的燈光,需要在查看轉換之前設置燈光位置。

  然后觀察變換以同樣的方式影響光和視點。

  記住燈光位置存儲在眼睛坐標中。

  

光源隨視點移動

GLfloat light_position[] = { 0.0, 0.0, 0.0, 1.0 };

glViewport(0, 0, (GLint) w, (GLint) h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

如果現在移動視點,燈光將隨之移動,相對於眼睛保持(0,0,0)距離。

//viewpoint參數,可改變

static GLdouble ex, ey, ez, upx, upy, upz;

void display(void)

{

  glClear(GL_COLOR_BUFFER_MASK | GL_DEPTH_BUFFER_MASK);

  glPushMatrix();

  gluLookAt (ex, ey, ez, 0.0, 0.0, 0.0, upx, upy, upz);

  glutSolidTorus (0.275, 0.85, 8, 15);

  glPopMatrix();

  glFlush();

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM