實現繪制正方形,主要分為創建Main函數、設置窗口、設置顯示函數、設置渲染屬性、按鍵監聽函數等五個步驟來實現
第一步:
首先是Main函數,主要是設置監聽窗口尺寸函數、顯示函數、按鍵監聽的改變和設置屬性setupRC(),以及開啟線程和保護線程
#include "GLShaderManager.h"
/*
`#include<GLShaderManager.h>` 移入了GLTool 著色器管理器(shader Mananger)類。沒有著色器,我們就不能在OpenGL(核心框架)進行著色。著色器管理器不僅允許我們創建并管理著色器,還提供一組“存儲著色器”,他們能夠進行一些初步?基本的渲染操作。
*/
#include "GLTools.h"
/*
`#include<GLTools.h>` GLTool.h頭文件包含了大部分GLTool中類似C語言的獨立函數
*/
#include <GLUT/GLUT.h>
/*
在Mac 系統下,`#include<glut/glut.h>`
在Windows 和 Linux上,我們使用freeglut的靜態庫版本并且需要添加一個宏
*/
// 定義一個,著色管理器
GLShaderManager shaderManager;
// 簡單的批次容器,是GLTools的一個簡單的容器類
GLBatch triangleBatch;
// blockSize 邊長
GLfloat blockSize = 0.1f;
//正方形的4個點坐標
GLfloat vVerts[] = {
-blockSize,-blockSize,0.0f,
blockSize,-blockSize,0.0f,
blockSize,blockSize,0.0f,
-blockSize,blockSize,0.0f
};
int main(int argc, char *argv[])
{
//設置當前工作目錄,針對MAC OS X
/*
`GLTools`函數`glSetWorkingDrectory`用來設置當前工作目錄。實際上在Windows中是不必要的,因為工作目錄默認就是與程序可執行執行程序相同的目錄。但是在Mac OS X中,這個程序將當前工作文件夾改為應用程序捆綁包中的`/Resource`文件夾。`GLUT`的優先設定自動進行了這個中設置,但是這樣中方法更加安全。
*/
gltSetWorkingDirectory(argv[0]);
//初始化GLUT庫,這個函數只是傳說命令參數并且初始化glut庫
glutInit(&argc, argv);
/*
初始化雙緩沖窗口,其中標志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分別指
雙緩沖窗口、RGBA顏色模式、深度測試、模板緩沖區
--GLUT_DOUBLE`:雙緩存窗口,是指繪圖命令實際上是離屏緩存區執行的,然后迅速轉換成窗口視圖,這種方式,經常用來生成動畫效果;
--GLUT_DEPTH`:標志將一個深度緩存區分配為顯示的一部分,因此我們能夠執行深度測試;
--GLUT_STENCIL`:確保我們也會有一個可用的模板緩存區。
深度、模板測試后面會細致講到
*/
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
//GLUT 窗口大小、窗口標題
glutInitWindowSize(800, 600);
glutCreateWindow("Hello world!");
/*
GLUT 內部運行一個本地消息循環,攔截適當的消息。然后調用我們不同時間注冊的回調函數。我們一共注冊2個回調函數:
1)為窗口改變大小而設置的一個回調函數
2)包含OpenGL 渲染的回調函數
*/
//注冊重塑函數
glutReshapeFunc(changeSize);
//注冊顯示函數
glutDisplayFunc(RenderScene);
//注冊特殊函數
glutSpecialFunc(SpecialKes);
/*
初始化一個GLEW庫,確保OpenGL API對程序完全可用。
在試圖做任何渲染之前,要檢查確定驅動程序的初始化過程中沒有任何問題
*/
GLenum status = glewInit();
if (GLEW_OK != status) {
printf("GLEW Error: %s\n", glewGetErrorString(status));
return 1;
}
setupRC();
//設置我們的渲染環境
//保護線程的運行
glutMainLoop();
return 0;
}
第二步:窗口尺寸的監聽回調
void changeSize(int w,int h)
{
/*
x,y 參數代表窗口中視圖的左下角坐標,而寬度、高度是像素為表示,通常x,y 都是為0
*/
glViewport(0, 0, w, h);
}
第三步:渲染函數,將設置的正方體渲染出窗口上
void RenderScene(void)
{
//1.清除一個或者一組特定的緩存區
/*
緩沖區是一塊存在圖像信息的儲存空間,紅色、綠色、藍色和alpha分量通常一起分量通常一起作為顏色緩存區或像素緩存區引用。
OpenGL 中不止一種緩沖區(顏色緩存區、深度緩存區和模板緩存區)
清除緩存區對數值進行預置
參數:指定將要清除的緩存的
GL_COLOR_BUFFER_BIT :指示當前激活的用來進行顏色寫入緩沖區
GL_DEPTH_BUFFER_BIT :指示深度緩存區
GL_STENCIL_BUFFER_BIT:指示模板緩沖區
*/
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//2.設置一組浮點數來表示紅色
//GLfloat vRed[] = {1.0,0.0,0.0,1.0f};
//傳遞到存儲著色器,即GLT_SHADER_IDENTITY著色器,這個著色器只是使用指定顏色以默認笛卡爾坐標第在屏幕上渲染幾何圖形
//shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
//提交著色器
//triangleBatch.Draw();
//在開始的設置openGL 窗口的時候,我們指定要一個雙緩沖區的渲染環境。這就意味著將在后臺緩沖區進行渲染,渲染結束后交換給前臺。這種方式可以防止觀察者看到可能伴隨著動畫幀與動畫幀之間的閃爍的渲染過程。緩沖區交換平臺將以平臺特定的方式進行。
//將后臺緩沖區進行渲染,然后結束后交換給前臺
//glutSwapBuffers();
//---------方法2--------
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = {1.0f,0.0f,0.0f,0.0f};
M3DMatrix44f mFinalTransform,mTransfromMatrix,mRotationMartix;
//平移
m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0f);
//每次平移時,旋轉5度
static float yRot = 0.0f;
yRot += 5.0f;
m3dRotationMatrix44(mRotationMartix, m3dDegToRad(yRot), 0.0f, 0.0f, 1.0f);
//將旋轉和移動的矩陣結果 合并到mFinalTransform (矩陣相乘)
m3dMatrixMultiply44(mFinalTransform, mTransfromMatrix, mRotationMartix);
//將矩陣結果 提交給固定著色器(平面著色器)中繪制
shaderManager.UseStockShader(GLT_SHADER_FLAT,mFinalTransform,vRed);
triangleBatch.Draw();
//執行交換緩存區
glutSwapBuffers();
}
第四步:設置基本屬性,設置頂點數據和顏色
void setupRC()
{
//設置清屏顏色(背景顏色)
glClearColor(0.98f, 0.40f, 0.7f, 1);
//沒有著色器,在OpenGL 核心框架中是無法進行任何渲染的。初始化一個渲染管理器。
//在前面的課程,我們會采用固管線渲染,后面會學著用OpenGL著色語言來寫著色器
shaderManager.InitializeStockShaders();
//修改為GL_TRIANGLE_FAN ,4個頂點
triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
第五步:按鍵監聽回調,通過按鍵可以移動正方體的位置
void SpecialKeys(int key, int x, int y){
GLfloat stepSize = 0.025f;
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;
}
//碰撞檢測
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();
}
到此就成功啦!