歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

OpenGL超級寶典學習筆記——紋理高級(三)

紋理組合器

OpenGL的紋理組合器可以控制多重紋理的片段是如何組合的。一般情況下,我們可以簡單的為每個紋理單元設置一個紋理環境模式(GL_REPLACE,GL_DECAL,GL_ADD和GL_MODULATE),把每個紋理應用的結果添加到下一個紋理單元中。然而紋理組合器提供了一個新的紋理環境GL_COMBINE允許我們顯示地控制每一個紋理單元的紋理片段是如何組合的。使用紋理組合器模式代碼如下:

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

紋理組合器是通過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組合器,你的函數調用如下:

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);

上表中的Arg0——Arg2通過更多的glTexEnv調用來設置。GL_SOURCEx_RGB和GL_SOURCEx_ALPHA值用於指定RGB和alpha組合器函數的參數,x可以是0,1或者2,這些來源的值如下表:

常量 描述 GL_TEXTURE 來源於當前綁定的紋理單元 GL_TEXTUREx 來源於綁定的紋理x GL_CONSTANT 顏色值或aplha值來源於通過GL_TEXTURE_ENV_COLOR參數設置的值 GL_PRIMARY_COLOR 來源於原幾何圖形片段 GL_PREVIOUS 來源於前一個紋理單元的紋理環境的結果

例:你設置Arg0為紋理單元0

glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);

我們還可以對給定的源值施加額外的控制。設置這些操作數,我們可以使用常量GL_OPERANDx_RGB或者GL_OPERANDx_ALPHA,x可以是0,1或者2,可以給這些操作數賦予的值如下表:

常量 描述 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)

例如你已經在兩個紋理單元中加載了兩個紋理,你在應用紋理時,想要把兩個紋理的顏色值相乘,你可以如下設置:

//設置紋理環境為紋理組合

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

OpenGL超級寶典 第4版 中文版PDF+英文版+源代碼 見  http://www.linuxidc.com/Linux/2013-10/91413.htm

OpenGL編程指南(原書第7版)中文掃描版PDF 下載 http://www.linuxidc.com/Linux/2012-08/67925.htm

OpenGL 渲染篇 http://www.linuxidc.com/Linux/2011-10/45756.htm

Ubuntu 13.04 安裝 OpenGL http://www.linuxidc.com/Linux/2013-05/84815.htm

OpenGL三維球體數據生成與繪制【附源碼】 http://www.linuxidc.com/Linux/2013-04/83235.htm

Ubuntu下OpenGL編程基礎解析 http://www.linuxidc.com/Linux/2013-03/81675.htm

如何在Ubuntu使用eclipse for c++配置OpenGL http://www.linuxidc.com/Linux/2012-11/74191.htm 

更多《OpenGL超級寶典學習筆記》相關知識 見 http://www.linuxidc.com/search.aspx?where=nkey&keyword=34581

Copyright © Linux教程網 All Rights Reserved