iOS圖像:OpenGL(下)

原創(chuàng):知識(shí)探索型文章
創(chuàng)作不易,請(qǐng)珍惜日川,之后會(huì)持續(xù)更新淮阐,不斷完善
個(gè)人比較喜歡做筆記和寫總結(jié)叮阅,畢竟好記性不如爛筆頭哈哈,這些文章記錄了我的IOS成長(zhǎng)歷程泣特,希望能與大家一起進(jìn)步
溫馨提示:由于簡(jiǎn)書不支持目錄跳轉(zhuǎn)浩姥,大家可通過(guò)command + F 輸入目錄標(biāo)題后迅速尋找到你所需要的內(nèi)容

目錄

  • 一、OpenGL變化
    • 1群扶、3D數(shù)學(xué)
    • 2及刻、仿射變換
  • 二镀裤、繪制圖形
    • 1竞阐、繪制球體
    • 2、繪制其他圖形
    • 3暑劝、繪制自動(dòng)旋轉(zhuǎn)的球體
    • 4骆莹、繪制圍繞太陽(yáng)旋轉(zhuǎn)的地球
  • 三、OpenGL紋理
    • 1担猛、繪制金字塔
    • 2幕垦、繪制隧道
    • 3、繪制自動(dòng)旋轉(zhuǎn)的球體世界
  • Demo
  • 參考文獻(xiàn)

續(xù)文見(jiàn)上篇:iOS多媒體:OpenGL(上)


一傅联、OpenGL變化

1先改、3D數(shù)學(xué)

a、3D數(shù)學(xué)的介紹

GITools庫(kù)中有一個(gè)組件叫Math3d蒸走,其中包含了大量好用的OpenGL的3D數(shù)學(xué)類型仇奶。雖然我們不必親自進(jìn)行所有的矩陣和向量的操作,但我們需要知道它們是什么以及如何運(yùn)用它們比驻。AR Kit框架以及Unity3D该溯、游戲開(kāi)發(fā)都必須學(xué)習(xí)3D數(shù)學(xué)知識(shí)岛抄。

在開(kāi)發(fā)過(guò)程中,我們涉及到的圖形變換狈茉,就會(huì)涉及到矩陣/向量的計(jì)算夫椭。例如大家在使用CAnimation實(shí)現(xiàn)仿射變換時(shí)就使用了OpenGL渲染技術(shù)。圖形的各個(gè)頂點(diǎn)*統(tǒng)一的變換矩陣就可以進(jìn)行平移氯庆、旋轉(zhuǎn)蹭秋、縮放。

// 旋轉(zhuǎn)
void MatrixStack::Rotate(GLfloat angle,GLfloat x,GLfloat y,GLfloat z);// angle參數(shù)傳遞的度數(shù)点晴,?不是弧度
// 平移
void MatrixStack::Translate(GLfloat x,GLfloat y,GLfloat z);
// 縮放
void MatrixStack::Scale(GLfloat x,GLfloat y,GLfloat z);

b感凤、OpenGL math3d庫(kù)

math3d庫(kù)有2個(gè)數(shù)據(jù)類型,能夠表示?個(gè)三維或者四維向量粒督。M3DVector3f可以表示?個(gè)三維向量(x,y,z)陪竿,而M3DVector4f則可以表示一個(gè)四維向量(x,y,z,w)。在典型情況下屠橄,w 坐標(biāo)設(shè)為1.0族跛。x,y,z值通過(guò)除以w來(lái)進(jìn)?行行縮放。除以1.0本質(zhì)上不改變x,y,z值锐墙。

// 聲明?個(gè)三維向量頂點(diǎn)數(shù)組礁哄,例如生成一個(gè)三角形
M3DVector3f vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,0.5f,0.0f
};

c、實(shí)現(xiàn)向量計(jì)算的方法
點(diǎn)乘

返回的是-1溪北,1之間的值桐绒,代表這2個(gè)向量的余弦值

float m3dDotProduct3(const M3DVector3f u,const M3DVector3f v);

返回2個(gè)向量之間的弧度值

float m3dGetAngleBetweenVector3(const M3DVector3f u,const M3DVector3f v);
叉乘

叉乘運(yùn)算結(jié)果返回?個(gè)新的向量,這個(gè)新的向量與原來(lái)的2個(gè)向量垂直

void m3dCrossProduct3(M3DVector3f result,const M3DVector3f u ,const M3DVector3f v);

d之拨、圖形的變化過(guò)程
  • 視圖:指定觀察者位置
  • 模型:在場(chǎng)景中移動(dòng)物體
  • 模型視圖:描述視圖/模型變換的?元性
  • 投影:改變視景體?小和設(shè)置它的投影?式
  • 視口:偽變化茉继,對(duì)窗口上最終輸出進(jìn)行縮放
頂點(diǎn)變換管線

2、仿射變換

a蚀乔、使用到的屬性

在x烁竭、y軸上移動(dòng)的距離

GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;
b、實(shí)現(xiàn)移動(dòng)的方法
void SpecialKeys(int key, int x, int y)
{
}

移動(dòng)的步長(zhǎng)

GLfloat stepSize = 0.025f;

上下左右移動(dòng)

if(key == GLUT_KEY_UP) yPos += stepSize;
if(key == GLUT_KEY_DOWN) yPos -= stepSize;
if(key == GLUT_KEY_LEFT) xPos -= stepSize;
if(key == GLUT_KEY_RIGHT) xPos += stepSize;

檢測(cè)是否碰撞邊界

if(xPos < (-1.0f + blockSize)) xPos = -1.0f + blockSize;
if(xPos > (1.0f - blockSize)) xPos = 1.0f - blockSize;
if(yPos < (-1.0f + blockSize)) yPos = -1.0f + blockSize;
if(yPos > (1.0f - blockSize)) yPos = 1.0f - blockSize;

重新渲染

glutPostRedisplay();

c吉挣、實(shí)現(xiàn)渲染場(chǎng)景的方法
void RenderScene(void)
{
}

平移派撕、旋轉(zhuǎn)、最終矩陣

M3DMatrix44f mFinalTransform, mTranslationMatrix, mRotationMatrix;

根據(jù)xPos,yPos進(jìn)行平移睬魂,每一個(gè)頂點(diǎn)都乘以平移矩陣

m3dTranslationMatrix44(mTranslationMatrix, xPos, yPos, 0.0f);

每次重繪時(shí)终吼,旋轉(zhuǎn)5度

static float yRot = 0.0f;
yRot += 5.0f;
m3dRotationMatrix44(mRotationMatrix, m3dDegToRad(yRot), 0.0f, 0.0f, 1.0f);

將旋轉(zhuǎn)和移動(dòng)的結(jié)果合并到mFinalTransform中(矩陣叉乘)

m3dMatrixMultiply44(mFinalTransform, mTranslationMatrix, mRotationMatrix);

將矩陣結(jié)果提交到固定著色器(平面著色器)中

shaderManager.UseStockShader(GLT_SHADER_FLAT, mFinalTransform, vRed);
squareBatch.Draw();

執(zhí)行緩沖區(qū)交換

glutSwapBuffers();

二、繪制圖形

1氯哮、繪制球體

a际跪、使用到的屬性
// 觀察者位置
GLFrame                cameraFrame;
// 世界坐標(biāo)位置
GLFrame             objectFrame;

// 視景體,用來(lái)構(gòu)造投影矩陣
GLFrustum            viewFrustum;

// 三角形批次類
GLTriangleBatch     CC_Triangle;
// 球
GLTriangleBatch     sphereBatch;
// 環(huán)
GLTriangleBatch     torusBatch;
// 圓柱
GLTriangleBatch     cylinderBatch;
// 錐
GLTriangleBatch     coneBatch;
// 磁盤
GLTriangleBatch     diskBatch;
b、上下左右垫卤,移動(dòng)圖形

移動(dòng)世界坐標(biāo)系威彰,而不是去移動(dòng)物體。比如將世界坐標(biāo)系在X方向移動(dòng)-5.0穴肘。

void SpecialKeys(int key, int x, int y)
{
    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();
}
c歇盼、添加數(shù)據(jù)源
void SetupRC()
{
}

開(kāi)啟深度測(cè)試(立體)

glEnable(GL_DEPTH_TEST);

表示觀察者離屏幕之間的距離,若是負(fù)數(shù)评抚,是往屏幕后面移動(dòng)豹缀;若是正數(shù),往屏幕前面移動(dòng)慨代。將觀察者坐標(biāo)位置Z往屏幕里移動(dòng)15個(gè)單位位置邢笙。

cameraFrame.MoveForward(-15.0f);

或者將物體向屏幕外移動(dòng)15.0

objectFrame.MoveForward(15.0f);
利用三角形批次類構(gòu)造圖形對(duì)象——球
  • sphereBatch:三角形批次類對(duì)象
  • fRadius:球體半徑
  • iSlices:從球體底部堆疊到頂部的三角形帶的數(shù)量,其實(shí)球體是一圈一圈三角形帶組成
  • iStacks:圍繞球體一圈排列的三角形對(duì)數(shù)
  • 一個(gè)對(duì)稱性較好的球體的片段數(shù)量是堆疊數(shù)量的2倍侍匙,就是iStacks = 2 * iSlices
  • 繪制球體都是圍繞Z軸氮惯,這樣+z就是球體的頂點(diǎn),-z就是球體的底部
gltMakeSphere(sphereBatch, 3.0, 10, 20);

d想暗、渲染場(chǎng)景

用當(dāng)前清除顏色清除窗口背景

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

模型視圖矩陣棧堆妇汗,壓棧∷的或者對(duì)objectFrame進(jìn)行壓棧杨箭,刪掉3.和4. 直接進(jìn)入switch(nStep)的判斷步驟

modelViewMatrix.PushMatrix();
modelViewMatrix.PushMatrix(objectFrame);

獲取攝像頭矩陣,從camereaFrame中獲取矩陣到mCamera

M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);

模型視圖堆棧的矩陣與mCamera矩陣相乘之后储狭,存儲(chǔ)到modelViewMatrix矩陣堆棧中

modelViewMatrix.MultMatrix(mCamera);

創(chuàng)建矩陣mObjectFrame互婿,從ObjectFrame獲取矩陣到mOjectFrame

M3DMatrix44f mObjectFrame;
objectFrame.GetMatrix(mObjectFrame);

modelViewMatrix的堆棧中的矩陣與mOjbectFrame矩陣相乘,存儲(chǔ)到modelViewMatrix矩陣堆棧中

modelViewMatrix.MultMatrix(mObjectFrame);

判斷目前是繪制第幾個(gè)圖形

switch(nStep)
{
    case 0:
        DrawWireFramedBatch(&sphereBatch);
        break;
    case 1:
        DrawWireFramedBatch(&torusBatch);
        break;
    case 2:
        DrawWireFramedBatch(&cylinderBatch);
        break;
    case 3:
        DrawWireFramedBatch(&coneBatch);
        break;
    case 4:
        DrawWireFramedBatch(&diskBatch);
        break;
}

出棧

modelViewMatrix.PopMatrix();

交換緩存

glutSwapBuffers();

e辽狈、繪制圖形和邊框
? 繪制圖形

平面著色器慈参,繪制三角形

shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);

傳過(guò)來(lái)的參數(shù)對(duì)應(yīng)不同的圖形Batch

pBatch->Draw();
? 開(kāi)啟多邊形偏移
glEnable(GL_POLYGON_OFFSET_LINE);

將多邊形背面設(shè)為線框模式

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

開(kāi)啟多邊形偏移(設(shè)置偏移數(shù)量)

glPolygonOffset(-1.0f, -1.0f);

線條寬度

glLineWidth(2.5f);
? 開(kāi)啟混合功能(顏色混合&抗鋸齒功能)
glEnable(GL_BLEND);

開(kāi)啟處理線段抗鋸齒功能使線條更加柔和

glEnable(GL_LINE_SMOOTH);

設(shè)置顏色混合因子

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
? 平面著色器繪制線條
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
pBatch->Draw();
? 恢復(fù)多邊形模式和深度測(cè)試
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);

2、繪制其他圖形

環(huán)面
  • torusBatch:三角形批次類對(duì)象
  • majorRadius:甜甜圈中心到外邊緣的半徑
  • minorRadius:甜甜圈中心到內(nèi)邊緣的半徑
  • numMajor:沿著主半徑的三角形數(shù)量
  • numMinor:沿著內(nèi)部較小半徑的三角形數(shù)量
gltMakeTorus(torusBatch, 3.0f, 0.75f, 15, 15);

圓柱
  • cylinderBatch:三角形批次類對(duì)象
  • baseRadius:底部半徑
  • topRadius:頭部半徑
  • fLength:圓形長(zhǎng)度
  • numSlices:圍繞Z軸的三角形對(duì)的數(shù)量
  • numStacks:圓柱底部堆疊到頂部圓環(huán)的三角形數(shù)量
gltMakeCylinder(cylinderBatch, 2.0f, 2.0f, 3.0f, 15, 2);

圓錐體
  • cylinderBatch:三角形批次類對(duì)象
  • baseRadius:底部半徑
  • topRadius:頭部半徑
  • fLength:圓形長(zhǎng)度
  • numSlices:圍繞Z軸的三角形對(duì)的數(shù)量
  • numStacks:圓柱底部堆疊到頂部圓環(huán)的三角形數(shù)量
  • 圓柱體稻艰,從0開(kāi)始向Z軸正方向延伸懂牧。圓錐體侈净,是一端的半徑為0尊勿,另一端半徑可指定
gltMakeCylinder(coneBatch, 2.0f, 0.0f, 3.0f, 13, 2);

磁盤
  • diskBatch:三角形批次類對(duì)象
  • innerRadius:內(nèi)圓半徑
  • outerRadius:外圓半徑
  • nSlices:圓盤圍繞Z軸的三角形對(duì)的數(shù)量
  • nStacks:圓盤外網(wǎng)到內(nèi)圍的三角形數(shù)量
gltMakeDisk(diskBatch, 1.5f, 3.0f, 13, 3);

3、繪制自動(dòng)旋轉(zhuǎn)的球體

void RenderScene(void)
{
}
? 建立基于時(shí)間變化的動(dòng)畫
static CStopWatch rotTimer;

當(dāng)前時(shí)間 * 60s

float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
? 矩陣變量
  • mTranslate:平移
  • mRotate:旋轉(zhuǎn)
  • mModelview:模型視圖
  • mModelViewProjection:模型視圖投影MVP
M3DMatrix44f mTranslate, mRotate, mModelview, mModelViewProjection;
? 仿射變換

創(chuàng)建一個(gè)4*4矩陣變量畜侦,將球體沿著Z軸負(fù)方向移動(dòng)2.5個(gè)單位長(zhǎng)度

m3dTranslationMatrix44(mTranslate, 0.0f, 0.0f, -2.5f);

創(chuàng)建一個(gè)4*4矩陣變量元扔,將球體在Y軸上旋轉(zhuǎn)yRot度,yRot根據(jù)經(jīng)過(guò)時(shí)間設(shè)置動(dòng)畫幀率

m3dRotationMatrix44(mRotate, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);

mModerView通過(guò)矩陣旋轉(zhuǎn)矩陣旋膳、移動(dòng)矩陣相乘澎语,將結(jié)果添加到mModerView

m3dMatrixMultiply44(mModelview, mTranslate, mRotate);

將投影矩陣乘以模型視圖矩陣,將變化結(jié)果通過(guò)矩陣乘法應(yīng)用到mModelViewProjection矩陣上

m3dMatrixMultiply44(mModelViewProjection, viewFrustum.GetProjectionMatrix(),mModelview);
? 著色器繪圖

繪圖顏色

GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };

通過(guò)平面著色器提交矩陣和顏色

shaderManager.UseStockShader(GLT_SHADER_FLAT, mModelViewProjection, vBlack);

開(kāi)始繪圖

torusBatch.Draw();

交換緩沖區(qū),并立即刷新

glutSwapBuffers();
glutPostRedisplay();

4擅羞、繪制圍繞太陽(yáng)旋轉(zhuǎn)的地球

a尸变、使用到的屬性
GLShaderManager        shaderManager;            // 著色器管理器
GLMatrixStack        modelViewMatrix;        // 模型視圖矩陣
GLMatrixStack        projectionMatrix;        // 投影矩陣
GLFrustum            viewFrustum;            // 視景體
GLGeometryTransform    transformPipeline;        // 幾何圖形變換管道
GLTriangleBatch        torusBatch;             // 大球
GLTriangleBatch     sphereBatch;            // 小球(隨機(jī)球,包括靜止和自轉(zhuǎn)兩種類型)
GLBatch                floorBatch;          // 地板
// 角色幀 照相機(jī)角色幀
GLFrame             cameraFrame;
// 添加附加隨機(jī)球
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];

b减俏、添加數(shù)據(jù)源
void SetupRC()
{
}

清空顏色緩沖區(qū)中的殘留顏色值召烂,再進(jìn)行初始化

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
shaderManager.InitializeStockShaders();

開(kāi)啟深度測(cè)試

glEnable(GL_DEPTH_TEST);

設(shè)置地板頂點(diǎn)數(shù)據(jù)

floorBatch.Begin(GL_LINES, 324);// 共324個(gè)
for(GLfloat x = -20.0; x <= 20.0f; x+= 0.5)
{
    // 地板是平面,只會(huì)在X娃承、Y上發(fā)生變化
    floorBatch.Vertex3f(x, -0.55f, 20.0f);
    floorBatch.Vertex3f(x, -0.55f, -20.0f);
    
    floorBatch.Vertex3f(20.0f, -0.55f, x);
    floorBatch.Vertex3f(-20.0f, -0.55f, x);
}
floorBatch.End();

設(shè)置大球模型

gltMakeSphere(torusBatch, 0.4f, 40, 80);

設(shè)置小球球模型

gltMakeSphere(sphereBatch, 0.1f, 26, 13);

隨機(jī)位置放置小球

for (int i = 0; i < NUM_SPHERES; I++)
{
    // 小球在同一個(gè)平面奏夫,說(shuō)明Y軸不變,X历筝,Z使用隨機(jī)值
    GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
    GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
    
    // 在y軸方向酗昼,將球體設(shè)置為0.0的位置,這使得它們看起來(lái)是飄浮在眼睛的高度
    // 對(duì)spheres數(shù)組中的每一個(gè)頂點(diǎn)梳猪,設(shè)置頂點(diǎn)數(shù)據(jù)
    spheres[i].SetOrigin(x, 0.0f, z);
}

c麻削、渲染場(chǎng)景
void RenderScene(void)
{
}

顏色值(地板、大球春弥、小球顏色)

static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f};
static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
static GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f};

清除顏色緩存區(qū)和深度緩沖區(qū)

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

時(shí)間動(dòng)畫

static CStopWatch    rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

為了讓藍(lán)色的小球的公轉(zhuǎn)在任何角度都能看到需要加入觀察者碟婆。觀察者放在地板之前,讓地板也支持?jǐn)z影機(jī)的移動(dòng)

M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.PushMatrix(mCamera);

使用平面著色器繪制地板

shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);
floorBatch.Draw();

獲取光源位置(固定管線里面都是4維矩陣的計(jì)算)

M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};
畫中央的紅色大球
  • 移動(dòng)觀察者camera進(jìn)行平移
  • 使用objectFrame移動(dòng)物體自身惕稻,最終還是調(diào)用了modelViewMatrix
  • 使用modelViewMatrix移動(dòng)物體自身
// 使得大球位置平移(3.0)向屏幕里面
modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
// 壓棧(復(fù)制棧頂)竖共,只有當(dāng)圖形發(fā)生了仿射變換的時(shí)候才需要使用到堆棧
modelViewMatrix.PushMatrix();
// 大球自轉(zhuǎn)(圍繞Y軸旋轉(zhuǎn))
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
// 指定合適的著色器(點(diǎn)光源著色器)
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);
torusBatch.Draw();
// 繪制完畢則Pop
modelViewMatrix.PopMatrix();

畫靜態(tài)的小球

for (int i = 0; i < NUM_SPHERES; I++)
{
    modelViewMatrix.PushMatrix();
    modelViewMatrix.MultMatrix(spheres[I]);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor);
    sphereBatch.Draw();
    modelViewMatrix.PopMatrix();
}

讓一個(gè)小籃球圍繞大球公眾自轉(zhuǎn)

// 圍繞Y軸繞負(fù)方向2倍速度旋轉(zhuǎn)
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
// 因?yàn)榛@球和紅球位置都在中央,為區(qū)分俺祠,將籃球沿著X軸正方向移動(dòng)0.8
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vSphereColor);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();

執(zhí)行緩存區(qū)交換

glutSwapBuffers();

為了讓球旋轉(zhuǎn)起來(lái)公给,需要進(jìn)行不斷渲染

glutPostRedisplay();

d、屏幕更改大小或已初始化
void ChangeSize(int nWidth, int nHeight)
{
}

設(shè)置視口

glViewport(0, 0, nWidth, nHeight);

創(chuàng)建投影矩陣

viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);

獲取viewFrustum投影矩陣蜘渣,并將其加載到投影矩陣堆棧上

projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

設(shè)置變換管道以使用兩個(gè)矩陣堆棧(變換矩陣modelViewMatrix 淌铐,投影矩陣projectionMatrix)。

transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

e蔫缸、鍵盤操作上下平移和左右旋轉(zhuǎn)

void SpeacialKeys(int key,int x,int y)
{
    // 移動(dòng)步長(zhǎng)
    float linear = 0.1f;
    // 旋轉(zhuǎn)度數(shù)
    float angular = float(m3dDegToRad(5.0f));
    ......
}

上下平移

if (key == GLUT_KEY_UP)
{
    cameraFrame.MoveForward(linear);
}

if (key == GLUT_KEY_DOWN)
{
    cameraFrame.MoveForward(-linear);
}

左右旋轉(zhuǎn)

if (key == GLUT_KEY_LEFT)
{
    cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
}

if (key == GLUT_KEY_RIGHT)
{
    cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
}

三腿准、OpenGL紋理

1、繪制金字塔

// 紋理變量拾碌,一般使用無(wú)符號(hào)整型
GLuint              textureID;
a吐葱、添加數(shù)據(jù)源
void SetupRC()
{
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
    shaderManager.InitializeStockShaders();
    glEnable(GL_DEPTH_TEST);
    .....
}
分配紋理對(duì)象
  • 參數(shù)1:紋理對(duì)象個(gè)數(shù)
  • 參數(shù)2:紋理對(duì)象指針
glGenTextures(1, &textureID);
綁定紋理狀態(tài)
  • 參數(shù)1:紋理狀態(tài)2D
  • 參數(shù)2:紋理對(duì)象
glBindTexture(GL_TEXTURE_2D, textureID);
將TGA文件加載為2D紋理
  • 參數(shù)1:紋理文件名稱
  • 參數(shù)2&參數(shù)3:需要縮小&放大的過(guò)濾器
  • 參數(shù)4:紋理坐標(biāo)環(huán)繞模式
LoadTGATexture("stone.tga", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, GL_CLAMP_TO_EDGE);
創(chuàng)造金字塔pyramidBatch

設(shè)置金字塔頂點(diǎn)坐標(biāo)數(shù)據(jù)/紋理坐標(biāo)數(shù)據(jù)

MakePyramid(pyramidBatch);
修改觀察者,將相機(jī)平移
cameraFrame.MoveForward(-10);

b校翔、將TGA文件加載為2D紋理
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
    // 指向圖像數(shù)據(jù)的指針
    GLbyte *pBits;
    // 圖片的寬弟跑、高、顏色
    int nWidth, nHeight, nComponents;
    // 顏色存儲(chǔ)方式
    GLenum eFormat;
    .....
}
讀取紋理位置防症,讀取像素
  • 參數(shù)1:紋理文件名稱
  • 參數(shù)2:文件寬度地址
  • 參數(shù)3:文件高度地址
  • 參數(shù)4:文件組件地址
  • 參數(shù)5:文件格式地址
  • 返回值:指向圖像數(shù)據(jù)的指針
pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
if(pBits == NULL) return false;// 未能成功讀取到數(shù)據(jù)
設(shè)置紋理參數(shù)
  • 參數(shù)1:紋理維度
  • 參數(shù)2:為S/T坐標(biāo)設(shè)置模式(線性過(guò)濾)
  • 參數(shù)3:環(huán)繞模式(過(guò)濾方式)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
載入紋理
  • 參數(shù)1:紋理維度
  • 參數(shù)2:貼圖層次
  • 參數(shù)3:紋理單元存儲(chǔ)的顏色成分(從讀取像素圖是獲得)
  • 參數(shù)4:加載紋理寬
  • 參數(shù)5:加載紋理高
  • 參數(shù)6:加載紋理的深度
  • 參數(shù)7:像素?cái)?shù)據(jù)的數(shù)據(jù)類型(GL_UNSIGNED_BYTE孟辑,每個(gè)顏色分量都是一個(gè)8位無(wú)符號(hào)整數(shù))
  • 參數(shù)8:指向紋理圖像數(shù)據(jù)的指針
glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits);
// 使用完畢釋放pBits
free(pBits);
紋理生成所有的Mip層
glGenerateMipmap(GL_TEXTURE_2D);

c哎甲、繪制金字塔
void MakePyramid(GLBatch& pyramidBatch)
{
}
? 通過(guò)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);
? 創(chuàng)建頂點(diǎn)數(shù)據(jù)
M3DVector3f vApex = { 0.0f, 1.0f, 0.0f };// 塔頂
M3DVector3f vFrontLeft = { -1.0f, -1.0f, 1.0f };// 前左
M3DVector3f vFrontRight = { 1.0f, -1.0f, 1.0f };// 前右
M3DVector3f vBackLeft = { -1.0f,  -1.0f, -1.0f };// 后左
M3DVector3f vBackRight = { 1.0f,  -1.0f, -1.0f };// 后右
M3DVector3f n;// 法線變量
? 繪制金字塔底部四邊形中的三角形X(vBackLeft,vBackRight,vFrontRight)
  • 找到三角形X的法線
// 參數(shù)1:結(jié)果
// 參數(shù)2-4:3個(gè)頂點(diǎn)數(shù)據(jù)
m3dFindNormal(n, vBackLeft, vBackRight, vFrontRight);
  • vBackLeft
// 添加一個(gè)表面法線炭玫。表面法線是有方向的向量,法線坐標(biāo)與Vertex頂點(diǎn)坐標(biāo)中的Y軸一致貌虾。
pyramidBatch.Normal3fv(n);// 設(shè)置法線

// texture:紋理層次础嫡,使用存儲(chǔ)著色器來(lái)進(jìn)行渲染,設(shè)置為0
// s:對(duì)應(yīng)頂點(diǎn)坐標(biāo)中的x坐標(biāo)
// t:對(duì)應(yīng)頂點(diǎn)坐標(biāo)中的y
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);// 設(shè)置紋理坐標(biāo)

pyramidBatch.Vertex3fv(vBackLeft);// 向三角形批次類添加頂點(diǎn)數(shù)據(jù)
  • 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);
? 按照繪制三角形X的步驟繪制金字塔各面的三角形
? 結(jié)束批次設(shè)置
pyramidBatch.End();

d酝惧、繪制場(chǎng)景

顏色值&光源位置

static GLfloat vLightPos [] = { 1.0f, 1.0f, 0.0f };
static GLfloat vWhite [] = { 1.0f, 1.0f, 1.0f, 1.0f };

清理緩存區(qū)

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

當(dāng)前模型視頻壓棧

modelViewMatrix.PushMatrix();

// 添加照相機(jī)矩陣
M3DMatrix44f mCamera;
// 從camraFrame中獲取一個(gè)4*4的矩陣
cameraFrame.GetCameraMatrix(mCamera);
// 矩陣乘以矩陣堆棧頂部矩陣榴鼎,相乘結(jié)果存儲(chǔ)到堆棧的頂部將照相機(jī)矩陣與當(dāng)前模型矩陣相乘壓入棧頂
modelViewMatrix.MultMatrix(mCamera);

// 創(chuàng)建mObjectFrame矩陣
M3DMatrix44f mObjectFrame;
// 從objectFrame中獲取矩陣,objectFrame保存的是特殊鍵位的變換矩陣
objectFrame.GetMatrix(mObjectFrame);
// 矩陣乘以矩陣堆棧頂部矩陣晚唇,相乘結(jié)果存儲(chǔ)到堆棧的頂部將照相機(jī)矩陣與當(dāng)前模型矩陣相乘壓入棧頂
modelViewMatrix.MultMatrix(mObjectFrame);

綁定紋理巫财。因?yàn)槲覀兊捻?xiàng)目中只有一個(gè)紋理,可以省略這步哩陕,但如果有多個(gè)紋理平项,綁定紋理很重要

glBindTexture(GL_TEXTURE_2D, textureID);
點(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.Draw();

模型視圖出棧悍及,恢復(fù)矩陣(push一次就要pop一次)

modelViewMatrix.PopMatrix();

交換緩存區(qū)

glutSwapBuffers();

e闽瓢、進(jìn)行清理,例如刪除紋理對(duì)象
void ShutdownRC(void)
{
    glDeleteTextures(1, &textureID);
}

2心赶、繪制隧道

a扣讼、使用到的屬性

4個(gè)批次容器類

GLBatch             floorBatch;//地面
GLBatch             ceilingBatch;//天花板
GLBatch             leftWallBatch;//左墻面
GLBatch             rightWallBatch;//右墻面

深度初始值為-65

GLfloat             viewZ = -65.0f;

紋理標(biāo)識(shí)符號(hào)

#define TEXTURE_BRICK   0 //墻面
#define TEXTURE_FLOOR   1 //地板
#define TEXTURE_CEILING 2 //紋理天花板
#define TEXTURE_COUNT   3 //紋理個(gè)數(shù)

紋理標(biāo)記數(shù)組

GLuint  textures[TEXTURE_COUNT];

文件tag名字?jǐn)?shù)組

const char *szTextureFiles[TEXTURE_COUNT] = { "brick.tga", "floor.tga", "ceiling.tga" };

b、輔助函數(shù)中的修改
在main函數(shù)中添加菜單入口缨叫,改變過(guò)濾器
glutCreateMenu(ProcessMenu);
glutAddMenuEntry("GL_NEAREST",0);
glutAddMenuEntry("GL_LINEAR",1);
glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST",2);
glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 3);
glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);
glutAddMenuEntry("Anisotropic Filter", 6);
glutAddMenuEntry("Anisotropic Off", 7);
glutAttachMenu(GLUT_RIGHT_BUTTON);
在ChangeSize函數(shù)中生成透視投影
GLfloat fAspect = (GLfloat)w/(GLfloat)h;
viewFrustum.SetPerspective(80.0f,fAspect,1.0,120.0);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
前后移動(dòng)視口來(lái)對(duì)方向鍵作出響應(yīng)的函數(shù)中改變的是深度值Z
if(key == GLUT_KEY_UP) viewZ += 0.5f;
if(key == GLUT_KEY_DOWN) viewZ -= 0.5f;
關(guān)閉渲染環(huán)境函數(shù)中刪除紋理
glDeleteTextures(TEXTURE_COUNT, textures);

c椭符、菜單欄選擇
綁定紋理
void ProcessMenu(int value)
{
    GLint iLoop;
    
    for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
    {
        // 綁定紋理
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        .......
        }
    }
    
    // 觸發(fā)重畫
    glutPostRedisplay();
}
配置紋理參數(shù)
// 0-縮小過(guò)濾器、最鄰近過(guò)濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

// 1-縮小過(guò)濾器耻姥、線性過(guò)濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// 2-縮小過(guò)濾器销钝、選擇最鄰近的Mip層,并執(zhí)行最鄰近過(guò)濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);

// 3-縮小過(guò)濾器琐簇、在Mip層之間執(zhí)行線性插補(bǔ)蒸健,并執(zhí)行最鄰近過(guò)濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);

// 4-縮小過(guò)濾器、選擇最鄰近Mip層婉商,并執(zhí)行線性過(guò)濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);

// 5-縮小過(guò)濾器似忧、在Mip層之間執(zhí)行線性插補(bǔ),并執(zhí)行線性過(guò)濾据某,又稱為三線性過(guò)濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

// 6
// 設(shè)置各向異性過(guò)濾
GLfloat fLargest;
// 獲取各向異性過(guò)濾的最大數(shù)量
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
// 設(shè)置紋理參數(shù)(各向異性采樣)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);

// 7-設(shè)置各向同性過(guò)濾橡娄,數(shù)量為1.0表示(各向同性采樣)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);

d诗箍、設(shè)置數(shù)據(jù)源
void SetupRC()
{
    glClearColor(0.0f, 0.0f, 0.0f,1.0f);// 黑色的背景
    shaderManager.InitializeStockShaders();
    
    GLbyte *pBytes;
    GLint iWidth, iHeight, iComponents;
    GLenum eFormat;
    GLint iLoop;

    // 分配紋理對(duì)象
    glGenTextures(TEXTURE_COUNT, textures);
    
    // 循環(huán)設(shè)置紋理數(shù)組的紋理參數(shù)
    for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++)
    {
        ......
    }
}

綁定紋理對(duì)象

glBindTexture(GL_TEXTURE_2D, textures[iLoop]);

加載tga文件

pBytes = gltReadTGABits(szTextureFiles[iLoop],&iWidth, &iHeight, &iComponents, &eFormat);

加載紋理癣籽、設(shè)置過(guò)濾器和包裝模式

// 放大過(guò)濾器挽唉、最鄰近過(guò)濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// 縮小過(guò)濾器、最鄰近過(guò)濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// s軸環(huán)繞筷狼、環(huán)繞模式強(qiáng)制對(duì)范圍之外的紋理坐標(biāo)沿著合法的紋理單元的最后一行或一列進(jìn)行采樣
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
// t軸環(huán)繞瓶籽、環(huán)繞模式強(qiáng)制對(duì)范圍之外的紋理坐標(biāo)沿著合法的紋理單元的最后一行或一列進(jìn)行采樣
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

載入紋理 glTexImage2D

glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);

為紋理對(duì)象生成一組完整的mipmap

glGenerateMipmap(GL_TEXTURE_2D);

釋放原始紋理數(shù)據(jù),不在需要紋理原始數(shù)據(jù)了

free(pBytes);

設(shè)置圖形上下左右各面的頂點(diǎn)/紋理坐標(biāo)

GLfloat z;// 隧道的深度
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);

// 地板墻面
for(z = 60.0f; z >= 0.0f; z -=10.0f)
{
    floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    floorBatch.Vertex3f(-10.0f, -10.0f, z);
    
    floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    floorBatch.Vertex3f(10.0f, -10.0f, z);
    
    floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
    floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
    
    floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    floorBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
}
floorBatch.End();

// 天花板墻面
......

// 左面墻面
.....

// 右面墻面
.....

e埂材、渲染場(chǎng)景
void RenderScene(void)
{
    // 用當(dāng)前清除色塑顺,清除窗口
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 模型視圖壓棧
    modelViewMatrix.PushMatrix();

    ......

    // 模型視圖出棧
    modelViewMatrix.PopMatrix();
    
    // 緩存區(qū)交換
    glutSwapBuffers();
}

在Z軸上平移viewZ距離

modelViewMatrix.Translate(0.0f, 0.0f, viewZ);
紋理替換矩陣著色器
  • 參數(shù)1:GLT_SHADER_TEXTURE_REPLACE(著色器標(biāo)簽)
  • 參數(shù)2:模型視圖投影矩陣
  • 參數(shù)3:紋理層
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);

綁定紋理

glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_FLOOR]);
floorBatch.Draw();

glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]);
ceilingBatch.Draw();

glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
leftWallBatch.Draw();

rightWallBatch.Draw();

3、繪制自動(dòng)旋轉(zhuǎn)的球體世界

a俏险、使用到的屬性

添加附加隨機(jī)球

#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];

批處理容器

GLTriangleBatch        torusBatch;             // 花托批處理
GLBatch                floorBatch;             // 地板批處理
GLTriangleBatch     sphereBatch;            //公轉(zhuǎn)球的批處理

照相機(jī)角色幀

GLFrame             cameraFrame;

紋理標(biāo)記數(shù)組

GLuint uiTextures[3];

b严拒、設(shè)置數(shù)據(jù)源
void SetupRC()
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    shaderManager.InitializeStockShaders();
    .....
}

開(kāi)啟深度測(cè)試/背面剔除

glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);

設(shè)置大球、小球(公轉(zhuǎn)自轉(zhuǎn))

gltMakeSphere(torusBatch, 0.4f, 40, 80);
gltMakeSphere(sphereBatch, 0.1f, 26, 13);

設(shè)置地板頂點(diǎn)數(shù)據(jù)&地板紋理

GLfloat texSize = 10.0f;
floorBatch.Begin(GL_TRIANGLE_FAN, 4,1);

floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
floorBatch.Vertex3f(-20.f, -0.41f, 20.0f);

floorBatch.MultiTexCoord2f(0, texSize, 0.0f);
floorBatch.Vertex3f(20.0f, -0.41f, 20.f);

floorBatch.MultiTexCoord2f(0, texSize, texSize);
floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);

floorBatch.MultiTexCoord2f(0, 0.0f, texSize);
floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);

floorBatch.End();

隨機(jī)小球頂點(diǎn)坐標(biāo)數(shù)據(jù)

for (int i = 0; i < NUM_SPHERES; I++)
{
    GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
    GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
    spheres[i].SetOrigin(x, 0.0f, z);
}

命名紋理對(duì)象

glGenTextures(3, uiTextures);

將TGA文件加載為2D紋理

glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);

glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR,
               GL_LINEAR, GL_CLAMP_TO_EDGE);

glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR,
               GL_LINEAR, GL_CLAMP_TO_EDGE);

c竖独、繪制地板和球
void drawSomething(GLfloat yRot)
{
}
定義光源位置&漫反射顏色
static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static GLfloat vLightPos[] = { 0.0f, 3.0f, 0.0f, 1.0f };
繪制懸浮小球
glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
for(int i = 0; i < NUM_SPHERES; I++)
{
    modelViewMatrix.PushMatrix();
    modelViewMatrix.MultMatrix(spheres[I]);
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 modelViewMatrix.GetMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPos,
                                 vWhite,
                                 0);
    sphereBatch.Draw();
    modelViewMatrix.PopMatrix();
}

// 繪制大球
........

// 繪制公轉(zhuǎn)自轉(zhuǎn)小球
.......

d裤唠、渲染場(chǎng)景
void RenderScene(void)
{
    ......
}
添加反光效果
// 壓棧(鏡面)
modelViewMatrix.PushMatrix();

// 翻轉(zhuǎn)Y軸
modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);
// 鏡面世界圍繞Y軸平移一定間距
modelViewMatrix.Translate(0.0f, 0.8f, 0.0f);

// 指定順時(shí)針為正面
glFrontFace(GL_CW);
// 繪制地面以外其他部分(鏡面)
drawSomething(yRot);
// 恢復(fù)為逆時(shí)針為正面
glFrontFace(GL_CCW);

// 繪制鏡面,恢復(fù)矩陣
modelViewMatrix.PopMatrix();
開(kāi)啟混合功能(繪制地板)
glEnable(GL_BLEND);
// 指定glBlendFunc 顏色混合方程式
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// 綁定地面紋理
glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
// 紋理調(diào)整著色器(將一個(gè)基本色乘以一個(gè)取自紋理的單元nTextureUnit的紋理)
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
                             transformPipeline.GetModelViewProjectionMatrix(),
                             vFloorColor,
                             0);
// 開(kāi)始繪制
floorBatch.Draw();
// 取消混合
glDisable(GL_BLEND);

Demo

Demo在我的Github上莹痢,歡迎下載种蘸。
Multi-MediaDemo

參考文獻(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者竞膳。
  • 序言:七十年代末航瞭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子坦辟,更是在濱河造成了極大的恐慌刊侯,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锉走,死亡現(xiàn)場(chǎng)離奇詭異滔吠,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)挠日,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門疮绷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人嚣潜,你說(shuō)我怎么就攤上這事冬骚。” “怎么了懂算?”我有些...
    開(kāi)封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵只冻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我计技,道長(zhǎng),這世上最難降的妖魔是什么垮媒? 我笑而不...
    開(kāi)封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任舍悯,我火速辦了婚禮航棱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘萌衬。我一直安慰自己饮醇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布秕豫。 她就那樣靜靜地躺著朴艰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪混移。 梳的紋絲不亂的頭發(fā)上祠墅,一...
    開(kāi)封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音歌径,去河邊找鬼饵隙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛沮脖,可吹牛的內(nèi)容都是我干的金矛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼勺届,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼驶俊!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起免姿,我...
    開(kāi)封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤饼酿,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后胚膊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體故俐,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年紊婉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了药版。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喻犁,死狀恐怖槽片,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肢础,我是刑警寧澤还栓,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站传轰,受9級(jí)特大地震影響剩盒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜慨蛙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一辽聊、第九天 我趴在偏房一處隱蔽的房頂上張望纪挎。 院中可真熱鬧,春花似錦身隐、人聲如沸廷区。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至埠帕,卻和暖如春垢揩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背敛瓷。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工叁巨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呐籽。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓锋勺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親狡蝶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子庶橱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 原創(chuàng):知識(shí)探索型文章創(chuàng)作不易,請(qǐng)珍惜贪惹,之后會(huì)持續(xù)更新苏章,不斷完善個(gè)人比較喜歡做筆記和寫總結(jié),畢竟好記性不如爛筆頭哈哈...
    時(shí)光啊混蛋_97boy閱讀 3,815評(píng)論 0 8
  • 原創(chuàng):知識(shí)探索型文章創(chuàng)作不易奏瞬,請(qǐng)珍惜枫绅,之后會(huì)持續(xù)更新,不斷完善個(gè)人比較喜歡做筆記和寫總結(jié)硼端,畢竟好記性不如爛筆頭哈哈...
    時(shí)光啊混蛋_97boy閱讀 1,004評(píng)論 0 4
  • 原創(chuàng):知識(shí)探索型文章創(chuàng)作不易并淋,請(qǐng)珍惜,之后會(huì)持續(xù)更新珍昨,不斷完善個(gè)人比較喜歡做筆記和寫總結(jié)预伺,畢竟好記性不如爛筆頭哈哈...
    時(shí)光啊混蛋_97boy閱讀 1,038評(píng)論 0 3
  • 本文首發(fā)于個(gè)人博客:Lam's Blog - 【OpenGL ES】入門及繪制一個(gè)三角形,文章由MarkDown語(yǔ)...
    格子林ll閱讀 7,274評(píng)論 2 18
  • 原創(chuàng):知識(shí)探索型文章創(chuàng)作不易曼尊,請(qǐng)珍惜酬诀,之后會(huì)持續(xù)更新,不斷完善個(gè)人比較喜歡做筆記和寫總結(jié)骆撇,畢竟好記性不如爛筆頭哈哈...
    時(shí)光啊混蛋_97boy閱讀 1,393評(píng)論 0 8