OpenGL實例:紋理映射
作者:凱魯嘎吉 - 博客園 http://www.cnblogs.com/kailugaji/
更多請查看:計算機圖形學
1. 介紹
用於指定一維、二維和三維紋理的函數分別為:
Void glTexImage1D(GLenum target, Glint level, Glint components, GLsizei width, Glint border, GLenum format, GLenum type, const GLvoid *texels); Void glTexImage2D(GLenum target, Glint level, Glint components, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *texels); Void glTexImage3D(GLenum target, Glint level, Glint components, GLsizei width, GLsizei height, GLsizei depth, Glint border, GLenum format, GLenum type, const GLvoid *texels);
其中,參數target取值一般為GL_TEXTURE_1D, GL_TEXTURE_2D和GL_TEXTURE_3D,分別與一維、二維和三維的紋理相對應。參數Level表示紋理多分辨率層數,通常取值為0,表示只有一種分辨率。參數components的可能取值為1~4的整數以及多種符號常量(如GL_RGBA),表示紋理元素中存儲的哪些分量(RGBA顏色、深度等)在紋理映射中被使用,1表示使用R顏色分量,2表示使用R和A顏色分量,3表示使用RGB顏色分量,4表示使用RGBA顏色分量。參數width,height,depth分別指定紋理的寬度、高度、深度。參數format和type表示給出的圖像數據的數據格式和數據類型,這兩個參數的取值都是符號常量(比如format指定為GL_RGBA,type指定為GL_UNSIGNED_BYTE,參數texels指向內存中指定的紋理圖像數據。
在定義了紋理之后,需要啟用紋理的函數:
glEnable(GL_TEXTURE_1D); glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_3D);
在啟用紋理之后,需要建立物體表面上點與紋理空間的對應關系,即在繪制基本圖元時,在glVertex函數調用之前調用glTexCoord函數,明確指定當前頂點所對應的紋理坐標,例如:
glBegin(GL_TRIANGLES); glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex2f(15.0, 15.0); glTexCoord2f(1.0, 0.0); glVertex2f(30.0, 0.0); glEnd();
其圖元內部點的紋理坐標利用頂點處的紋理坐標采用線性插值的方法計算出來。
在OpenGL中,紋理坐標的范圍被指定在[0,1]之間,而在使用映射函數進行紋理坐標計算時,有可能得到不在[0,1]之間的坐標。此時OpenGL有兩種處理方式,一種是截斷,另一種是重復,它們被稱為環繞模式。在截斷模式(GL_CLAMP)中,將大於1.0的紋理坐標設置為1.0,將小於0.0的紋理坐標設置為0.0。在重復模式(GL_REPEAT)中,如果紋理坐標不在[0,1]之間,則將紋理坐標值的整數部分舍棄,只使用小數部分,這樣使紋理圖像在物體表面重復出現。例如,使用下面的函數:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
分別指定二維紋理中s坐標采用截斷或重復處理方式。
另外,在變換和紋理映射后,屏幕上的一個像素可能對應紋理元素的一小部分(放大),也可能對應大量的處理元素(縮小)。在OpenGL中,允許指定多種方式來決定如何完成像素與紋理元素對應的計算方法(濾波)。比如,下面的函數可以指定放大和縮小的濾波方法:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
其中,glTexParameteri函數的第一個參數指定使用的是一維、二維或三維紋理;第二個參數為GL_TEXTURE_MAG_FILTER或GL_TEXTURE_MIN_FILTER,指出要指定縮小還是放大濾波算法;最后一個參數指定濾波的方法。
補充:透視投影函數
void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
它也創建一個對稱透視視景體,但它的參數定義於前面的不同。其操作是創建一個對稱的透視投影矩陣,並且用這個矩陣乘以當前矩陣。參數fovy定義視野在X-Z平面的角度,范圍是[0.0,180.0];參數aspect是投影平面寬度與高度的比率;參數zNear和Far分別是遠近裁剪面沿Z負軸到視點的距離,它們總為正值。
2. 實例一
#include <GL/glut.h> #include <cstdlib> #include <cstdio> #include <cmath> #define stripeImageWidth 32 GLubyte stripeImage[4 * stripeImageWidth]; // create 2D texture void makeStripeImage(void) { int j; for (j = 0; j < stripeImageWidth; j++) { stripeImage[4 * j + 0] = (GLubyte)((j <= 4) ? 255 : 0); stripeImage[4 * j + 1] = (GLubyte)((j > 4) ? 255 : 0); stripeImage[4 * j + 2] = (GLubyte)0; stripeImage[4 * j + 3] = (GLubyte)255; } } static GLfloat xequalzero[] = { 1.0, 1.0, 1.0, 1.0 }; static GLfloat slanted[] = { 1.0, 1.0, 1.0, 1.0 }; static GLfloat *currentCoeff; static GLenum currentPlane; static GLint currentGenMode; static float roangles; void init(void) { glClearColor(1.0, 1.0, 1.0, 1.0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); makeStripeImage(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage1D(GL_TEXTURE_1D, 0, 4, stripeImageWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); currentCoeff = xequalzero; currentGenMode = GL_OBJECT_LINEAR; currentPlane = GL_OBJECT_PLANE; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, currentGenMode); glTexGenfv(GL_S, currentPlane, currentCoeff); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_1D); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glMaterialf(GL_FRONT, GL_SHININESS, 64.0); roangles = 45.0f; } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(roangles, 0.0, 0.0, 1.0); glutSolidSphere(2.0, 32, 32); glPopMatrix(); glFlush(); }; void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-3.5, 3.5, -3.5*(GLfloat)h / (GLfloat)w, 3.5*(GLfloat)h / (GLfloat)w, -3.5, 3.5); else glOrtho(-3.5*(GLfloat)w / (GLfloat)h, 3.5*(GLfloat)w / (GLfloat)h, -3.5, 3.5, -3.5, 3.5); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void idle() { roangles += 0.05f; glutPostRedisplay(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(256, 256); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); glutIdleFunc(idle); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; }
結果:
3. 實例二
#include <GL/glut.h> #include <cstdlib> #include <cstdio> #include <cmath> #define stripeImageWidth 32 #define stripeImageHeight 32 GLubyte stripeImage[stripeImageWidth][stripeImageHeight][4]; void makeStripeImage(void) { int i, j; for (i = 0; i < stripeImageWidth; i++) { for (j = 0; j < stripeImageHeight; j++) { stripeImage[i][j][0] = (GLubyte)(i * 7 - 1); stripeImage[i][j][1] = (GLubyte)(j * 4 - 1); stripeImage[i][j][2] = (GLubyte)50; stripeImage[i][j][3] = (GLubyte)255; } } } static GLfloat xequalzero[] = { 1.0, 1.0, 1.0, 1.0 }; static GLfloat slanted[] = { 1.0, 1.0, 1.0, 1.0 }; static GLfloat *currentCoeff; static GLenum currentPlane; static GLint currentGenMode; static float roangles; void init(void) { glClearColor(1.0, 1.0, 1.0, 1.0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); makeStripeImage(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, 4, stripeImageWidth, stripeImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); currentCoeff = xequalzero; currentGenMode = GL_OBJECT_LINEAR; currentPlane = GL_OBJECT_PLANE; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, currentGenMode); glTexGenfv(GL_S, currentPlane, currentCoeff); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glMaterialf(GL_FRONT, GL_SHININESS, 64.0); roangles = 60.0f; //光照 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 white_light[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat Light_Model_Ambient[] = { 0.2, 0.2, 0.2, 1.0 }; 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, white_light); //建立光源 (漫反射光分量強度) glLightfv(GL_LIGHT0, GL_SPECULAR, white_light); //建立光源 (折射光分量強度) glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Light_Model_Ambient); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(roangles, 0.0, 1.0, 0.0); glutSolidSphere(3.0, 32, 32); glPopMatrix(); glFlush(); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-3.5, 3.5, -3.5*(GLfloat)h / (GLfloat)w, 3.5*(GLfloat)h / (GLfloat)w, -3.5, 3.5); else glOrtho(-3.5*(GLfloat)w / (GLfloat)h, 3.5*(GLfloat)w / (GLfloat)h, -3.5, 3.5, -3.5, 3.5); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void idle() { roangles += 0.05f; glutPostRedisplay(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(256, 256); glutInitWindowPosition(100, 100); glutCreateWindow("balloon"); glutIdleFunc(idle); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; }
結果: