一典尾、 畫一個金字塔
!!!這一部分主要是畫金字塔的代碼解析部分,對此已經(jīng)熟練掌握的朋友可以直接跳過睹耐。
首先附上簡單整理的一張包含setupRC、changeSize部翘、RenderScene一般情況下分別處理的代碼邏輯的簡圖硝训,這里有必要說明的是,圖里的邏輯只是一般情況下可以這么做,但并非一成不變窖梁。
1赘风、 引入的庫
#include "GLTools.h"
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLGeometryTransform.h"
#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
2、用到的變量
// 著色器管理類
GLShaderManager shaderManager;
//模型視圖矩陣堆棧
GLMatrixStack modelViewMatrix;
//投影矩陣堆棧
GLMatrixStack projectionMatrix;
//照相機(jī) 參考幀
GLFrame cameraFrame;
//模型 參考幀
GLFrame objectFrame;
//投影矩陣
GLFrustum viewFrustum;
//容器類 對應(yīng)GL_TRIANGLES 圖元類型
GLBatch triangleBatch;
//幾何變換的管道
GLGeometryTransform transformPipeline;
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
// 跟蹤效果步驟
int nStep = 0;
3纵刘、SetupRC中的邏輯
SetupRC 是在main方法中手動調(diào)用邀窃,且只執(zhí)行一次,主要是做著色器初始化假哎、窗口背景初始化瞬捕、頂點(diǎn)數(shù)據(jù)的準(zhǔn)備等工作,在這個案例中舵抹,此方法主要是初始化了繪制金字塔需要的頂點(diǎn)數(shù)據(jù)肪虎。
void SetupRC()
{
// 灰色的背景
glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
//初始化著色器
shaderManager.InitializeStockShaders();
//將相機(jī)向前移動15個單元
cameraFrame.MoveForward(-15.0f);
/*
常見函數(shù):
void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);
參數(shù)1:表示使用的圖元
參數(shù)2:頂點(diǎn)數(shù)
參數(shù)3:紋理坐標(biāo)(可選)
//負(fù)責(zé)頂點(diǎn)坐標(biāo)
void GLBatch::CopyVertexData3f(GLFloat *vNorms);
//結(jié)束,表示已經(jīng)完成數(shù)據(jù)復(fù)制工作
void GLBatch::End(void);
*/
// 通過三角形創(chuàng)建金字塔
GLfloat vPyramid[12][3] = {
-2.0f, 0.0f, -2.0f,
2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f,
2.0f, 0.0f, -2.0f,
2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
-2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f
};
//GL_TRIANGLES 每3個頂點(diǎn)定義一個新的三角形
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
}
4惧蛹、ChangeSize中的邏輯
ChangeSize為重塑方法扇救,當(dāng)?shù)谝淮蝿?chuàng)建窗口或者窗口改變時候系統(tǒng)調(diào)用,主要在該方法中使用窗口維度設(shè)置視口和投影矩陣香嗓。
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
//創(chuàng)建投影矩陣迅腔,并將它載入投影矩陣堆棧中
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
將投影矩陣載入投影堆棧
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//將單元矩陣載入模型視圖矩陣堆棧
modelViewMatrix.LoadIdentity();
//設(shè)置變換管線以使用兩個矩陣堆棧
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
5、RenderScene中的邏輯
RenderScene同ChangeSize一樣靠娱,需要在main函數(shù)里注冊通知钾挟,當(dāng)屏幕發(fā)生變化或者通過調(diào)用glutPostRedisplay方法,從而讓系統(tǒng)調(diào)用饱岸。
在此方法中掺出,主要通過模型視圖堆棧,做了一系列的矩陣計算苫费,從而得到一個新的模型視圖堆棧汤锨。最后通過渲染管線獲取到模型視圖矩陣以及投影矩陣,作為固定著色器中幾何圖形變換的變換矩陣百框。
void RenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//壓棧
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
//矩陣乘以矩陣堆棧的頂部矩陣闲礼,相乘的結(jié)果隨后簡存儲在堆棧的頂部
modelViewMatrix.MultMatrix(mCamera);
M3DMatrix44f mObjectFrame;
//只要使用 GetMatrix 函數(shù)就可以獲取矩陣堆棧頂部的值,這個函數(shù)可以進(jìn)行2次重載铐维。用來使用GLShaderManager 的使用柬泽。或者是獲取頂部矩陣的頂點(diǎn)副本數(shù)據(jù)
objectFrame.GetMatrix(mObjectFrame);
//矩陣乘以矩陣堆棧的頂部矩陣嫁蛇,相乘的結(jié)果隨后簡存儲在堆棧的頂部
modelViewMatrix.MultMatrix(mObjectFrame);
/* GLShaderManager 中的Uniform 值——平面著色器
參數(shù)1:平面著色器
參數(shù)2:運(yùn)行為幾何圖形變換指定一個 4 * 4變換矩陣
--transformPipeline.GetModelViewProjectionMatrix() 獲取的
GetMatrix函數(shù)就可以獲得矩陣堆棧頂部的值
參數(shù)3:顏色值(黑色)
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
DrawWireFramedBatch(&triangleBatch);
//還原到以前的模型視圖矩陣(單位矩陣)
modelViewMatrix.PopMatrix();
// 進(jìn)行緩沖區(qū)交換
glutSwapBuffers();
}
//方法主要實現(xiàn)金字塔的黑色邊緣
void DrawWireFramedBatch(GLBatch* pBatch)
{
/*------------畫綠色部分----------------*/
/* GLShaderManager 中的Uniform 值——平面著色器
參數(shù)1:平面著色器
參數(shù)2:運(yùn)行為幾何圖形變換指定一個 4 * 4變換矩陣
--transformPipeline 變換管線(指定了2個矩陣堆棧)
參數(shù)3:顏色值
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
pBatch->Draw();
/*-----------邊框部分-------------------*/
/*
glEnable(GLenum mode); 用于啟用各種功能锨并。功能由參數(shù)決定
參數(shù)列表:http://blog.csdn.net/augusdi/article/details/23747081
注意:glEnable() 不能寫在glBegin() 和 glEnd()中間
GL_POLYGON_OFFSET_LINE 根據(jù)函數(shù)glPolygonOffset的設(shè)置,啟用線的深度偏移
GL_LINE_SMOOTH 執(zhí)行后睬棚,過慮線點(diǎn)的鋸齒
GL_BLEND 啟用顏色混合第煮。例如實現(xiàn)半透明效果
GL_DEPTH_TEST 啟用深度測試 根據(jù)坐標(biāo)的遠(yuǎn)近自動隱藏被遮住的圖形(材料
glDisable(GLenum mode); 用于關(guān)閉指定的功能 功能由參數(shù)決定
*/
//畫黑色邊框
glPolygonOffset(-1.0f, -1.0f);// 偏移深度解幼,在同一位置要繪制填充和邊線,會產(chǎn)生z沖突包警,所以要偏移
glEnable(GL_POLYGON_OFFSET_LINE);
// 畫反鋸齒撵摆,讓黑邊好看些
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//繪制線框幾何黑色版 三種模式,實心害晦,邊框特铝,點(diǎn),可以作用在正面壹瘟,背面苟呐,或者兩面
//通過調(diào)用glPolygonMode將多邊形正面或者背面設(shè)為線框模式,實現(xiàn)線框渲染
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//設(shè)置線條寬度
glLineWidth(2.5f);
/* GLShaderManager 中的Uniform 值——平面著色器
參數(shù)1:平面著色器
參數(shù)2:運(yùn)行為幾何圖形變換指定一個 4 * 4變換矩陣
--transformPipeline.GetModelViewProjectionMatrix() 獲取的
GetMatrix函數(shù)就可以獲得矩陣堆棧頂部的值
參數(shù)3:顏色值(黑色)
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
pBatch->Draw();
// 復(fù)原原本的設(shè)置
//通過調(diào)用glPolygonMode將多邊形正面或者背面設(shè)為全部填充模式
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
至此俐筋,一個金字塔就畫完了牵素,效果如下圖。
二澄者、矩陣堆棧
在上述的RenderScene()方法中笆呆,有著modelViewMatrix.PushMatrix()、modelViewMatrix.PopMatrix()這樣的代碼存在粱挡,這就是壓棧與出棧赠幕。
下面附上矩陣壓棧出棧的釋義圖。
1询筏、PushMatrix()
壓棧: 和數(shù)據(jù)結(jié)構(gòu)中的棧類似榕堰,調(diào)用這個方法的時候,若傳入一個矩陣嫌套,則將該矩陣壓入棧頂逆屡;若不傳入?yún)?shù),則默認(rèn)copy一份當(dāng)前棧頂矩陣踱讨,壓入棧頂魏蔗,主要作用就是記錄狀態(tài),保存當(dāng)時的臨時結(jié)果痹筛。
2莺治、MultMatrix(x)
矩陣相乘:將棧頂元素copy一份,并與x矩陣相乘帚稠,得到的結(jié)果賦值給矩陣堆棧的棧頂矩陣谣旁。
3、PopMatrix()
矩陣出棧:將棧頂矩陣出棧滋早,恢復(fù)為原始的矩陣堆棧榄审。
在使用完該棧之后,這個方法必須調(diào)用馆衔。原因就是瘟判,之前有提到怨绣,OpenGL上下文本身就是一個巨大的狀態(tài)機(jī)角溃,若在這里不將棧頂矩陣出棧拷获,對于在其他使用到該矩陣堆棧的地方來說,矩陣數(shù)據(jù)就會錯亂减细。