學習書籍: OpenGL 超級寶典(中文第五版) 密碼:fu4w
書籍原始碼:OpenGL 超級寶典第五版原始碼 密碼:oyb4
環境搭建:OpenGL 學習 01 - Mac 搭建 OpenGL 環境
上一節我們學了如何在視窗上渲染一個三角形,這節我們在此基礎上加入圖形的移動,並且圖形從三角形變成矩形。
畫矩形
上一節我們設定三角形資料程式碼如下:
//開始構建批次,GL_TRIANGLES 表示三角形,後面引數是頂點數
triangleBatch.Begin(GL_TRIANGLES, 3);
//批次增加儲存屬性,頂點資料
triangleBatch.CopyVertexData3f(vVerts);
//結束批次屬性設定,表明完成資料複製操作,不能再新增新屬性
triangleBatch.End();
複製程式碼
和三角形相似,而設定矩形資料用到的是 GL_TRIANGLE_FAN
, 頂點數為 4 個
//開始構建批次,GL_TRIANGLE_FAN 表示四邊形,後面引數是頂點數
squareBatch.Begin(GL_TRIANGLE_FAN, 4);
//批次增加儲存屬性,頂點資料
squareBatch.CopyVertexData3f(vVerts);
//結束批次屬性設定,表明完成資料複製操作,不能再新增新屬性
squareBatch.End();
複製程式碼
這個具體有多少種圖形型別(也叫圖元),以後我們會逐步介紹,這裡就不詳細講了
按鍵移動
檢測鍵盤的方向鍵點選,需要呼叫 GLUT 的鍵盤特殊按鍵回撥註冊函式,和視窗大小變化、視窗渲染回撥註冊函式形式一樣
//註冊視窗大小變化回撥函式
glutReshapeFunc(ChangeSize);
//註冊視窗渲染回撥函式
glutDisplayFunc(RenderScene);
//註冊鍵盤特殊按鍵點選回撥函式
glutSpecialFunc(SpecialKeys);
複製程式碼
注意:這裡是鍵盤特殊按鍵點選回撥註冊(
glutSpecialFunc
),GLUT 語法中,特殊按鍵指功能鍵或者方向鍵(上、下、左、右箭頭鍵等),它還有另外一個鍵盤普通按鍵點選的回撥註冊(glutKeyboardFunc
),比如空格。
/*
* 引數 key 表示按鍵的唯一標識,(x, y) 是發生按鍵事件時滑鼠點所處位置(以左上角為起點)
* 上、下、左、右箭頭按鍵分別對應的 key 值為:
* GLUT_KEY_UP、GLUT_KEY_DOWN、GLUT_KEY_LEFT、GLUT_KEY_RIGHT
*/
void SpecialKey(GLint key, GLint x, GLint y);
複製程式碼
邊界檢測
我們不希望矩形移動出我們的視窗範圍,這裡就需要在移動時進行邊界檢測,在做邊界檢測前,我們需要了解視窗的座標系
視窗座標系預設是從 -1.0f 到 1.0f,中央是座標原點,而我們的矩形起始位置的中央也是原點,邊長為 0.4f,所以頂點座標為:
// 這裡用 blockSize 來儲存矩形的半邊長,便於之後修改矩形邊長
GLfloat blockSize = 0.2f;
GLfloat vVerts[] = {
-blockSize, -blockSize, 0.0f, //左下角
blockSize, -blockSize, 0.0f, //右下角
blockSize, blockSize, 0.0f, //右上角
-blockSize, blockSize, 0.0f //左上角
};
複製程式碼
邊界檢測,這裡我以左下角頂點為標準進行判斷,如上圖可以得到以下邊界檢測程式碼:
//左下角座標的 (x, y)
GLfloat blockX = vVerts[0];
GLfloat blockY = vVerts[1];
//中間進行移動
...
//邊界檢測,讓矩形沒法超出邊界
if(blockX < -1.0f) blockX = -1.0f;
if(blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;
if(blockY < -1.0f) blockY = -1.0f;
if(blockY > (1.0f - blockSize * 2)) blockY = 1.0f - blockSize * 2;
複製程式碼
矩形按鍵移動
#include <iostream>
#include <GLShaderManager.h>
#include <GLTools.h>
#include <glut/glut.h>
GLBatch squareBatch;
GLShaderManager shaderManager;
GLfloat blockSize = 0.2f;
GLfloat vVerts[] = {
-blockSize, -blockSize, 0.0f, //左下角
blockSize, -blockSize, 0.0f, //右下角
blockSize, blockSize, 0.0f, //右上角
-blockSize, blockSize, 0.0f //左上角
};
void BourceFunction(int key) {
//每次按鍵的矩形移動距離
GLfloat stepSize = 0.025f;
//左下角座標的 (x, y)
GLfloat blockX = vVerts[0];
GLfloat blockY = vVerts[1];
//判斷鍵盤點選的是哪個按鈕,計算下一個點的位置
if(key == GLUT_KEY_UP) blockY += stepSize;
if(key == GLUT_KEY_DOWN) blockY -= stepSize;
if(key == GLUT_KEY_LEFT) blockX -= stepSize;
if(key == GLUT_KEY_RIGHT) blockX += stepSize;
//邊界檢測,讓矩形沒法超出邊界
if(blockX < -1.0f) blockX = -1.0f;
if(blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;
if(blockY < -1.0f) blockY = -1.0f;
if(blockY > (1.0f - blockSize * 2)) blockY = 1.0f - blockSize * 2;
//設定下個位置的 4 個頂點座標
//左下角
vVerts[0] = blockX;
vVerts[1] = blockY;
//右下角
vVerts[3] = blockX + blockSize * 2;
vVerts[4] = blockY;
//右上角
vVerts[6] = blockX + blockSize * 2;
vVerts[7] = blockY + blockSize * 2;
//左上角
vVerts[9] = blockX;
vVerts[10] = blockY + blockSize * 2;
//批次裡面的資料更新
squareBatch.CopyVertexData3f(vVerts);
}
// 監控特殊按鍵(功能鍵和方向鍵)點選
void SpecialKeys(int key, int x, int y) {
//計算下一個矩形位置
BourceFunction(key);
//觸發重畫事件 -> RenderScene
glutPostRedisplay();
}
//視窗渲染
void RenderScene(void) {
//清除一個或一組特定的緩衝區
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//利用單位著色器設定矩形顏色為紅色
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
//畫圖
squareBatch.Draw();
//將在後臺緩衝區進行渲染,然後在結束時交換到前臺
glutSwapBuffers();
}
//為程式作一次性的設定
void SetupRC() {
//設定背景顏色為藍色
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
//著色器初始化
shaderManager.InitializeStockShaders();
//批次初始化
squareBatch.Begin(GL_TRIANGLE_FAN, 4);
squareBatch.CopyVertexData3f(vVerts);
squareBatch.End();
}
//視窗大小改變時接受新的寬度和高度,其中0,0代表視窗中視口的左下角座標,w,h代表畫素
void ChangeSize(int width, int height) {
glViewport(0, 0, width, height);
}
//程式入口
int main(int argc, char* argv[]) {
//設定當前工作目錄,針對MAC OS X
gltSetWorkingDirectory(argv[0]);
//初始化GLUT庫
glutInit(&argc, argv);
/*初始化渲染模式,其中標誌GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分別指
雙緩衝視窗、RGBA顏色模式、深度測試、模板緩衝區*/
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//初始化視窗大小
glutInitWindowSize(800, 600);
//建立視窗
glutCreateWindow("MoveDemo");
//註冊視窗大小變化回撥函式
glutReshapeFunc(ChangeSize);
//註冊視窗渲染回撥函式
glutDisplayFunc(RenderScene);
//註冊鍵盤特殊按鍵點選回撥函式
glutSpecialFunc(SpecialKeys);
//確保驅動程式的初始化中沒有出現任何問題。
GLenum err = glewInit();
if(GLEW_OK != err) {
fprintf(stderr, "glew error:%s\n", glewGetErrorString(err));
return 1;
}
//初始化設定
SetupRC();
//進入呼叫迴圈
glutMainLoop();
return 0;
}
複製程式碼
矩形自動移動,按鍵控制方向
這裡我們注意到在 SpecialKeys
方法中呼叫了 glutPostRedisplay
方法觸發視窗渲染,得到的效果是我們按一下矩形就走一下,如果我們想讓矩形自己動,我們只控制方向,怎麼辦呢?
矩形自己動,就需要自動持續重新整理,只需要修改視窗渲染 RenderScene
程式碼為以下程式碼即可:
//視窗渲染
void RenderScene(void) {
//清除一個或一組特定的緩衝區
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//利用單位著色器設定矩形顏色為紅色
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
//畫圖
squareBatch.Draw();
//將在後臺緩衝區進行渲染,然後在結束時交換到前臺
glutSwapBuffers();
//計算下一個矩形位置,specialKey 是全域性記錄的特殊按鍵 key
BounceFunction(specialKey);
//觸發重畫事件 -> RenderScene
glutPostRedisplay();
}
複製程式碼
注意:這裡不是一個無限迴圈,重繪訊息實際上是一條傳遞到一個內部訊息迴圈中的訊息,在螢幕重新整理的間隔中,也會發生其他視窗事件,我們仍可以檢測按鍵、滑鼠移動、改變視窗大小等動作。
specialKey
的記錄程式碼如下:
int specialKey = GLUT_KEY_RIGHT;
// 監控特殊按鍵(功能鍵和方向鍵)點選
void SpecialKeys(int key, int x, int y) {
specialKey = key;
}
複製程式碼
Demo 原始碼在這裡:02-MoveDemo
有什麼問題可以在下方評論區提出,求關注求贊,O(∩_∩)O哈哈~