青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

  C++博客 :: 首頁(yè) :: 聯(lián)系 ::  :: 管理
  163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

常用鏈接

留言簿(48)

我參與的團(tuán)隊(duì)

搜索

  •  

積分與排名

  • 積分 - 402524
  • 排名 - 59

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

      這一課由Jens Schneider所寫(xiě),它基本上是由第6課改寫(xiě)而來(lái)的,在這一課里,你將學(xué)習(xí):
怎樣控制多重紋理
怎樣創(chuàng)建一個(gè)“假”的凹凸映射
怎樣做一個(gè)標(biāo)志,它看起來(lái)在你的場(chǎng)景上方
怎樣使矩陣變化更有效率
基本的多通道渲染
因?yàn)樯厦嫣岬降暮芏喾矫媸歉呒?jí)渲染得內(nèi)容,我們?cè)谥v述的時(shí)候會(huì)先說(shuō)明理論,接著在分析代碼 。如果你已經(jīng)熟悉了這些理論,你可以跳過(guò)他們,直接看代碼。當(dāng)你遇到什么問(wèn)題的時(shí)候,不妨回過(guò)頭來(lái)看看這些理論。
最后這份代碼超過(guò)了1200行,大部分我們?cè)谇懊娴慕坛讨杏龅竭^(guò)了。我不會(huì)解釋每一行代碼,只在重要的地方做些提示,好了,讓我們開(kāi)始吧。 
  

#include <string.h>       // 字符串處理函數(shù)
  
 MAX_EMBOSS常量定義了突起的最大值 
  

#define MAX_EMBOSS (GLfloat)0.01f      // 定義了突起的最大值

  
 好了,現(xiàn)在我們準(zhǔn)備使用GL_ARB_multitexture這個(gè)擴(kuò)展,它非常簡(jiǎn)單。
大部分圖形卡不止一個(gè)紋理單元,為了利用這個(gè)功能,你必須檢查GL_ARB_multitexture是否被支持,它可以使你同時(shí)把2個(gè)或多個(gè)不同的紋理映射到OpenGL圖元上。開(kāi)起來(lái)這個(gè)功能好像沒(méi)有太大的作用,但當(dāng)你使用多個(gè)紋理時(shí),如果能同時(shí)把這些紋理值混合,而不使用費(fèi)時(shí)的乘法運(yùn)算,你將會(huì)得到很高的速度提高。

現(xiàn)在回到我們的代碼,__ARB_ENABLE用來(lái)設(shè)置是否使用ARB擴(kuò)展。如果你想看你的OpenGL擴(kuò)展,只要把#define EXT_INFO前的注釋去掉就行了。接著,我們?cè)谶\(yùn)行檢查我們的擴(kuò)展,以保證我們的程序可以在不同的系統(tǒng)上運(yùn)行。所以我們需要一些內(nèi)存保存擴(kuò)展名的字符串,他們是下面兩行。接著我們用一個(gè)變量multitextureSupported來(lái)標(biāo)志當(dāng)前系統(tǒng)是否能使用multitexture擴(kuò)展,并用maxTexelUnits記錄運(yùn)行系統(tǒng)的紋理單元,這個(gè)值最少是1。
 
  

#define __ARB_ENABLE true       // 使用它設(shè)置是否使用ARB擴(kuò)展
// #define EXT_INFO       // 把注釋去掉,可以在啟動(dòng)時(shí)查看你的擴(kuò)展
#define MAX_EXTENSION_SPACE 10240      // 保存擴(kuò)展字符
#define MAX_EXTENSION_LENGTH 256      // 每個(gè)擴(kuò)展字符串最大的長(zhǎng)度
bool multitextureSupported=false;      // 標(biāo)志是否支持多重渲染
bool useMultitexture=true;       // 如果支持,是否使用它
GLint maxTexelUnits=1;       // 紋理處理單元的個(gè)數(shù)

  
 下面的函數(shù)定義用來(lái)使用OpenGL的擴(kuò)展函數(shù),你可以把PFN-who-ever-reads-this看成是預(yù)先定義的函數(shù)類(lèi)型,因?yàn)槲覀儾磺宄欠衲艿玫竭@些函數(shù)的實(shí)體,所以先把他們都設(shè)置為NULL。glMultiTexCoordifARB函數(shù)是glTexCoordif函數(shù)的擴(kuò)展,它門(mén)的功能相似,其中i為紋理坐標(biāo)的維數(shù),f為數(shù)據(jù)的類(lèi)型。最后兩個(gè)函數(shù)用來(lái)激活紋理處理單元,可以使用特定的紋理單元來(lái)邦定紋理。
順便說(shuō)一句,ARB是"Architectural Review Board"的縮寫(xiě),用來(lái)定義這個(gè)組織提出的對(duì)OpenGL的擴(kuò)展,并不強(qiáng)制OpenGL的實(shí)現(xiàn)必須包含這個(gè)功能,但他們希望這個(gè)功能得到廣泛的支持。當(dāng)前,只有multitexture被加入到ARB中,這從另一個(gè)方面支持multitexture的擴(kuò)展將大大的提高渲染速度。 
  

PFNGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB = NULL;
PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL;
PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB = NULL;
PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB = NULL;
PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;
PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB= NULL;

  
 下面我們來(lái)定義一些全局變量: 
filter定義過(guò)濾器類(lèi)型
texture[3]保存三個(gè)紋理
bump[3]保存三個(gè)凹凸紋理
invbump[3]保存三個(gè)反轉(zhuǎn)了的凹凸紋理
glLogo保存標(biāo)志
multiLogo保存多重紋理標(biāo)志
 
  

GLuint  filter=1;         // 定義過(guò)濾器類(lèi)型
GLuint  texture[3];        // 保存三個(gè)紋理
GLuint  bump[3];         //保存三個(gè)凹凸紋理
GLuint  invbump[3];        // 保存三個(gè)反轉(zhuǎn)了的凹凸紋理
GLuint  glLogo;         // glLogo保存標(biāo)志
GLuint  multiLogo;         // multiLogo保存多重紋理標(biāo)志
GLfloat LightAmbient[] = { 0.2f, 0.2f, 0.2f};     // 環(huán)境光
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f};     // 漫射光
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f};     // 光源位置
GLfloat Gray[]  = { 0.5f, 0.5f, 0.5f, 1.0f};

  
 下面一塊代碼用來(lái)保存立方體的紋理和坐標(biāo),每5個(gè)數(shù)字描述一個(gè)頂點(diǎn),包含2D的紋理坐標(biāo)和3D的頂點(diǎn)坐標(biāo)。 
  

// 立方體的紋理和坐標(biāo)

GLfloat data[]= {
 // 前面
 0.0f, 0.0f,  -1.0f, -1.0f, +1.0f,
 1.0f, 0.0f,  +1.0f, -1.0f, +1.0f,
 1.0f, 1.0f,  +1.0f, +1.0f, +1.0f,
 0.0f, 1.0f,  -1.0f, +1.0f, +1.0f,
 // 背面
 1.0f, 0.0f,  -1.0f, -1.0f, -1.0f,
 1.0f, 1.0f,  -1.0f, +1.0f, -1.0f,
 0.0f, 1.0f,  +1.0f, +1.0f, -1.0f,
 0.0f, 0.0f,  +1.0f, -1.0f, -1.0f,
 // 上面
 0.0f, 1.0f,  -1.0f, +1.0f, -1.0f,
 0.0f, 0.0f,  -1.0f, +1.0f, +1.0f,
 1.0f, 0.0f,  +1.0f, +1.0f, +1.0f,
 1.0f, 1.0f,  +1.0f, +1.0f, -1.0f,
 // 下面
 1.0f, 1.0f,  -1.0f, -1.0f, -1.0f,
 0.0f, 1.0f,  +1.0f, -1.0f, -1.0f,
 0.0f, 0.0f,  +1.0f, -1.0f, +1.0f,
 1.0f, 0.0f,  -1.0f, -1.0f, +1.0f,
 // 右面
 1.0f, 0.0f,  +1.0f, -1.0f, -1.0f,
 1.0f, 1.0f,  +1.0f, +1.0f, -1.0f,
 0.0f, 1.0f,  +1.0f, +1.0f, +1.0f,
 0.0f, 0.0f,  +1.0f, -1.0f, +1.0f,
 // 左面
 0.0f, 0.0f,  -1.0f, -1.0f, -1.0f,
 1.0f, 0.0f,  -1.0f, -1.0f, +1.0f,
 1.0f, 1.0f,  -1.0f, +1.0f, +1.0f,
 0.0f, 1.0f,  -1.0f, +1.0f, -1.0f
};

  
 下一部分代碼,用來(lái)這運(yùn)行時(shí)確定是否支持多重紋理的擴(kuò)展。
首先,我們假定一個(gè)字符串包含了所有的擴(kuò)展名,各個(gè)擴(kuò)展名之間用'\n'分開(kāi)。我們所要做的就是在其中查找是否有我們需要的擴(kuò)展。如果成功找到則返回TRUE,否則返回FALSE。
 
  

bool isInString(char *string, const char *search) {
 int pos=0;
 int maxpos=strlen(search)-1;
 int len=strlen(string);
 char *other;
 for (int i=0; i<len; i++) {
  if ((i==0) || ((i>1) && string[i-1]=='\n')) {    // 新的擴(kuò)展名開(kāi)始與這里
   other=&string[i];
   pos=0;       // 開(kāi)始新的比較
   while (string[i]!='\n') {     // 比較整個(gè)擴(kuò)展名
    if (string[i]==search[pos]) pos++;   // 下一個(gè)字符
    if ((pos>maxpos) && string[i+1]=='\n') return true; // 如果整個(gè)擴(kuò)展名相同則成功返回
    i++;
   }
  }
 }
 return false;        // 沒(méi)找到
}

  
 現(xiàn)在我們需要先取得擴(kuò)展名字符串,并把它轉(zhuǎn)換為以'\n'分割的字符串,接著調(diào)用以上定義的函數(shù)看看是否包含我們需要的擴(kuò)展。如果定義了__ARB_ENABLE則使用多重紋理擴(kuò)展,接下來(lái)我們檢查是否支持GL_EXT_texture_env_combine擴(kuò)展,這個(gè)擴(kuò)展提供各個(gè)紋理單元復(fù)雜的交互方式,利用它可以完成復(fù)雜的混合方程。如果所有的擴(kuò)展都被支持,我們首先取得紋理單元的個(gè)數(shù),把它保存到變量maxTexelUnits中,接著通過(guò)函數(shù)wglGetProcAdress把各個(gè)函數(shù)定義連接到各自的實(shí)體上,這樣在后面的程序中就可以使用這些函數(shù)了。 
  

bool initMultitexture(void) {
 char *extensions;
 extensions=strdup((char *) glGetString(GL_EXTENSIONS));   // 返回?cái)U(kuò)展名字符串
 int len=strlen(extensions);
 for (int i=0; i<len; i++)       // 使用'\n'分割各個(gè)擴(kuò)展名
  if (extensions[i]==' ') extensions[i]='\n';

#ifdef EXT_INFO
 MessageBox(hWnd,extensions,"supported GL extensions",MB_OK | MB_ICONINFORMATION);
#endif

 if (isInString(extensions,"GL_ARB_multitexture")    // 是否支持多重紋理擴(kuò)展?
  && __ARB_ENABLE       // 是否使用多重紋理擴(kuò)展?
  && isInString(extensions,"GL_EXT_texture_env_combine"))  // 是否支持紋理環(huán)境混合
 {
  glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&maxTexelUnits);
  glMultiTexCoord1fARB = (PFNGLMULTITEXCOORD1FARBPROC) wglGetProcAddress("glMultiTexCoord1fARB");
  glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress("glMultiTexCoord2fARB");
  glMultiTexCoord3fARB = (PFNGLMULTITEXCOORD3FARBPROC) wglGetProcAddress("glMultiTexCoord3fARB");
  glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC) wglGetProcAddress("glMultiTexCoord4fARB");
  glActiveTextureARB   = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress("glActiveTextureARB");
  glClientActiveTextureARB= (PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress("glClientActiveTextureARB");

#ifdef EXT_INFO
  MessageBox(hWnd,"The GL_ARB_multitexture 擴(kuò)展被使用.","支持多重紋理",MB_OK | MB_ICONINFORMATION);
#endif

  return true;
 }
 useMultitexture=false;       // 如果不支持多重紋理則返回false
 return false;
}

  
 初始化燈光 
  

void initLights(void) {
 glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);    
 glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
 glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
 glEnable(GL_LIGHT1);
}

  
 下面我們加載許多紋理,這和前面的教程很像 
  

int LoadGLTextures() {        // 載入*.bmp圖像,并轉(zhuǎn)換為紋理
 bool status=true;  
 AUX_RGBImageRec *Image=NULL;      
 char *alpha=NULL;

 // 加載基礎(chǔ)紋理
 if (Image=auxDIBImageLoad("Data/Base.bmp")) {
  glGenTextures(3, texture);      // 創(chuàng)建3個(gè)紋理

  // 創(chuàng)建使用臨近過(guò)濾器過(guò)濾得紋理
  glBindTexture(GL_TEXTURE_2D, texture[0]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->sizeX, Image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, Image->data);

  // 創(chuàng)建使用線(xiàn)形過(guò)濾器過(guò)濾得紋理
  glBindTexture(GL_TEXTURE_2D, texture[1]);
  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, GL_RGB8, Image->sizeX, Image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, Image->data);

  // 創(chuàng)建使用線(xiàn)形Mipmap過(guò)濾器過(guò)濾得紋理
  glBindTexture(GL_TEXTURE_2D, texture[2]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
  gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, Image->sizeX, Image->sizeY, GL_RGB, GL_UNSIGNED_BYTE, Image->data);
 }
 else status=false;

 if (Image) {        // 如果圖像句柄存在,則釋放圖像回收資源
  if (Image->data) delete Image->data;    
  delete Image;
  Image=NULL;
 }

  
 現(xiàn)在我們加載凹凸映射紋理。這個(gè)紋理必須使用50%的亮度(原因我們?cè)诤竺娼榻B),我們使用glPixelTransferf函數(shù)完成這個(gè)功能。
另一個(gè)限制是我們不希望紋理重復(fù)貼圖,只希望它粘貼一次,從紋理坐標(biāo)(0,0)-(1,1),所有大于它的紋理坐標(biāo)都被映射到邊緣,為了完成這個(gè)功能,我們使用glTexParameteri函數(shù)。 
  

 // 載入凹凸貼圖
 if (Image=auxDIBImageLoad("Data/Bump.bmp")) {
  glPixelTransferf(GL_RED_SCALE,0.5f);     // 把顏色值變?yōu)樵瓉?lái)的50%
  glPixelTransferf(GL_GREEN_SCALE,0.5f);    
  glPixelTransferf(GL_BLUE_SCALE,0.5f);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);  //不使用重復(fù)貼圖
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
  glGenTextures(3, bump);      //創(chuàng)建凹凸貼圖紋理

  // 創(chuàng)建使用臨近過(guò)濾器過(guò)濾得紋理
  >…<
 // 創(chuàng)建使用線(xiàn)形過(guò)濾器過(guò)濾得紋理
  >…< // 創(chuàng)建使用線(xiàn)形Mipmap過(guò)濾器過(guò)濾得紋理
  >…<

  
 反轉(zhuǎn)凹凸貼圖數(shù)據(jù),創(chuàng)建三個(gè)反轉(zhuǎn)的凹凸貼圖紋理 
  

  for (int i=0; i<3*Image->sizeX*Image->sizeY; i++)   // 反轉(zhuǎn)凹凸貼圖數(shù)據(jù)
   Image->data[i]=255-Image->data[i];

  glGenTextures(3, invbump);      // 創(chuàng)建三個(gè)反轉(zhuǎn)了凹凸貼圖

  // 創(chuàng)建使用臨近過(guò)濾器過(guò)濾得紋理
  >…< // 創(chuàng)建使用線(xiàn)形過(guò)濾器過(guò)濾得紋理
  >…< // 創(chuàng)建使用線(xiàn)形Mipmap過(guò)濾器過(guò)濾得紋理
  >…<
 }
 else status=false;
 if (Image) {        // 如果圖像存在,則刪除
  if (Image->data) delete Image->data; 
  delete Image;
  Image=NULL;
 }

  
 載入標(biāo)志圖像,圖像是把顏色和alpha通道存為兩張不同的bmp位圖的,所以在處理的時(shí)候需要注意以下各個(gè)分量的位置。 
  

 if (Image=auxDIBImageLoad("Data/OpenGL_ALPHA.bmp")) {
  alpha=new char[4*Image->sizeX*Image->sizeY];
  for (int a=0; a<Image->sizeX*Image->sizeY; a++)
   alpha[4*a+3]=Image->data[a*3];    
  if (!(Image=auxDIBImageLoad("Data/OpenGL.bmp"))) status=false;
  for (a=0; a<Image->sizeX*Image->sizeY; a++) {
   alpha[4*a]=Image->data[a*3];    
   alpha[4*a+1]=Image->data[a*3+1];  
   alpha[4*a+2]=Image->data[a*3+2];   
  }

  glGenTextures(1, &glLogo);      // 創(chuàng)建標(biāo)志紋理

  // 使用線(xiàn)形過(guò)濾器
  glBindTexture(GL_TEXTURE_2D, glLogo);
  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, GL_RGBA8, Image->sizeX, Image->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, alpha);
  delete alpha;
 }
 else status=false;

 if (Image) {        // 如果圖像存在,則刪除
  if (Image->data) delete Image->data;    
  delete Image;
  Image=NULL;
 }

 // 載入擴(kuò)展標(biāo)志紋理
 if (Image=auxDIBImageLoad("Data/multi_on_alpha.bmp")) {
  alpha=new char[4*Image->sizeX*Image->sizeY];   
  >...<
  glGenTextures(1, &multiLogo);     
  >...<
  delete alpha;
 }
 else status=false;

 if (Image) {        // 如果圖像存在,則刪除
  if (Image->data) delete Image->data;    
  delete Image;
  Image=NULL;
 }
 return status;        
}

  
 下面是窗口大小變化函數(shù),沒(méi)有任何改變。
接下來(lái)是繪制一個(gè)立方體的函數(shù),它使用常規(guī)的方法繪制。
 
  

void doCube (void) {
 int i;
 glBegin(GL_QUADS);
  // 前面
  glNormal3f( 0.0f, 0.0f, +1.0f);
  for (i=0; i<4; i++) {
   glTexCoord2f(data[5*i],data[5*i+1]);
   glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
  }
  // 后面
  glNormal3f( 0.0f, 0.0f,-1.0f);
  for (i=4; i<8; i++) {
   glTexCoord2f(data[5*i],data[5*i+1]);
   glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
  }
  // 上面
  glNormal3f( 0.0f, 1.0f, 0.0f);
  for (i=8; i<12; i++) {
   glTexCoord2f(data[5*i],data[5*i+1]);
   glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
  }
  // 下面
  glNormal3f( 0.0f,-1.0f, 0.0f);
  for (i=12; i<16; i++) {
   glTexCoord2f(data[5*i],data[5*i+1]);
   glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
  }
  // 右面
  glNormal3f( 1.0f, 0.0f, 0.0f);
  for (i=16; i<20; i++) {
   glTexCoord2f(data[5*i],data[5*i+1]);
   glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
  }
  // 左面
  glNormal3f(-1.0f, 0.0f, 0.0f);
  for (i=20; i<24; i++) {
   glTexCoord2f(data[5*i],data[5*i+1]);
   glVertex3f(data[5*i+2],data[5*i+3],data[5*i+4]);
  }
 glEnd();
}

  
 現(xiàn)在到了OpenGL的初始化函數(shù),它和前面的教程基本相同,只是添加了以下代碼: 
  

 multitextureSupported=initMultitexture();

 initLights(); 

  
 這里我們完成了95%的工作,下面我們來(lái)解釋上面提到的原理。
開(kāi)始理論講解(凹凸映射)
如果你安裝了Powerpoint-viewer,下面是一個(gè)講解凹凸映射原理的PPT,你可以下載后慢慢研究:
凹凸映射 作者M(jìn)ichael I. Gold, nVidia 公司
如果你沒(méi)有安裝Powerpoint-viewer,我把它轉(zhuǎn)換為Html格式,現(xiàn)講解如下:

凹凸貼圖
Michael I. Gold
NVIDIA 公司

凹凸貼圖

真實(shí)的凹凸貼圖是逐像素計(jì)算的

光照計(jì)算是按每個(gè)象素點(diǎn)的法向量計(jì)算的
巨大的計(jì)算量
更多的信息可以看: Blinn, J. Simulation of Wrinkled Surfaces. Computer Graphics. 12, 3 (August 1978), 286-292
凹凸貼圖是在效果和精度之間的一個(gè)折中

只能對(duì)漫射光計(jì)算,不能使用反射光
欺騙視覺(jué)的采樣
可能運(yùn)行于當(dāng)前的硬件上
如果它看起來(lái)很好,就干吧
漫射光的計(jì)算

C = (L*N)*Dl*Dm

L 頂點(diǎn)到燈之間的單位向量
N 頂點(diǎn)的單位法向量
Dl 燈光的漫射光顏色
Dm 頂點(diǎn)材質(zhì)的漫射屬性
凸值 逐像素改變N值
凹凸映射 改變(L*N)的值
近似的漫射因子 L*N

紋理圖代表高度場(chǎng)

[0,1] 之間的高度代表凹凸方程
首先導(dǎo)出偏離度m
m 增加/減少基礎(chǔ)的漫射因子Fd
(Fd+m) 在每一像素上近似等于 (L*N)
偏移量m的導(dǎo)出

偏移量m的近似導(dǎo)出

查找(s,t)紋理的高度H0
查找(s+ds, t+dt)紋理的高度H1
M近似等于H1-H0
計(jì)算凹凸量
 

1) 原始凸起(H0).

 

2) 原始的凸起(H0)向光源移動(dòng)一小段距離形成第二個(gè)凸起(H1)

 

3) 用H1凸起減去H0凸起 (H1-H0)

計(jì)算燈光亮度

計(jì)算片斷的顏色Cf

Cf = (L*N) x Dl x Dm
(L*N) ~ (Fd + (H1-H0))
Ct= Dm x Dl
Cf = (Fd + (H0-H1) x Ct
Fd等于頂點(diǎn)法線(xiàn)與燈光的向量的乘積
上面就是全部么? 太簡(jiǎn)單了!

我們還沒(méi)有完成所有的任務(wù),還必須做以下內(nèi)容:
創(chuàng)建一個(gè)紋理
計(jì)算紋理坐標(biāo)偏移量ds, dt
計(jì)算漫射因子Fd
ds, dt ,F(xiàn)d都從N和L導(dǎo)出
現(xiàn)在我們開(kāi)始做一些數(shù)學(xué)計(jì)算
創(chuàng)建紋理

保存紋理!
當(dāng)前的多重紋理硬件只支持兩個(gè)紋理
偏移值保存在alpha通道里
最大凸起值為 = 1.0
水平面值為 = 0.5
最小值為= 0.0
顏色存儲(chǔ)在RGB通道中
設(shè)置內(nèi)部顏色格式為RGBA8 !!
計(jì)算紋理偏移量

把燈光方向向量變換到一個(gè)笛卡爾坐標(biāo)系中
頂點(diǎn)法線(xiàn)為z軸
從法線(xiàn)和視口的“上”向量導(dǎo)出坐標(biāo)系
頂點(diǎn)法線(xiàn)為z軸
叉乘得到X軸
丟棄“上”向量,利用z,y軸導(dǎo)出x軸
創(chuàng)建3x3變換矩陣Mn
變換燈光方向向量到這個(gè)坐標(biāo)系中
計(jì)算紋理偏移量

使用法向坐標(biāo)系中的向量作為偏移量
L'= Mn x L
使用L’.x, L’.y 作為 ds, dt
使用 L’.z 作為漫射因子!
如果燈光方向接近垂直,則L’.x, L’.y 非常小
如果燈光方向接近水平,則L’.x, L’.y 非常大
L’.z小于零的含義?
燈光在法線(xiàn)的對(duì)面
在TNT上的實(shí)現(xiàn)

計(jì)算向量,紋理坐標(biāo)
設(shè)置漫射因子
從紋理單元0取出表面顏色和H0值
從紋理單元1取出H1值
ARB_multitexture 擴(kuò)展
混合紋理擴(kuò)展 (TBD)

混合0 alpha設(shè)置:
(1-T0a) + T1a - 0.5
T1a-T0a 映射到[-1,1],但硬件把它映射到[0,1]
T1a為H1的值,T0a為H0的值
0.5 平衡損失的掐除值
使用漫射光顏色調(diào)制(相乘)片斷顏色T0c
混合1 顏色設(shè)置:
(T0c * C0a + T0c * Fda - 0.5 )*2
0.5 平衡損失的掐除值
乘以2加亮圖像顏色
結(jié)束理論講解(凹凸映射)

雖然我們做了一些改動(dòng),使得這個(gè)程序的實(shí)現(xiàn)與TNT的實(shí)現(xiàn)不一樣,但它能工作與各種不同的顯卡上。在這里我們將學(xué)到兩三件事,凹凸映射在大多數(shù)顯卡上是一個(gè)多通道算法(在TNT系列,可以使用一個(gè)2紋理通道實(shí)現(xiàn)),現(xiàn)在你應(yīng)該能想到多重紋理的好處了吧。我們將使用一個(gè)三通道非多重紋理的算法實(shí)現(xiàn),這個(gè)算法可以被改寫(xiě)為使用一個(gè)2紋理通道實(shí)現(xiàn)的算法。
現(xiàn)在必須告訴你,我們將要做一些矩陣和向量的乘法,但那沒(méi)有什么可擔(dān)心的,所有的矩陣和向量都使用齊次坐標(biāo)。
 
  

// 計(jì)算向量v=v*M(左乘)
void VMatMult(GLfloat *M, GLfloat *v) {
 GLfloat res[3];
 res[0]=M[ 0]*v[0]+M[ 1]*v[1]+M[ 2]*v[2]+M[ 3]*v[3];
 res[1]=M[ 4]*v[0]+M[ 5]*v[1]+M[ 6]*v[2]+M[ 7]*v[3];
 res[2]=M[ 8]*v[0]+M[ 9]*v[1]+M[10]*v[2]+M[11]*v[3];
 v[0]=res[0];
 v[1]=res[1];
 v[2]=res[2];
 v[3]=M[15];        
}

  
 開(kāi)始理論講解(凹凸映射)

開(kāi)始,讓我們看看它的算法

所有的向量必須在物體空間或則世界空間中
計(jì)算向量v,由燈的位置減去當(dāng)前頂點(diǎn)的位置
歸一化向量v
把向量v投影到切空間中
安向量v在切空間中的投影偏移紋理坐標(biāo)
這看起來(lái)不錯(cuò),它基本上和Michael I. Gold介紹的方法差不多。但它有一個(gè)缺點(diǎn),它只對(duì)xy平面進(jìn)行投影,這對(duì)我們的應(yīng)用還是不夠的。
但這個(gè)實(shí)現(xiàn)在計(jì)算漫射光的方法和我們是一樣的,我們不能存儲(chǔ)漫射因子,所以我們不能使用Michael I. Gold介紹的方法,因?yàn)槲覀兿胱屗谌魏物@卡上運(yùn)行而不僅僅是TNT系列。為什么不光照計(jì)算留到最后呢?這在簡(jiǎn)單的幾何體繪制上是可行的,如果你需要渲染幾千個(gè)具有凹凸貼圖的三角形,你會(huì)感到繪制的速度不夠快,到那時(shí)你需要改變這種渲染過(guò)程,尋找其它的方法。

在我們的實(shí)現(xiàn)里,它看起來(lái)和上面的實(shí)現(xiàn)差不多,除了投影部分,我們將使用我們自己的近似。

我們使用模型坐標(biāo),這種設(shè)定可以使得燈光位置相對(duì)于物體不變。
我們計(jì)算當(dāng)前的頂點(diǎn)坐標(biāo)
接著計(jì)算法線(xiàn),并使它單位化
創(chuàng)建一個(gè)正投影矩陣,把燈光方向變?yōu)榍锌臻g
計(jì)算紋理坐標(biāo)的偏移量,ds = s點(diǎn)乘v*MAX_EMBOSS, dt=t點(diǎn)乘v*MAX_EMBOSS
在通道2中,把偏移量添加到紋理坐標(biāo)
為什么更好:
更快
看起來(lái)好看
這個(gè)方法可以工作與各種表面
可以運(yùn)行于各種顯卡
最大化的兼容
缺陷:
并不是完全的物理模擬
殘留一些人為的假相
 

這個(gè)示意圖顯示了我們坐標(biāo)系統(tǒng),你可以通過(guò)相減相鄰的坐標(biāo)來(lái)獲得s,t向量,但必須保證他們構(gòu)成右手系和歸一化。

結(jié)束理論講解(凹凸映射)

下面讓我們看看如何生成偏移量,首先創(chuàng)建一個(gè)函數(shù)創(chuàng)建凹凸映射:
 
  

// 設(shè)置紋理偏移,都為單位長(zhǎng)度
// n : 表面的法向量
// c : 當(dāng)前的頂點(diǎn)紋理坐標(biāo),返回紋理坐標(biāo)的偏移量
// l : 燈光的位置
// s : s方向
// t : t方向
void SetUpBumps(GLfloat *n, GLfloat *c, GLfloat *l, GLfloat *s, GLfloat *t) {
 GLfloat v[3];        // 燈光方向
 GLfloat lenQ;        // 燈光方向向量的長(zhǎng)度,使用它來(lái)單位化
 // 計(jì)算燈光方向
 v[0]=l[0]-c[0];
 v[1]=l[1]-c[1];
 v[2]=l[2]-c[2];
 lenQ=(GLfloat) sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
 v[0]/=lenQ;
 v[1]/=lenQ;
 v[2]/=lenQ;
 // 把方向向量投影到s,t方向
 c[0]=(s[0]*v[0]+s[1]*v[1]+s[2]*v[2])*MAX_EMBOSS;
 c[1]=(t[0]*v[0]+t[1]*v[1]+t[2]*v[2])*MAX_EMBOSS;}
  
 那看起來(lái)復(fù)雜么,但為了理解這個(gè)效果理論是必須的。(我在寫(xiě)這篇教程的時(shí)候也學(xué)習(xí)了它)。
我在程序運(yùn)行的時(shí)候,總喜歡在屏幕上顯示標(biāo)志,現(xiàn)在我們有了兩個(gè),使用doLogo函數(shù)創(chuàng)建它。

下面的函數(shù)顯示兩個(gè)標(biāo)志:一個(gè)OpenGL的標(biāo)志,一個(gè)多重紋理的標(biāo)志,如果可以使用多重紋理,則標(biāo)志使用alpha混合,并看起來(lái)半透明。為了讓它在屏幕的邊沿顯示我們使用混合并禁用光照和深度測(cè)試。


 
  

void doLogo(void) {
 // 必須最后在調(diào)用這個(gè)函數(shù),以公告板的形式顯示兩個(gè)標(biāo)志
 glDepthFunc(GL_ALWAYS);
 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
 glEnable(GL_BLEND);
 glDisable(GL_LIGHTING);
 glLoadIdentity();
 glBindTexture(GL_TEXTURE_2D,glLogo);
 glBegin(GL_QUADS);
  glTexCoord2f(0.0f,0.0f); glVertex3f(0.23f, -0.4f,-1.0f);
  glTexCoord2f(1.0f,0.0f); glVertex3f(0.53f, -0.4f,-1.0f);
  glTexCoord2f(1.0f,1.0f); glVertex3f(0.53f, -0.25f,-1.0f);
  glTexCoord2f(0.0f,1.0f); glVertex3f(0.23f, -0.25f,-1.0f);
 glEnd();
 if (useMultitexture) {
  glBindTexture(GL_TEXTURE_2D,multiLogo);
  glBegin(GL_QUADS);
   glTexCoord2f(0.0f,0.0f); glVertex3f(-0.53f, -0.25f,-1.0f);
   glTexCoord2f(1.0f,0.0f); glVertex3f(-0.33f, -0.25f,-1.0f);
   glTexCoord2f(1.0f,1.0f); glVertex3f(-0.33f, -0.15f,-1.0f);
   glTexCoord2f(0.0f,1.0f); glVertex3f(-0.53f, -0.15f,-1.0f);
  glEnd();
 }
 glDepthFunc(GL_LEQUAL);
}

  
 現(xiàn)在到了繪制凹凸貼圖的函數(shù)了,我們先來(lái)看看不使用多重映射的方法,它通過(guò)三個(gè)通道實(shí)現(xiàn)。在第一步,我們先取得模型變換矩陣的逆矩陣! 
  

bool doMesh1TexelUnits(void) {
 GLfloat c[4]={0.0f,0.0f,0.0f,1.0f};     // 保存當(dāng)前的頂點(diǎn)
 GLfloat n[4]={0.0f,0.0f,0.0f,1.0f};     // 保存法線(xiàn)
 GLfloat s[4]={0.0f,0.0f,0.0f,1.0f};     // s紋理坐標(biāo)方向
 GLfloat t[4]={0.0f,0.0f,0.0f,1.0f};     // t紋理坐標(biāo)方向
 GLfloat l[4];       // 保存燈光方向
 GLfloat Minv[16];       // 保存模型變換矩陣的逆
 int i;

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   // 清空背景顏色和深度緩存

 // 創(chuàng)建模型變換矩陣的逆
 glLoadIdentity();
 glRotatef(-yrot,0.0f,1.0f,0.0f);
 glRotatef(-xrot,1.0f,0.0f,0.0f);
 glTranslatef(0.0f,0.0f,-z);
 glGetFloatv(GL_MODELVIEW_MATRIX,Minv);
 glLoadIdentity();
 glTranslatef(0.0f,0.0f,z);
 glRotatef(xrot,1.0f,0.0f,0.0f);
 glRotatef(yrot,0.0f,1.0f,0.0f);

 // 設(shè)置燈光的位置
 l[0]=LightPosition[0];
 l[1]=LightPosition[1];
 l[2]=LightPosition[2];
 l[3]=1.0f;        
 VMatMult(Minv,l);

  
 通道1:
使用凹凸紋理
禁止混合
禁止光照
使用無(wú)偏移的紋理坐標(biāo)
繪制幾何體
這將渲染一個(gè)無(wú)凹凸貼圖的幾何體 
  

 glBindTexture(GL_TEXTURE_2D, bump[filter]);
 glDisable(GL_BLEND);
 glDisable(GL_LIGHTING);
 doCube();

  
 通道2:
使用反轉(zhuǎn)的紋理凹凸貼圖
設(shè)置混合因子為1,1
使用光照
使用偏移紋理坐標(biāo)
繪制幾何體
這將繪制一個(gè)具有凹凸貼圖的幾何體,但沒(méi)有顏色 

 
  

 glBindTexture(GL_TEXTURE_2D,invbump[filter]);
 glBlendFunc(GL_ONE,GL_ONE);
 glDepthFunc(GL_LEQUAL);
 glEnable(GL_BLEND);

 glBegin(GL_QUADS);
  // 前面
  n[0]=0.0f;
  n[1]=0.0f;
  n[2]=1.0f;
  s[0]=1.0f;
  s[1]=0.0f;
  s[2]=0.0f;
  t[0]=0.0f;
  t[1]=1.0f;
  t[2]=0.0f;
  for (i=0; i<4; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   // 設(shè)置紋理坐標(biāo)為偏移后的紋理坐標(biāo)
   glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
  // 后面
  n[0]=0.0f;
  n[1]=0.0f;
  n[2]=-1.0f;
  s[0]=-1.0f;
  s[1]=0.0f;
  s[2]=0.0f;
  t[0]=0.0f;
  t[1]=1.0f;
  t[2]=0.0f;
  for (i=4; i<8; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
  // 上面
  n[0]=0.0f;
  n[1]=1.0f;
  n[2]=0.0f;
  s[0]=1.0f;
  s[1]=0.0f;
  s[2]=0.0f;
  t[0]=0.0f;
  t[1]=0.0f;
  t[2]=-1.0f;
  for (i=8; i<12; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
  // 下面
  n[0]=0.0f;
  n[1]=-1.0f;
  n[2]=0.0f;
  s[0]=-1.0f;
  s[1]=0.0f;
  s[2]=0.0f;
  t[0]=0.0f;
  t[1]=0.0f;
  t[2]=-1.0f;
  for (i=12; i<16; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
  // 右面
  n[0]=1.0f;
  n[1]=0.0f;
  n[2]=0.0f;
  s[0]=0.0f;
  s[1]=0.0f;
  s[2]=-1.0f;
  t[0]=0.0f;
  t[1]=1.0f;
  t[2]=0.0f;
  for (i=16; i<20; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
  // 左面
  n[0]=-1.0f;
  n[1]=0.0f;
  n[2]=0.0f;
  s[0]=0.0f;
  s[1]=0.0f;
  s[2]=1.0f;
  t[0]=0.0f;
  t[1]=1.0f;
  t[2]=0.0f;
  for (i=20; i<24; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glTexCoord2f(data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
 glEnd();

  
 通道3:
使用顏色紋理Use (colored) base-texture
使用混合因子GL_DST_COLOR, GL_SRC_COLOR
這個(gè)混合等于把顏色值乘以2
使用光照
繪制幾何體
這個(gè)過(guò)程將結(jié)束立方體的渲染,因?yàn)槲覀兛梢栽谑欠袷褂枚嘀劁秩局g切換,所以必須把紋理環(huán)境參數(shù)設(shè)為GL_MODULATE,這是默認(rèn)的值。 
  

 if (!emboss) {
  glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  glBindTexture(GL_TEXTURE_2D,texture[filter]);
  glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
  glEnable(GL_LIGHTING);
  doCube();
 }

  
 最后的通道:
更新幾何體
繪制標(biāo)志
 
  

 xrot+=xspeed;
 yrot+=yspeed;
 if (xrot>360.0f) xrot-=360.0f;
 if (xrot<0.0f) xrot+=360.0f;
 if (yrot>360.0f) yrot-=360.0f;
 if (yrot<0.0f) yrot+=360.0f;

 //繪制標(biāo)志
 doLogo();
 return true;       // 成功返回
}

  
 這個(gè)函數(shù)將在多重紋理功能的支持下載兩個(gè)通道中完成凹凸貼圖的繪制,我們支持兩個(gè)紋理單元,與一個(gè)紋理單元不同的是,我們給一個(gè)頂點(diǎn)設(shè)置兩個(gè)紋理坐標(biāo)。 
  

bool doMesh2TexelUnits(void) {
 GLfloat c[4]={0.0f,0.0f,0.0f,1.0f};     // 保存當(dāng)前的頂點(diǎn)
 GLfloat n[4]={0.0f,0.0f,0.0f,1.0f};     // 保存法線(xiàn)
 GLfloat s[4]={0.0f,0.0f,0.0f,1.0f};     // s紋理坐標(biāo)方向
 GLfloat t[4]={0.0f,0.0f,0.0f,1.0f};     // t紋理坐標(biāo)方向
 GLfloat l[4];       // 保存燈光方向
 GLfloat Minv[16];       // 保存模型變換矩陣的逆
 int i;

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   // 清空背景顏色和深度緩存

 // 創(chuàng)建模型變換矩陣的逆
 glLoadIdentity();
 glRotatef(-yrot,0.0f,1.0f,0.0f);
 glRotatef(-xrot,1.0f,0.0f,0.0f);
 glTranslatef(0.0f,0.0f,-z);
 glGetFloatv(GL_MODELVIEW_MATRIX,Minv);
 glLoadIdentity();
 glTranslatef(0.0f,0.0f,z);

 glRotatef(xrot,1.0f,0.0f,0.0f);
 glRotatef(yrot,0.0f,1.0f,0.0f);

 // 設(shè)置燈光的位置
 l[0]=LightPosition[0];
 l[1]=LightPosition[1];
 l[2]=LightPosition[2];
 l[3]=1.0f;        
 VMatMult(Minv,l);

  
 通道1:
無(wú)凹凸貼圖
無(wú)光照
設(shè)置紋理混合器0
使用凹凸紋理
使用無(wú)偏移的紋理坐標(biāo)
使用替換方式粘貼紋理
設(shè)置紋理混合器1
偏移紋理坐標(biāo)
使用相加的紋理操作
這將繪制一個(gè)灰度的立方體 
  

 // 紋理單元 #0
 glActiveTextureARB(GL_TEXTURE0_ARB);
 glEnable(GL_TEXTURE_2D);
 glBindTexture(GL_TEXTURE_2D, bump[filter]);
 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
 glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);

 // 紋理單元 #1
 glActiveTextureARB(GL_TEXTURE1_ARB);
 glEnable(GL_TEXTURE_2D);
 glBindTexture(GL_TEXTURE_2D, invbump[filter]);
 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
 glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);

 // 禁用混合和光照
 glDisable(GL_BLEND);
 glDisable(GL_LIGHTING);

  
 現(xiàn)在按面一個(gè)一個(gè)的渲染立方體,和doMesh1TexelUnits函數(shù)中所作的操作差不多,只是用glMultiTexCoor2fARB替換glTexCoord2f,在這個(gè)函數(shù)中,你必須把紋理坐標(biāo)發(fā)向不同的紋理處理單元,可用的參數(shù)值為GL_TEXTUREi_ARB0到GL_TEXTUREi_ARB31。 
  

 glBegin(GL_QUADS);
  // 前面
  n[0]=0.0f;
  n[1]=0.0f;
  n[2]=1.0f;
  s[0]=1.0f;
  s[1]=0.0f;
  s[2]=0.0f;
  t[0]=0.0f;
  t[1]=1.0f;
  t[2]=0.0f;
  for (i=0; i<4; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
   glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
  // 后面
  n[0]=0.0f;
  n[1]=0.0f;
  n[2]=-1.0f;
  s[0]=-1.0f;
  s[1]=0.0f;
  s[2]=0.0f;
  t[0]=0.0f;
  t[1]=1.0f;
  t[2]=0.0f;
  for (i=4; i<8; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
   glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
  // 上面
  n[0]=0.0f;
  n[1]=1.0f;
  n[2]=0.0f;
  s[0]=1.0f;
  s[1]=0.0f;
  s[2]=0.0f;
  t[0]=0.0f;
  t[1]=0.0f;
  t[2]=-1.0f;
  for (i=8; i<12; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
   glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
  // 下面
  n[0]=0.0f;
  n[1]=-1.0f;
  n[2]=0.0f;
  s[0]=-1.0f;
  s[1]=0.0f;
  s[2]=0.0f;
  t[0]=0.0f;
  t[1]=0.0f;
  t[2]=-1.0f;
  for (i=12; i<16; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
   glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
  // 右面
  n[0]=1.0f;
  n[1]=0.0f;
  n[2]=0.0f;
  s[0]=0.0f;
  s[1]=0.0f;
  s[2]=-1.0f;
  t[0]=0.0f;
  t[1]=1.0f;
  t[2]=0.0f;
  for (i=16; i<20; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
   glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
  // 左面
  n[0]=-1.0f;
  n[1]=0.0f;
  n[2]=0.0f;
  s[0]=0.0f;
  s[1]=0.0f;
  s[2]=1.0f;
  t[0]=0.0f;
  t[1]=1.0f;
  t[2]=0.0f;
  for (i=20; i<24; i++) {
   c[0]=data[5*i+2];
   c[1]=data[5*i+3];
   c[2]=data[5*i+4];
   SetUpBumps(n,c,l,s,t);
   glMultiTexCoord2fARB(GL_TEXTURE0_ARB,data[5*i], data[5*i+1]);
   glMultiTexCoord2fARB(GL_TEXTURE1_ARB,data[5*i]+c[0], data[5*i+1]+c[1]);
   glVertex3f(data[5*i+2], data[5*i+3], data[5*i+4]);
  }
 glEnd();

  
 通道2:
使用基本紋理
使用光照
使用普通的紋理混合操作
這將完成最后的凹凸貼圖 
  

 glActiveTextureARB(GL_TEXTURE1_ARB);
 glDisable(GL_TEXTURE_2D);
 glActiveTextureARB(GL_TEXTURE0_ARB);
 if (!emboss) {
  glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  glBindTexture(GL_TEXTURE_2D,texture[filter]);
  glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
  glEnable(GL_BLEND);
  glEnable(GL_LIGHTING);
  doCube();
 }

  
 最后的通道:
更新幾何體
繪制標(biāo)志
 
  

 xrot+=xspeed;
 yrot+=yspeed;
 if (xrot>360.0f) xrot-=360.0f;
 if (xrot<0.0f) xrot+=360.0f;
 if (yrot>360.0f) yrot-=360.0f;
 if (yrot<0.0f) yrot+=360.0f;

 doLogo();
 return true;        
}

  
 最后繪制一個(gè)無(wú)凹凸貼圖的立方體,用來(lái)觀察兩者之間的效果 
  

bool doMeshNoBumps(void) {
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   
 glLoadIdentity();       
 glTranslatef(0.0f,0.0f,z);

 glRotatef(xrot,1.0f,0.0f,0.0f);
 glRotatef(yrot,0.0f,1.0f,0.0f);

 if (useMultitexture) {
  glActiveTextureARB(GL_TEXTURE1_ARB);
  glDisable(GL_TEXTURE_2D);
  glActiveTextureARB(GL_TEXTURE0_ARB);
 }

 glDisable(GL_BLEND);
 glBindTexture(GL_TEXTURE_2D,texture[filter]);
 glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
 glEnable(GL_LIGHTING);
 doCube();

 xrot+=xspeed;
 yrot+=yspeed;
 if (xrot>360.0f) xrot-=360.0f;
 if (xrot<0.0f) xrot+=360.0f;
 if (yrot>360.0f) yrot-=360.0f;
 if (yrot<0.0f) yrot+=360.0f;

 doLogo();
 return true;        
}

  
 所有的繪制函數(shù)都已經(jīng)完成,接下來(lái)只要在繪制函數(shù)中調(diào)用即可 
  

bool DrawGLScene(GLvoid) 
{
 if (bumps) {
  if (useMultitexture && maxTexelUnits>1)
   return doMesh2TexelUnits();
  else return doMesh1TexelUnits();  }
 else return doMeshNoBumps();
}

  
 刪除OpenGL窗口 
  

GLvoid KillGLWindow(GLvoid)  
  
 創(chuàng)建OpenGL窗口 
  

BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)

  
 Windows循環(huán) 
  

LRESULT CALLBACK WndProc( HWND hWnd,
    UINT uMsg,     
    WPARAM wParam,     
    LPARAM lParam)     
  
 在Windows主函數(shù)中加入一些控制鍵 :
E: 切換凹凸貼圖模式中是否帶有彩色紋理
M: 切換多重紋理模式
B: 切換是否使用凹凸貼圖
F: 切換紋理過(guò)濾器模式
方向鍵: 旋轉(zhuǎn)立方體
 
  

    if (keys['E'])
    {
     keys['E']=false;
     emboss=!emboss;
    }

    if (keys['M'])
    {
     keys['M']=false;
     useMultitexture=((!useMultitexture) && multitextureSupported);
    }

    if (keys['B'])
    {
     keys['B']=false;
     bumps=!bumps;
    }

    if (keys['F'])
    {
     keys['F']=false;
     filter++;
     filter%=3;
    }

    if (keys[VK_PRIOR])
    {
     z-=0.02f;
    }

    if (keys[VK_NEXT])
    {
     z+=0.02f;
    }

    if (keys[VK_UP])
    {
     xspeed-=0.01f;
    }

    if (keys[VK_DOWN])
    {
     xspeed+=0.01f;
    }

    if (keys[VK_RIGHT])
    {
     yspeed+=0.01f;
    }

    if (keys[VK_LEFT])
    {
     yspeed-=0.01f;
    }

  
 現(xiàn)在你應(yīng)該可以熟練的使用凹凸貼圖了,如果你想讓你的具有凹凸貼圖的程序跑起來(lái)更快,你應(yīng)該注意以下幾點(diǎn):
你不應(yīng)該使用256x256的紋理,這會(huì)讓處理變得緩慢。
一個(gè)具有凹凸貼圖的立方體是不常見(jiàn)的,這和你的視角有關(guān),因?yàn)槿敲孢^(guò)于大了,如果要獲得很好的視覺(jué)效果,你需要很大的紋理貼圖,這必然會(huì)降低渲染速度。你可以把模型 創(chuàng)建為一些小的三角形,從而使用小的紋理,來(lái)獲得好的效果。
你應(yīng)該先創(chuàng)建顏色紋理,接著把它轉(zhuǎn)換為具有深度的凹凸紋理
凹凸紋理應(yīng)該銳化,這可以取得更好的效果,在你的圖像處理程序中可以完成這個(gè)操作。
凹凸貼圖的值因該在50%灰度圖上波動(dòng)(RGB=127,127,127), 亮的值代表凸起,暗的值代表凹陷。
凹凸貼圖可以為紋理圖大小的1/4,而不會(huì)影響外觀效果。
現(xiàn)在你應(yīng)該對(duì)這篇文章中內(nèi)容的大慨有了一個(gè)基本的認(rèn)識(shí),希望你讀的愉快。
如果你有任何紋理,請(qǐng)聯(lián)系我或訪(fǎng)問(wèn)我的網(wǎng)站http://www.glhint.de
我必須感謝以下的人:

Michael I. Gold ,它寫(xiě)出了凹凸貼圖的原理
Diego Tártara ,它寫(xiě)出了示例代碼
NVidia 公司,他在Internet發(fā)布了大量的源碼
最后感謝Nehe,它對(duì)我的OpenGL學(xué)習(xí)起了很大的幫助 

posted on 2007-12-17 18:57 sdfasdf 閱讀(1831) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): OPENGL
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产成人在线视频| 国产偷久久久精品专区| 亚洲片在线资源| 久久精品国产69国产精品亚洲| 99天天综合性| 一本一本a久久| 亚洲自拍另类| 久久国产精品一区二区三区四区| 香蕉精品999视频一区二区| 性欧美在线看片a免费观看| 欧美在线观看网址综合| 久久精品亚洲热| 欧美不卡高清| 一本色道久久88综合亚洲精品ⅰ | 亚洲精品免费在线播放| 99视频超级精品| 亚洲欧美美女| 久热国产精品| 亚洲精品你懂的| 亚洲日本免费| 亚洲免费视频观看| 蜜臀久久99精品久久久画质超高清| 欧美精品一区二区蜜臀亚洲 | 国产一区二区三区电影在线观看| 黑人巨大精品欧美黑白配亚洲| 在线观看视频免费一区二区三区| 亚洲精品一区二区三区不| 亚洲综合欧美| 亚洲高清不卡av| 亚洲网友自拍| 欧美r片在线| 国产欧美一区二区三区在线看蜜臀| 在线国产精品播放| 午夜精品美女自拍福到在线| 麻豆成人在线观看| 亚洲五月六月| 欧美日韩人人澡狠狠躁视频| 欧美大片在线看| 久久永久免费| 亚洲天堂av高清| 亚洲图片欧美一区| 欧美大片在线看免费观看| 亚洲视频综合| 欧美日韩免费一区二区三区| 影音先锋亚洲视频| 久久国内精品自在自线400部| 亚洲国产精品久久| 久久亚洲综合| 国产一区二区0| 香蕉久久久久久久av网站| 最新亚洲视频| 美女被久久久| 黑人中文字幕一区二区三区| 亚洲午夜国产成人av电影男同| 美女国产一区| 久久精品国产视频| 国产亚洲精品自拍| 亚洲欧美综合精品久久成人| 亚洲人成在线免费观看| 久久一区二区三区av| 国产精品免费视频xxxx| 亚洲作爱视频| 在线亚洲精品福利网址导航| 欧美日韩情趣电影| 在线一区二区三区做爰视频网站| 欧美高清hd18日本| 老鸭窝亚洲一区二区三区| 极品少妇一区二区三区| 久久久xxx| 亚洲日本一区二区| 欧美日韩国产不卡在线看| 亚洲美女区一区| 亚洲成色777777在线观看影院| 久久久久久久999精品视频| 亚洲欧美一区二区精品久久久| 国产精品美女久久久免费| 欧美一级精品大片| 欧美一区二区三区久久精品| 黄色成人片子| 亚洲第一黄色| 欧美日韩1区2区3区| 亚洲一区二区三区涩| 亚洲一区免费网站| 国内精品久久久久国产盗摄免费观看完整版 | 一区二区三区毛片| 欧美午夜激情小视频| 欧美一级二级三级蜜桃| 久久激情视频| 亚洲精品中文字| 亚洲无限乱码一二三四麻| 国产日韩高清一区二区三区在线| 久久久亚洲国产天美传媒修理工| 久久国产精品一区二区三区| 亚洲精品在线观| 亚洲视频1区2区| 国产精品影片在线观看| 久久婷婷丁香| 欧美精品aa| 99精品99| 性做久久久久久久久| 最新国产成人av网站网址麻豆| 亚洲欧洲日本mm| 国产麻豆日韩| 欧美激情一区二区在线| 欧美色道久久88综合亚洲精品| 久久精品国产综合| 欧美精品一卡| 免费在线国产精品| 欧美色另类天堂2015| 久久亚洲欧洲| 欧美精品免费播放| 久久综合久久久| 久久成人羞羞网站| 99热在线精品观看| 欧美在线看片a免费观看| 99国产一区| 久久九九精品| 欧美一区二区久久久| 欧美精品九九99久久| 久久久久久网| 国产九九精品| 99热精品在线| 亚洲日韩成人| 亚洲国产精品视频一区| 国内精品久久国产| 中文久久精品| av成人黄色| 久久夜色精品| 久久精品视频免费播放| 国产精品蜜臀在线观看| 日韩性生活视频| 日韩一级片网址| 免费人成精品欧美精品| 美国三级日本三级久久99| 国产伊人精品| 欧美在线视频全部完| 欧美诱惑福利视频| 国产精品推荐精品| 亚洲欧美福利一区二区| 性欧美xxxx视频在线观看| 国产精品午夜在线观看| 亚洲一区二区三区高清| 性8sex亚洲区入口| 国产人久久人人人人爽| 欧美一区日本一区韩国一区| 欧美在线91| 国产日韩欧美夫妻视频在线观看| 亚洲一线二线三线久久久| 欧美一区影院| 国产亚洲视频在线| 久久中文精品| 最新日韩欧美| 亚洲无限av看| 国产精品美女久久久久av超清 | 亚洲伦理一区| 国产精品国产三级国产普通话99| 亚洲精华国产欧美| 久久久噜噜噜| 亚洲免费在线看| 国产欧美亚洲一区| 久久久精品性| 亚洲网在线观看| 久久久久**毛片大全| 亚洲成色999久久网站| 欧美精品久久久久久久久老牛影院 | 欧美中在线观看| 国产日韩欧美在线看| 亚洲视频你懂的| 欧美a级一区| 亚洲精品视频在线播放| 免费观看成人| 亚洲国产精品久久91精品| 99riav1国产精品视频| 欧美日韩天堂| 亚洲欧美日本日韩| 老色批av在线精品| 亚洲激情在线| 国产精品狠色婷| 亚洲永久视频| 中文欧美在线视频| 又紧又大又爽精品一区二区| 免费国产自线拍一欧美视频| 亚洲精品免费电影| 久久亚洲综合色| 亚洲精品久久久一区二区三区| 欧美日韩午夜在线视频| 亚洲欧美日产图| 一区二区三区不卡视频在线观看| 欧美激情亚洲| 亚洲免费影视第一页| 国产一区二区日韩| 欧美精品免费在线| 久久一综合视频| 亚洲午夜精品网| 欧美a级片一区| 日韩系列在线| 国产精品在线看| 欧美a级一区二区| 欧美一级专区| 午夜日韩激情|