iOS圖像:OpenGL(下)

原創(chuàng):知識(shí)探索型文章
創(chuàng)作不易,請(qǐng)珍惜,之后會(huì)持續(xù)更新,不斷完善
個(gè)人比較喜歡做筆記和寫(xiě)總結(jié),畢竟好記性不如爛筆頭哈哈,這些文章記錄了我的IOS成長(zhǎng)歷程,希望能與大家一起進(jìn)步
溫馨提示:由于簡(jiǎn)書(shū)不支持目錄跳轉(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é)類(lèi)型。雖然我們不必親自進(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ù)類(lèi)型,能夠表示?個(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)變換管線(xià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;

// 三角形批次類(lèi)
GLTriangleBatch     CC_Triangle;
// 球
GLTriangleBatch     sphereBatch;
// 環(huán)
GLTriangleBatch     torusBatch;
// 圓柱
GLTriangleBatch     cylinderBatch;
// 錐
GLTriangleBatch     coneBatch;
// 磁盤(pán)
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);
利用三角形批次類(lèi)構(gòu)造圖形對(duì)象——球
  • sphereBatch:三角形批次類(lèi)對(duì)象
  • fRadius:球體半徑
  • iSlices:從球體底部堆疊到頂部的三角形帶的數(shù)量,其實(shí)球體是一圈一圈三角形帶組成
  • iStacks:圍繞球體一圈排列的三角形對(duì)數(shù)
  • 一個(gè)對(duì)稱(chēng)性較好的球體的片段數(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è)為線(xiàn)框模式

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

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

glPolygonOffset(-1.0f, -1.0f);

線(xiàn)條寬度

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

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

glEnable(GL_LINE_SMOOTH);

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

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
? 平面著色器繪制線(xiàn)條
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:三角形批次類(lèi)對(duì)象
  • majorRadius:甜甜圈中心到外邊緣的半徑
  • minorRadius:甜甜圈中心到內(nèi)邊緣的半徑
  • numMajor:沿著主半徑的三角形數(shù)量
  • numMinor:沿著內(nèi)部較小半徑的三角形數(shù)量
gltMakeTorus(torusBatch, 3.0f, 0.75f, 15, 15);

圓柱
  • cylinderBatch:三角形批次類(lèi)對(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:三角形批次類(lèi)對(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);

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

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

void RenderScene(void)
{
}
? 建立基于時(shí)間變化的動(dòng)畫(huà)
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)畫(huà)幀率

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)兩種類(lèi)型)
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)畫(huà)

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();

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

M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};
畫(huà)中央的紅色大球
  • 移動(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();

畫(huà)靜態(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、鍵盤(pán)操作上下平移和左右旋轉(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:紋理文件名稱(chēng)
  • 參數(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:紋理文件名稱(chēng)
  • 參數(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è)置模式(線(xiàn)性過(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ù)類(lèi)型(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è)紋理,如果不寫(xiě)這個(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;// 法線(xiàn)變量
? 繪制金字塔底部四邊形中的三角形X(vBackLeft,vBackRight,vFrontRight)
  • 找到三角形X的法線(xiàn)
// 參數(shù)1:結(jié)果
// 參數(shù)2-4:3個(gè)頂點(diǎn)數(shù)據(jù)
m3dFindNormal(n, vBackLeft, vBackRight, vFrontRight);
  • vBackLeft
// 添加一個(gè)表面法線(xiàn)。表面法線(xiàn)是有方向的向量,法線(xiàn)坐標(biāo)與Vertex頂點(diǎn)坐標(biāo)中的Y軸一致。
pyramidBatch.Normal3fv(n);// 設(shè)置法線(xiàn)

// 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);// 向三角形批次類(lèi)添加頂點(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è)批次容器類(lèi)

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ā)重畫(huà)
    glutPostRedisplay();
}
配置紋理參數(shù)
// 0-縮小過(guò)濾器、最鄰近過(guò)濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

// 1-縮小過(guò)濾器、線(xiàn)性過(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í)行線(xiàn)性插補(bǔ),并執(zhí)行最鄰近過(guò)濾
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);

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

// 5-縮小過(guò)濾器、在Mip層之間執(zhí)行線(xiàn)性插補(bǔ),并執(zhí)行線(xiàn)性過(guò)濾,又稱(chēng)為三線(xiàn)性過(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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容