? ? 德者嘴秸,本也。財(cái)者署辉,末也哭尝。但行好事材鹦,莫問前程桶唐。
一茉兰、認(rèn)識(shí)紋理
? ? ? ? ? 紋理是什么规脸?你可以把它理解成一張貼紙一樣的東西,在物體表面貼上圖案闹丐,紋理的作用就是用來裝飾我們的物體模型卿拴,就像裝修的時(shí)候,在家里的墻壁上貼墻紙一樣,當(dāng)然紋理的作用應(yīng)該遠(yuǎn)遠(yuǎn)不止這些如贷。
個(gè)人思考:在一些游戲場(chǎng)景中尚猿,特別是地圖伴榔,比如吃雞這種主機(jī)游戲踪少,場(chǎng)景都是用很多相同的,類似3D紋理的立體圖形拼出來的糠涛,比如一片草地忍捡,一片樹林,一片房屋具篇,這些3D場(chǎng)景和墻紙及紋理的定義沒有本質(zhì)上的區(qū)別驱显,不知廣義上把這些“場(chǎng)景貼紙”稱為紋理合不合適埃疫?大佬可以在評(píng)論區(qū)告知我或者可以一起討論。
二挨下、紋理基礎(chǔ)
? ? 了解紋理基礎(chǔ)之前熔恢,讓我們先來了解一下圖像的存儲(chǔ)
1、原始圖像數(shù)據(jù)在內(nèi)存中的存儲(chǔ)
圖像占用的存儲(chǔ)空間 = 圖像的高度 * 圖像的寬度 * 每個(gè)像素點(diǎn)的字節(jié)數(shù)
2臭笆、認(rèn)識(shí)OpenGL圖像存儲(chǔ)相關(guān)函數(shù)
1叙淌、改變像素存儲(chǔ)方式
void glPixelStorei(GLenum pname, GLint param)
2秤掌、恢復(fù)像素存儲(chǔ)方式
void glPxielStoref (GLenum pname, GLFloat param)
參數(shù)1:GL_UNPACK_ALIGNMENT,指定OpenGL如何從數(shù)據(jù)緩存區(qū)中解包圖像數(shù)據(jù);
參數(shù)2:表示參數(shù)GL_UNPACK_ALIGNMENT設(shè)置的值鹰霍。GL_UNPACK_ALIGNMENT指內(nèi)存中的每一個(gè)像素行起點(diǎn)的排列請(qǐng)求闻鉴,允許設(shè)置為1(byte排列)、2(排列為偶數(shù)byte的行)茂洒、4(字word排列)8(行從雙字節(jié)邊界開始)
例:glPxielStorei(GL_UNPACK_ALIGNMENT, 1)
3孟岛、從顏色緩沖區(qū)內(nèi)容作為像素圖直接讀取(重要)
void glReadPixels(GLint x,? GLint y, GLSizei width, GLSizei height, GLenum format, GLenum type, const void*pixels);
參數(shù)1:x,矩形左下角的窗口坐標(biāo)x值
參數(shù)2:y屯吊,矩形左下角的窗口坐標(biāo)y值
參數(shù)3:width,矩形的寬,以像素為單位
參數(shù)4:height,矩形的高,以像素為單位
參數(shù)5:format体箕,OpenGL的像素格式站叼,參照下表1
參數(shù)6:type第练,解釋參數(shù)pxiels指向的數(shù)據(jù),告訴OpenGL使用緩沖區(qū)的什么數(shù)據(jù)類型來存儲(chǔ)顏色分量,像素?cái)?shù)據(jù)的數(shù)據(jù)類型塞蹭,參照下表2
參數(shù)7:pxiels,指向圖形數(shù)據(jù)的指針
4瘟裸、載入紋理
void glTexImage1D(GLenum target 超棺, GLint level, GLint internalformat夜矗, GLsizei width对扶, GLint border络凿, GLenum format, GLenum type, void*data)
void glTexImage2D(GLenum target , GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type劫流, void*data)
void glTexImage3D(GLenum target , GLint level姜骡, GLint internalformat惫周, GLsizei width, GLsizei height登舞,GLsizei depth悬荣, GLint border践叠, GLenum format弄捕, GLenum type悴务, void*data)
參數(shù)1:target:GL_TEXTURE_2D,GL_TEXTURE_1D, GL_TEXTURE_3D
參數(shù)2:level指定所加載的mip貼圖層次,一般我們都把這個(gè)參數(shù)設(shè)置為0.
參數(shù)3:internalformat:每個(gè)紋理單元中存儲(chǔ)多少顏色成分菇怀。
參數(shù)4:width,height爱沟,depth參數(shù):指的是加載紋理的寬度帅霜、高度、深度呼伸;需要注意的是這些數(shù)必須是2的整數(shù)次方义屏。這個(gè)因?yàn)镺penGL舊版本上遺留下的一個(gè)要求,當(dāng)然現(xiàn)在已經(jīng)支持可以不是2的整數(shù)次方,但是開發(fā)者已經(jīng)習(xí)慣使用2的證書此房去設(shè)置這些參數(shù)闽铐。
參數(shù)5:border:允許為紋理貼圖制定一個(gè)邊界寬度
參數(shù)6:format蝶怔、type、data參數(shù)與glDrawPxiels函數(shù)對(duì)于的參數(shù)相同兄墅。
5踢星、更新紋理
void glTexSubImage1D(GLenum target,GLint level隙咸,GLint xOffset沐悦, GLint yoffset,GLSizei width五督, GLenum format藏否, GLenum type,const? GLvoid * data)
void glTexSubImage2D(GLenum target充包,GLint level副签,GLint xOffset, GLint yoffset基矮,GLSizei width淆储, GLSizei height, GLenum format家浇, GLenum type本砰,const? GLvoid * data)
void glTexSubImage3D(GLenum target,GLint level钢悲,GLint xOffset点额, GLint yoffset,GLSizei width莺琳, GLSizei height咖楣,GLsizei depth, GLenum format芦昔, GLenum type,const? GLvoid * data)
1D娃肿,2D咕缎,3D的區(qū)別只在于3D比1D多了depth.height,2D只比1D多了height
6料扰、插入替換紋理
void glCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset,GLsizei width,GLsizei height)
void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yOffset,GLsizei width,GLsizei height)
void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset凭豪, GLint yOffset,GLint zOffset,GLsizei width,GLsizei height)
1D,2D晒杈,3D的區(qū)別只在于1D只有xOffset嫂伞,2D有xOffset yOffset,3D比2D多了zOffset
7、使用顏色緩沖區(qū)加載數(shù)據(jù)帖努,形成新的紋理使用
void glCopyTexImage1D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,GLsizei width, GLint border)
void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,GLsizei width, GLsizei height, GLint border)
x,y在顏色緩沖區(qū)中指定了開始讀取紋理數(shù)據(jù)的位置:緩沖區(qū)里面的數(shù)據(jù)是源緩沖區(qū)通過glReadBuffer設(shè)置的
注意:不存在glCopyTexImage3D撰豺,因?yàn)槲覀儫o法從2D顏色緩沖區(qū)中獲取體積數(shù)據(jù)
8、使用函數(shù)分配紋理對(duì)象(重要)
指定紋理對(duì)象的數(shù)量和指針拼余,(指針指向一個(gè)無符號(hào)整形數(shù)據(jù)污桦,由紋理對(duì)象標(biāo)識(shí)符填充)
void glGenTexTures(GLsizei n,GLuint * textures)匙监;
9凡橱、綁定紋理狀態(tài)(重要)
void glBindTexture(GLenum target, GLunit texture)亭姥;
參數(shù)1:target:GL_TEXTURE_2D,GL_TEXTURE_1D, GL_TEXTURE_3D
參數(shù)2:需要綁定的紋理對(duì)象
10稼钩、刪除綁定紋理對(duì)象(重要)
void glDeleteTexture(GLsizei n, GLuint * texture)达罗;
紋理對(duì)象以及紋理對(duì)象指針(指針指向一個(gè)無符號(hào)整形數(shù)組坝撑,由紋理對(duì)象標(biāo)識(shí)符填充)
11、測(cè)試紋理對(duì)象是否有效
如果texture是一個(gè)已經(jīng)分配空間的紋理對(duì)象氮块,那么這個(gè)函數(shù)會(huì)返回GL_TURE绍载,否則會(huì)返回GL_FALST
GLboolean glIsTexture(GLuint texture);
12滔蝉、設(shè)置紋理參數(shù)
glTextureParameter(GLenum target击儡, GLenum pname, GLFloat param)蝠引;
glTextureParameter(GLenum target阳谍, GLenum pname, GLint param)螃概;
glTextureParameter(GLenum target矫夯, GLenum pname, GLFloat * param)吊洼;
glTextureParameter(GLenum target训貌, GLenum pname, GLint *param)
參數(shù)1:target冒窍,指定這些參數(shù)應(yīng)用哪個(gè)紋理模式上递沪,比如GL_TEXTURE_2D,GL_TEXTURE_1D, GL_TEXTURE_3D
參數(shù)2:pname,指定需要設(shè)置哪個(gè)紋理參數(shù)
參數(shù)3:設(shè)定特定的紋理參數(shù)的值
13综液、設(shè)置過濾方式(也叫取樣)(重點(diǎn))
1款慨、鄰近過濾 GL_NEAREST
鄰近過濾是最簡(jiǎn)單最快速的過濾方法,它總是把最鄰近的紋理單元取到紋理坐標(biāo)中谬莹。
2桩了、線性過濾GL_LINEAR
線性過濾會(huì)把這個(gè)紋理坐標(biāo)周圍的紋理單元加權(quán)平均值應(yīng)用到這個(gè)紋理坐標(biāo)中。周圍坐標(biāo)的紋理單元距離越近埠戳,則權(quán)值越大
一般建議紋理縮小用鄰近過濾,紋理放大用線性過濾,當(dāng)然你也可以隨意搭配
glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
14乞而、設(shè)置環(huán)繞方式
glTextParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAR_S, GL_CLAMP_TO_EDGE);
glTextParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAR_T, GL_CLAMP_TO_EDGE)
參數(shù)1: GL_TEXTURE_1D送悔、GL_TEXTURE_2D、GL_TEXTURE_3D
參數(shù)2:GL_TEXTURE_WRAP_S爪模、GL_TEXTURE_T欠啤、GL_TEXTURE_R,針對(duì)s,t,r坐標(biāo)
S 、T屋灌、 R 坐標(biāo)系對(duì)應(yīng)著世界坐標(biāo)系的X洁段, Y, Z
參數(shù)3:GL_REPEAT共郭、GL_CLAMP祠丝、GL_CLAMP_TO_EDGE、GL_CLAMP_TO_BORDER
GL_REPEAT:OpenGL 在紋理坐標(biāo)超過1.0的?向上對(duì)紋理進(jìn)?重復(fù);
GL_CLAMP:所需的紋理單元取?紋理邊界或TEXTURE_BORDER_COLOR.
GL_CLAMP_TO_EDGE環(huán)繞模式強(qiáng)制對(duì)范圍之外的紋理坐標(biāo)沿著合法的紋理單元的最后一行或者最后?列來進(jìn)行采樣除嘹。
GL_CLAMP_TO_BORDER:在紋理坐標(biāo)在0.0到1.0范圍之外的只使?邊界紋理單元写半。邊界紋理單元是作為圍繞基本圖像的額外的?和列列,并與基本紋理圖像?起加載的
三、金字塔繪制及紋理填充
1、主函數(shù)中設(shè)置環(huán)境及注冊(cè)函數(shù)
intmain(intargc,char* argv[])
{
? ? gltSetWorkingDirectory(argv[0]);
?? ?glutInit(&argc, argv);
? ? glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
? ? glutInitWindowSize(800, 600);
? ? glutCreateWindow("Pyramid");
? ? glutReshapeFunc(ChangeSize);
? ? glutSpecialFunc(SpecialKeys);
? ? glutDisplayFunc(RenderScene);
? ? GLenum err = glewInit();
? ? if(GLEW_OK!= err) {
? ? ? ? fprintf(stderr,"GLEW Error: %s\n",glewGetErrorString(err));
? ? ? ? return1;
? ? }
? ? SetupRC();
? ? glutMainLoop();
? ? ShutdownRC();//重要单芜,紋理綁定后需要進(jìn)行解綁
? ? return 0;
}
2蜕该、定義全局變量
GLShaderManager shaderManager;//著色器程序
GLMatrixStack modelViewMatrix;//模型視圖矩陣
GLMatrixStack projectionMatrix;
GLFrame cameraFrame;//觀察者坐標(biāo)
GLFrame? ? ? ? ? ? objectFrame;//對(duì)象坐標(biāo)
GLFrustum viewFrustum;//
GLBatch? ? ? ? ? ? pyramidBatch;//金字塔
GLuint? ? ? ? ? ? ? textureID;//紋理變量,一般使用無符號(hào)整型
GLGeometryTransform transformPipeline;
M3DMatrix44f shadowMatrix;
3洲鸠、開始設(shè)置環(huán)境
voidSetupRC()
{
? ? //1.初始化著色器堂淡,設(shè)置清屏顏色
? ? glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
? ? shaderManager.InitializeStockShaders();
? ? //2.開啟深度測(cè)試
? ? glEnable(GL_DEPTH_TEST);
? ? //3.分配紋理對(duì)象
? ? // 參數(shù)1:紋理對(duì)象個(gè)數(shù),金字塔的5個(gè)面扒腕,共6個(gè)三角形绢淀,但是用的是同一個(gè)紋理,所以紋理對(duì)象個(gè)數(shù)為1袜匿。
//參數(shù)2:紋理對(duì)象指針,之前定義過了紋理對(duì)象稚疹,直接拿下來取地址就行了
? ? glGenTextures(1, &textureID);
? ? //4居灯、綁定紋理狀態(tài)?
? ?//參數(shù)1:紋理狀態(tài)2D 參數(shù)2:紋理對(duì)象
? ? glBindTexture(GL_TEXTURE_2D, textureID);
? ? //將TGA文件加載為2D紋理祭务。
? ? //參數(shù)1:紋理文件名稱
? ? //參數(shù)2&參數(shù)3:需要縮小&放大的過濾器
? ? //參數(shù)4:紋理坐標(biāo)環(huán)繞模式
? ? LoadTGATexture("stone.tga", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, GL_CLAMP_TO_EDGE);
? ? //5.創(chuàng)造金字塔pyramidBatch
? ? MakePyramid(pyramidBatch);
? ? //6.調(diào)整觀察者位置
? ? /**相機(jī)frame MoveForward(平移)
? ? 參數(shù)1:Z,深度(屏幕到圖形的Z軸距離)
?? ? */
? ? cameraFrame.MoveForward(-10);
}
4怪嫌、渲染場(chǎng)景
步驟一:設(shè)置場(chǎng)景
voidRenderScene(void)
{
? ? //1.顏色值&光源位置
? ? staticGLfloatvLightPos [] = {1.0f,1.0f,0.0f};
? ? staticGLfloatvWhite [] = {1.0f,1.0f,1.0f,1.0f};
? ? //2.清理緩沖區(qū)
? ? glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
? ? //3.當(dāng)前模型視圖壓棧
? ? modelViewMatrix.PushMatrix();
? ? //添加照相機(jī)矩陣
? ? M3DMatrix44fmCamera;
? ? //從camraFrame中獲取一個(gè)4*4的矩陣
? ? cameraFrame.GetCameraMatrix(mCamera);
? ? //矩陣乘以矩陣堆棧頂部矩陣觅够,相乘結(jié)果存儲(chǔ)到堆棧的頂部 將照相機(jī)矩陣 與 當(dāng)前模型矩陣相乘 壓入棧頂
? ? modelViewMatrix.MultMatrix(mCamera);
? ? //創(chuàng)建mObjectFrame矩陣
? ? M3DMatrix44fmObjectFrame;
? ? //從objectFrame中獲取矩陣机断,objectFrame保存的是特殊鍵位的變換矩陣
? ? objectFrame.GetMatrix(mObjectFrame);
? ? //矩陣乘以矩陣堆棧頂部矩陣,相乘結(jié)果存儲(chǔ)到堆棧的頂部 將世界變換矩陣 與 當(dāng)前模型矩陣相乘 壓入棧頂
? ? modelViewMatrix.MultMatrix(mObjectFrame);
? ? //4.綁定紋理,因?yàn)槲覀兊捻?xiàng)目中只有一個(gè)紋理姑子。如果有多個(gè)紋理。綁定紋理很重要
? ? glBindTexture(GL_TEXTURE_2D, textureID);
? ? /*5.點(diǎn)光源著色器
?? ? 參數(shù)1:GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF(著色器標(biāo)簽)
?? ? 參數(shù)2:模型視圖矩陣
?? ? 參數(shù)3:投影矩陣
?? ? 參數(shù)4:視點(diǎn)坐標(biāo)系中的光源位置
?? ? 參數(shù)5:基本漫反射顏色
?? ? 參數(shù)6:圖形顏色(用紋理就不需要設(shè)置顏色换帜。設(shè)置為0)
?? ? */
? ? shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? transformPipeline.GetModelViewMatrix(),
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? transformPipeline.GetProjectionMatrix(),
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? vLightPos, vWhite,0);
? ? //pyramidBatch 繪制
? ? pyramidBatch.Draw();
? ? //模型視圖出棧藏雏,恢復(fù)矩陣(push一次就要pop一次,push和pop成對(duì)存在)
? ? modelViewMatrix.PopMatrix();
? ? //6.交換緩存區(qū)
? ? glutSwapBuffers();
}
步驟二:繪制金字塔
voidMakePyramid(GLBatch& pyramidBatch)
{
? ? /*1找爱、通過pyramidBatch組建三角形批次
? ? ? 參數(shù)1:類型
? ? ? 參數(shù)2:頂點(diǎn)數(shù)
? ? ? 參數(shù)3:這個(gè)批次中將會(huì)應(yīng)用1個(gè)紋理
? ? ? 注意:如果不寫這個(gè)參數(shù)梗顺,默認(rèn)為0。
?? ? */
? ? pyramidBatch.Begin(GL_TRIANGLES,18,1);
? ? /***前情導(dǎo)入
?? ? 1)設(shè)置法線
?? ? void Normal3f(GLfloat x, GLfloat y, GLfloat z);
?? ? Normal3f:添加一個(gè)表面法線(法線坐標(biāo) 與 Vertex頂點(diǎn)坐標(biāo)中的Y軸一致)
?? ? 表面法線是有方向的向量车摄,代表表面或者頂點(diǎn)面對(duì)的方向(相反的方向)寺谤。在多數(shù)的關(guān)照模式下是必須使用。后面的課程會(huì)詳細(xì)來講法線的應(yīng)用
?? ? pyramidBatch.Normal3f(X,Y,Z);
?? ? 2)設(shè)置紋理坐標(biāo)
?? ? void MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);
?? ? 參數(shù)1:texture吮播,紋理層次变屁,對(duì)于使用存儲(chǔ)著色器來進(jìn)行渲染,設(shè)置為0
?? ? 參數(shù)2:s:對(duì)應(yīng)頂點(diǎn)坐標(biāo)中的x坐標(biāo)
?? ? 參數(shù)3:t:對(duì)應(yīng)頂點(diǎn)坐標(biāo)中的y
?? ? (s,t,r,q對(duì)應(yīng)頂點(diǎn)坐標(biāo)的x,y,z,w)
?? ? pyramidBatch.MultiTexCoord2f(0,s,t);
?? ? 3)void Vertex3f(GLfloat x, GLfloat y, GLfloat z);
? ? ? void Vertex3fv(M3DVector3f vVertex);
?? ? 向三角形批次類添加頂點(diǎn)數(shù)據(jù)(x,y,z);
? ? ? pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
?? ? 4)獲取從三點(diǎn)找到一個(gè)法線坐標(biāo)(三點(diǎn)確定一個(gè)面)
?? ? void m3dFindNormal(result,point1, point2,point3);
?? ? 參數(shù)1:結(jié)果
?? ? 參數(shù)2-4:3個(gè)頂點(diǎn)數(shù)據(jù)
?? ? */
? ? //塔頂
? ? M3DVector3fvApex = {0.0f,1.0f,0.0f};
? ? M3DVector3fvFrontLeft = { -1.0f, -1.0f,1.0f};
? ? M3DVector3fvFrontRight = {1.0f, -1.0f,1.0f};
? ? M3DVector3fvBackLeft = { -1.0f,? -1.0f, -1.0f};
? ? M3DVector3fvBackRight = {1.0f,? -1.0f, -1.0f};
? ? M3DVector3f n;
? ? //金字塔底部
? ? //底部的四邊形 = 三角形X + 三角形Y
? ? //三角形X = (vBackLeft,vBackRight,vFrontRight)
? ? //1.找到三角形X 法線
? ? m3dFindNormal(n, vBackLeft, vBackRight, vFrontRight);
? ? //vBackLeft
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vBackLeft);
? ? //vBackRight
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,1.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vBackRight);
? ? //vFrontRight
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,1.0f,1.0f);
? ? pyramidBatch.Vertex3fv(vFrontRight);
? ? //三角形Y =(vFrontLeft,vBackLeft,vFrontRight)
? ? //1.找到三角形X 法線
? ? m3dFindNormal(n, vFrontLeft, vBackLeft, vFrontRight);
? ? //vFrontLeft
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.0f,1.0f);
? ? pyramidBatch.Vertex3fv(vFrontLeft);
? ? //vBackLeft
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vBackLeft);
? ? //vFrontRight
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,1.0f,1.0f);
? ? pyramidBatch.Vertex3fv(vFrontRight);
? ? // 金字塔前面
? ? //三角形:(Apex意狠,vFrontLeft粟关,vFrontRight)
? ? m3dFindNormal(n, vApex, vFrontLeft, vFrontRight);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.5f,1.0f);
? ? pyramidBatch.Vertex3fv(vApex);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vFrontLeft);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,1.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vFrontRight);
? ? //金字塔左邊
? ? //三角形:(vApex, vBackLeft, vFrontLeft)
? ? m3dFindNormal(n, vApex, vBackLeft, vFrontLeft);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.5f,1.0f);
? ? pyramidBatch.Vertex3fv(vApex);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,1.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vBackLeft);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vFrontLeft);
? ? //金字塔右邊
? ? //三角形:(vApex, vFrontRight, vBackRight)
? ? m3dFindNormal(n, vApex, vFrontRight, vBackRight);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.5f,1.0f);
? ? pyramidBatch.Vertex3fv(vApex);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,1.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vFrontRight);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vBackRight);
? ? //金字塔后邊
? ? //三角形:(vApex, vBackRight, vBackLeft)
? ? m3dFindNormal(n, vApex, vBackRight, vBackLeft);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.5f,1.0f);
? ? pyramidBatch.Vertex3fv(vApex);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vBackRight);
? ? pyramidBatch.Normal3fv(n);
? ? pyramidBatch.MultiTexCoord2f(0,1.0f,0.0f);
? ? pyramidBatch.Vertex3fv(vBackLeft);
? ? //結(jié)束批次設(shè)置
? ? pyramidBatch.End();
}
步驟三:自定義函數(shù) ,從TGA文件加載2D紋理摄职。
boolLoadTGATexture(constchar*szFileName,GLenumminFilter,GLenummagFilter,GLenumwrapMode)
{
? ? GLbyte*pBits;
? ? intnWidth, nHeight, nComponents;
? ? GLenumeFormat;
? ? //1誊役、讀紋理位,讀取像素
? ? //參數(shù)1:紋理文件名稱
? ? //參數(shù)2:文件寬度地址
? ? //參數(shù)3:文件高度地址
? ? //參數(shù)4:文件組件地址
? ? //參數(shù)5:文件格式地址
? ? //返回值:pBits,指向圖像數(shù)據(jù)的指針
? ? pBits =gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
? ? if(pBits ==NULL)
? ? ? ? return false;
? ? //2谷市、設(shè)置紋理參數(shù)
? ? //參數(shù)1:紋理維度
? ? //參數(shù)2:為S/T坐標(biāo)設(shè)置模式
? ? //參數(shù)3:wrapMode,環(huán)繞模式
? ? glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
? ? glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
? ? //參數(shù)1:紋理維度
? ? //參數(shù)2:線性過濾
? ? //參數(shù)3:wrapMode,環(huán)繞模式
? ? glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
? ? glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
? ? //3.載入紋理
? ? //參數(shù)1:紋理維度
? ? //參數(shù)2:mip貼圖層次
? ? //參數(shù)3:紋理單元存儲(chǔ)的顏色成分(從讀取像素圖是獲得)
? ? //參數(shù)4:加載紋理寬
? ? //參數(shù)5:加載紋理高
? ? //參數(shù)6:加載紋理的深度
? ? //參數(shù)7:像素?cái)?shù)據(jù)的數(shù)據(jù)類型(GL_UNSIGNED_BYTE蛔垢,每個(gè)顏色分量都是一個(gè)8位無符號(hào)整數(shù))
? ? //參數(shù)8:指向紋理圖像數(shù)據(jù)的指針
? ? glTexImage2D(GL_TEXTURE_2D,0, nComponents, nWidth, nHeight,0,
?? ? ? ? ? ? ? ? eFormat,GL_UNSIGNED_BYTE, pBits);
? ? //使用完畢釋放pBits
? ? free(pBits);
? ? //4.加載Mip,紋理生成所有的Mip層
? ? //參數(shù):GL_TEXTURE_1D、GL_TEXTURE_2D迫悠、GL_TEXTURE_3D
? ? glGenerateMipmap(GL_TEXTURE_2D);
? ? return true;
}
5鹏漆、窗口改變監(jiān)聽
voidChangeSize(intw,inth)
{
? ? //1.設(shè)置視口
? ? glViewport(0,0, w, h);
? ? //2.創(chuàng)建投影矩陣
? ? viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
? ? //viewFrustum.GetProjectionMatrix()? 獲取viewFrustum投影矩陣
? ? //并將其加載到投影矩陣堆棧上
? ? projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
? ? //3.設(shè)置變換管道以使用兩個(gè)矩陣堆棧(變換矩陣modelViewMatrix ,投影矩陣projectionMatrix)
? ? //初始化GLGeometryTransform 的實(shí)例transformPipeline.通過將它的內(nèi)部指針設(shè)置為模型視圖矩陣堆棧 和 投影矩陣堆棧實(shí)例创泄,來完成初始化
? ? //當(dāng)然這個(gè)操作也可以在SetupRC 函數(shù)中完成艺玲,但是在窗口大小改變時(shí)或者窗口創(chuàng)建時(shí)設(shè)置它們并沒有壞處。而且這樣可以一次性完成矩陣和管線的設(shè)置鞠抑。
? ? transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
6饭聚、特殊鍵位操作
voidSpecialKeys(intkey,intx,inty)
{
? ? if(key ==GLUT_KEY_UP)
? ? ? ? objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
? ? if(key == GLUT_KEY_DOWN)
? ? ? ? objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
? ? if(key == GLUT_KEY_LEFT)
? ? ? ? objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
? ? if(key == GLUT_KEY_RIGHT)
? ? ? ? objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
? ? glutPostRedisplay();//視口改變,更新窗口
}
7搁拙、最后需要清除綁定的紋理
voidShutdownRC(void)
{
? ? glDeleteTextures(1, &textureID);
}
8秒梳、最終效果圖
[溪浣雙鯉的技術(shù)摸爬滾打之路](http://www.reibang.com/p/3fbecd65faae)