OpenGL的紋理組合器能夠控制多重紋理的片斷是如何組合的。通常狀況下,咱們能夠簡單的爲每一個紋理單元設置一個紋理環境模式(GL_REPLACE,GL_DECAL,GL_ADD和GL_MODULATE),把每一個紋理應用的結果添加到下一個紋理單元中。然而紋理組合器提供了一個新的紋理環境GL_COMBINE容許咱們顯示地控制每個紋理單元的紋理片斷是如何組合的。使用紋理組合器模式代碼以下: html
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); app
紋理組合器是經過glTexEnv函數來控制的。而後咱們須要設置使用哪一個紋理組合器的函數。glTexEnv函數的第二個參數是組合器函數的選擇器,能夠是GL_COMBINE_RGB或GL_COMBINE_ALPHA。第三個參數是你想使用的紋理環境函數。這個參數值以下表: 函數
常量 | 函數 |
GL_REPLACE | Arg0 |
GL_MODULATE | Arg0 * Arg1 |
GL_ADD | Arg0 + Arg1 |
GL_ADD_SIGNED | Arg0 + Arg1 – 0.5 |
GL_INTERPOLATE | (Arg0 * Arg2) + (Arg1 * (1-Arg2)) |
GL_SUBTRACT | Arg0 - Arg1 |
GL_DDT3_RGB/GL_DDT3_RGBA | 4*((Arg0r-0.5)*(Arg1r-0.5)+(Arg0g-0.5)*(Arg1g-0.5)+(Arg0b-0.5)*(Arg1b-0.5)) |
例如你給RGB值選擇GL_REPLACE組合器,你的函數調用以下: oop
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); 性能
上表中的Arg0——Arg2經過更多的glTexEnv調用來設置。GL_SOURCEx_RGB和GL_SOURCEx_ALPHA值用於指定RGB和alpha組合器函數的參數,x能夠是0,1或者2,這些來源的值以下表: ui
常量 | 描述 |
GL_TEXTURE | 來源於當前綁定的紋理單元 |
GL_TEXTUREx | 來源於綁定的紋理x |
GL_CONSTANT | 顏色值或aplha值來源於經過GL_TEXTURE_ENV_COLOR參數設置的值 |
GL_PRIMARY_COLOR | 來源於原幾何圖形片斷 |
GL_PREVIOUS | 來源於前一個紋理單元的紋理環境的結果 |
例:你設置Arg0爲紋理單元0 spa
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0); .net
咱們還能夠對給定的源值施加額外的控制。設置這些操做數,咱們可使用常量GL_OPERANDx_RGB或者GL_OPERANDx_ALPHA,x能夠是0,1或者2,能夠給這些操做數賦予的值以下表: 3d
常量 | 描述 |
GL_SRC_COLOR | 源顏色值,不能用於GL_OPERANDx_ALPHA |
GL_ONE_MINUS_SRC_COLOR | 源顏色值的反碼(1-value)不能用於GL_OPERANDx_ALPHA |
GL_SRC_ALPHA | 源alpha值 |
GL_ONE_MINUS_SRC_ALPHA | 源alpha值的反碼(1-value) |
例如你已經在兩個紋理單元中加載了兩個紋理,你在應用紋理時,想要把兩個紋理的顏色值相乘,你能夠以下設置: code
//設置紋理環境爲紋理組合
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
//告訴OpenGL,對RGB值使用組合函數GL_MODULATE
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
//設置arg0爲第0個紋理單元
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
//設置arg1爲紋理單元1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR):
咱們還能夠爲紋理組合器,指定一個RGB或alpha的縮放因子。默認狀況下是:
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.0f);
glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0f);
點精靈的特性是OpenGl1.5開始引入的。使用點精靈,咱們能夠經過繪製一個3D的點來把紋理圖像映射的屏幕上。例如本來是一個矩形的幾何圖元(由四個頂點組成),而後再把2D的紋理映射到這個矩形上才能獲得的效果,如今使用點精靈則只須要繪製一個3D的點就能夠了。這減小了處理器須要處理的頂點,也減小了頂點傳輸的帶寬,提升了性能。
例如,大量的微粒在屏幕上移動造成魔幻般的視覺效果,能夠經過點精靈來實現(常見的屏幕保護程序)。
在點精靈以前,要實現這種效果,咱們須要在屏幕上繪製大量的紋理多邊形,並須要經過對多邊形進行旋轉,以確保它面對這照相機。而點精靈紋理容許咱們繪製一個3D的頂點,來渲染一個完美對齊的紋理2D多邊形。
點精靈很是容易使用,開啓點精靈GL_POINT_SPRITE,設置紋理環境的目標位GL_POINT_SPRITE 的GL_COORD_REPLACE參數爲真,發送3D點。
glBindTexture(GL_TEXTURE_2D, objectID);
glEnable(GL_POINT_SPRITE);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glBegin(GL_POINTS);
…
glEnd();
把以前第六章的smooth樣例進行修改,使用點精靈的方式來繪製,代碼以下:
#include "gltools.h" #include <math.h> #include "math3d.h" //屏幕的寬,高 #define SCREEN_X 800 #define SCREEN_Y 600 //大中小星星的數量 #define LARGE_NUM 20 #define MEDIUM_NUM 30 #define SMALL_NUM 40 //星星的座標 M3DVector2f smallStars[SMALL_NUM]; M3DVector2f mediumStars[MEDIUM_NUM]; M3DVector2f largeStars[LARGE_NUM]; #define TEXNUM 2 #define STAR 0 #define MOON 1 GLuint textureObj[TEXNUM]; void ProcessMenu(int value); void ChangeSize(GLsizei w, GLsizei h) { if (h == 0) h = 1; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); //設置爲2D的正投影,使得座標從屏幕的左下角開始 gluOrtho2D(0.0, SCREEN_X, 0.0, SCREEN_Y); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glutPostRedisplay(); } void SetupRC() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //隨機獲取星星的位置 for (int i = 0; i < SMALL_NUM; ++i) { smallStars[i][0] = (GLfloat)(rand() % SCREEN_X); smallStars[i][1] = (GLfloat)(rand() % SCREEN_Y); } for (int i = 0; i < MEDIUM_NUM; ++i) { mediumStars[i][0] = (GLfloat)(rand() % SCREEN_X); mediumStars[i][1] = (GLfloat)((rand() % SCREEN_Y) + 50); } for (int i = 0; i < LARGE_NUM; ++i) { largeStars[i][0] = (GLfloat)(rand() % SCREEN_X); largeStars[i][1] = (GLfloat)(rand() % SCREEN_Y); } GLint iWidth, iHeight, iComponents; GLenum eFormat; //生成紋理對象 glGenTextures(TEXNUM, textureObj); //加載紋理圖片 glBindTexture(GL_TEXTURE_2D, textureObj[STAR]); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); void *pImage = gltLoadTGA("..\\images\\star.tga", &iWidth, &iHeight, &iComponents, &eFormat); if (pImage) { glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pImage); free(pImage); pImage = NULL; } glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_2D, textureObj[MOON]); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); pImage = gltLoadTGA("..\\images\\moon.tga", &iWidth, &iHeight, &iComponents, &eFormat); if (pImage) { glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pImage); free(pImage); pImage = NULL; } glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); //啓用點精靈 glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); glEnable(GL_POINT_SPRITE); ProcessMenu(3); } void RenderScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0f, 1.0f, 1.0f); //綁定紋理,使用點精靈 glBindTexture(GL_TEXTURE_2D, textureObj[STAR]); glEnable(GL_POINT_SPRITE); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); //畫小星星 glPointSize(7.0); glBegin(GL_POINTS); for (int i = 0; i < SMALL_NUM; ++i) glVertex2fv(smallStars[i]); glEnd(); //畫中等大小的星星 glPointSize(12.0); glBegin(GL_POINTS); for (int i = 0; i < MEDIUM_NUM; ++i) { glVertex2fv(mediumStars[i]); } glEnd(); //大星星 glPointSize(20.0); glBegin(GL_POINTS); for (int i = 0; i < LARGE_NUM; ++i) { glVertex2fv(largeStars[i]); } glEnd(); glBindTexture(GL_TEXTURE_2D, textureObj[MOON]); //畫月亮 glPointSize(120.0f); GLfloat x = 650.0f; GLfloat y = 400.0f; glBegin(GL_POINTS); glVertex2f(x, y); glEnd(); //星座連線 glDisable(GL_TEXTURE_2D); glDisable(GL_POINT_SPRITE); glLineWidth(3.0); glBegin(GL_LINE_STRIP); glVertex2f(0.0f, 50.0f); glVertex2f(50.0f, 150.0f); glVertex2f(100.0f, 20.0f); glVertex2f(300.0f, 300.0f); glVertex2f(450.0f, 100.0f); glVertex2f(600.0f, 200.0f); glVertex2f(800.0f, 30.0f); glEnd(); glutSwapBuffers(); } void ProcessMenu(int value) { switch (value) { case 1: { //開啓混合 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_POINT_SMOOTH); glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glEnable(GL_POLYGON_SMOOTH); glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); glDisable(GL_TEXTURE_2D); glDisable(GL_POINT_SPRITE); break; } case 2: { //關閉混合 glDisable(GL_BLEND); glDisable(GL_POINT_SMOOTH); glDisable(GL_LINE_SMOOTH); glDisable(GL_POLYGON_SMOOTH); glDisable(GL_TEXTURE_2D); glDisable(GL_POINT_SPRITE); break; } case 3: //點精靈 glEnable(GL_BLEND); glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR); glDisable(GL_LINE_SMOOTH); glDisable(GL_POINT_SMOOTH); glDisable(GL_POLYGON_SMOOTH); break; default: break; } glutPostRedisplay(); } void ShutdownRC() { glDeleteTextures(TEXNUM, textureObj); } int main(int args, char **argv) { glutInit(&args, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowSize(SCREEN_X, SCREEN_Y); glutCreateWindow("POINTSPRITES"); //右鍵菜單 int menuID = glutCreateMenu(ProcessMenu); glutAddMenuEntry("antialiasing", 1); glutAddMenuEntry("normal", 2); glutAddMenuEntry("pointsprites", 3); glutAttachMenu(GLUT_RIGHT_BUTTON); glutDisplayFunc(RenderScene); glutReshapeFunc(ChangeSize); SetupRC(); glutMainLoop(); return 0; }
效果以下:
點精靈遵循全部的2D紋理的規則,包括紋理環境爲GL_DECAL,GL_REPLACE,GL_MODULATE等,以及mipmapped和多重紋理。若是把GL_COORD_REPLACE設置爲加,
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_FALSE);
那麼頂點指定單個紋理座標,並應用於整個點。若是爲GL_TRUE,則OpenGL根據點的表面對紋理座標進行插值。固然這些點的大小必須是大於1.0的。
點精靈的特性能夠經過glPointParameter來進行微調,下圖展現應用點精靈的兩個不一樣紋理座標的原點位置。
經過設置GL_POINT_SPRITE_COORD_ORIGIN爲GL_LOWER_LEFT把紋理座標的原點設置到左下角。
glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
更多的參數設置參考https://www.opengl.org/sdk/docs/man/xhtml/glPointParameter.xml