前言:前一部分了解了OpenGL環境搭建和基本API以後,咱們先來作一個小小的練習,使用固定管線來繪製一個可移動的三角形,同時詳細解釋一下一些經常使用方法的含義
複製代碼
搭建Xcode環境,這裏再也不作過多贅述了windows
傳送門:juejin.im/post/5d67e1…數組
(注:完整代碼在文章的最後面) 一、首先來到main函數中進行環境初始化和一些函數的註冊安全
int main(int argc,char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
glutInitWindowSize(800,600);
glutCreateWindow("Triangle");
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;
}
複製代碼
下面來一一分析對應函數和方法的意思,bash
gltSetWorkingDirectory(argv[0]) : 是」GLTools「用來設置當前工做目錄的函數,實際上在windows中是沒必要要的,由於工做目錄默認就是與程序的可執行程序的目錄相同。可是在Mac OSX環境中,這個程序將當前工做文件夾改成應用程序捆綁包中的"/Resource"文件夾.'GLUT'的優先設定會自動設定爲這個,這樣寫也是爲了更加安全。框架
glutInit(&argc, argv): 初始化GLUT庫,這個函數只是傳入命令參數而且初始化glut庫函數
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL): 設置顯示模式。其中GLUT_DOUBLE 指的是初始化雙緩衝窗口顯示模式,GLUT_RGBA RGBA顏色顯示模式,GLUT_DEPTH 初始化深度測試顯示模式,能夠用於開啓深度測試,GLUT_STENCIL 初始化模板緩衝區oop
glutInitWindowSize(800,600) 初始化一個GLUT窗口並設置窗口大小 glutCreateWindow("Triangle") 設置窗口的標題post
glutReshapeFunc(ChangeSize) 註冊綁定重塑函數,當窗口第一次建立或者窗口大小發生變化,須要界面重繪時,系統會自動調用這個已經註冊過的自定義函數ChangeSize glutDisplayFunc(RenderScene) 註冊綁定顯示函數,當屏幕發生渲染或者你使用代碼強制渲染,須要界面重繪的時候,系統會自動調用這個已經註冊綁定過的自定義函數RenderSize測試
glutSpecialFunc(SpecialKeys); 當你使用特殊鍵位的時候好比鍵盤的上下左右鍵的時候,就會走到這個方法裏,在這個函數中作特殊鍵位區分的時候,這些特殊鍵位都有對應的枚舉值好比上(GLUT_KEY_UP) 下(GLUT_KEY_DOWN)左(GLUT_KEY_LEFT)右(GLUT_KEY_RIGHT),我找了一些,這個簡單瞭解一下就好了ui
#define GLUT_KEY_F1 1
#define GLUT_KEY_F2 2
#define GLUT_KEY_F3 3
#define GLUT_KEY_F4 4
#define GLUT_KEY_F5 5
#define GLUT_KEY_F6 6
#define GLUT_KEY_F7 7
#define GLUT_KEY_F8 8
#define GLUT_KEY_F9 9
#define GLUT_KEY_F10 10
#define GLUT_KEY_F11 11
#define GLUT_KEY_F12 12
/* directional keys */
#define GLUT_KEY_LEFT 100
#define GLUT_KEY_UP 101
#define GLUT_KEY_RIGHT 102
#define GLUT_KEY_DOWN 103
#define GLUT_KEY_PAGE_UP 104
#define GLUT_KEY_PAGE_DOWN 105
#define GLUT_KEY_HOME 106
#define GLUT_KEY_END 107
#define GLUT_KEY_INSERT 108
複製代碼
GLenum err = glewInit(); 初始化一個GLEW庫,確保OpenGL API對程序徹底可用,在試圖作任何渲染以前,要檢查肯定驅動程序的初始化過程當中沒有任何問題
SetupRC() 自定方法,設置咱們的渲染環境
glutMainLoop() 運行循環,相似OC的Runloop,函數在調用以後,在主窗口被關閉以前都不會返回,一個應用程序只須要調用一次,這個函數負責處理咱們全部的消息,直到咱們關閉程序爲止。
二、接着引入固定管線着色器和OpenGL一些基本庫文件
#include "GLShaderManager.h"
#include "GLTools.h"
#include <glut/glut.h>
複製代碼
GLShaderManager.h 這個移入了GLTool着色器管理器類shader manager,沒有着色器,咱們就不能再OpenGL核心框架進行着色,着色器管理器不只容許咱們建立並管理着色器,還提供了一組」存儲着色器「,他們可以進行一些基本的渲染操做。
GLTools.h GLTool.h頭文件包含了大部分GLTool中相似C語言的獨立函數
GLUT/GLUT.h 在Mac 系統下,須要#include <glut/glut.h> ; 在windows和Linux上,咱們使用freeglut的靜態庫版本並須要添加一個宏
三、重塑函數的實現,在窗口大小改變的時候,接受新的寬度和高度
void changeSize(int w,int h)
{
glViewport(0, 0, w, h);
}
複製代碼
glViewPort這個函數就是設置視口,x,y 參數表明窗口中視圖的左下角座標,而寬度、高度是像素爲表示,一般x,y 都是爲0,調用glViewPort會調用從新渲染RenderScene
四、接着定義一個着色器管理變量和一個批次類,GLBatch是GLTools的一個簡單的容器類
GLBatch triangleBatch;
GLShaderManager shaderManager;
複製代碼
五、接下來,咱們須要設置渲染環境和頂點數據
void SetupRC()
{
glClearColor(0.0f,0.0f,1.0f,1.0f);
shaderManager.InitializeStockShaders();
GLfloat vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,1.0f,0.0f,
};
triangleBatch.Begin(GL_TRIANGLES,3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
複製代碼
glClearColor 設置清屏顏色,設置到顏色緩衝區裏面,是一個狀態基,能夠理解爲窗口的背景色
shaderManager.InitializeStockShaders() 初始化一個着色器管理器
GLfloat vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,1.0f,0.0f,
};
定義一個一維數組,裏面存儲三角形的三個頂點的座標,每一個頂點有三個數(x,y,z)
複製代碼
其中 triangleBatch.Begin(GL_TRIANGLES,3); 第一個參數GL_TRIANGLES指的是選擇三角形的鏈接方式,第二個參數3表明3個頂點
triangleBatch.CopyVertexData3f(vVerts);把頂點數據copy進去,而後triangleBatch.End();表示設置完成
這裏拓展一下便於理解,若是是畫四邊形SetUpRC中的頂點座標須要修改爲
若是是要繪製四邊形,須要修改頂點數組,而後修改鏈接方式以下
void SetupRC()
{
glClearColor(0.0f,0.0f,1.0f,1.0f);
shaderManager.InitializeStockShaders();
GLfloat vVerts[] = {
-0.5f,-0.5f,0.0f,
-0.5f,0.5f,0.0f,
0.5f,0.5f,0.0f,
0.5f,-0.5f,0.0f,
};
triangleBatch.Begin(GL_TRIANGLE_FAN,4);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
複製代碼
對比一下,頂點數組變了,而後鏈接方式由GL_TRIANGLES變爲GL_TRIANGLE_FAN,頂點個數由3個變爲4個
頂點數組的變化很明顯,就不細說了
鏈接方式和頂點個數變了
//三角形的
triangleBatch.Begin(GL_TRIANGLES,3);
//四邊形的
triangleBatch.Begin(GL_TRIANGLE_FAN,4);
複製代碼
這裏再拓展一下,OpenGL圖元只有點、線、三角形,如今畫點,線以及多邊形都沒問題了,圓形就須要經過這三個作處理一下了
六、接下來咱們須要設置渲染
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);
triangleBatch.Draw();
glutSwapBuffers();
}
複製代碼
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT) 每次渲染前須要清除特定緩衝區好比深度緩衝區,顏色緩衝區
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed) 不一樣的着色器,參數都是不同的,可是函數名都是這個,繪製簡單的三角形,用單元着色器就好了,因此選GLT_SHADER_IDENTITY,並設置繪製顏色
triangleBatch.Draw() 開始顏色渲染
glutSwapBuffers() 交換緩衝區,把渲染的內容提交上去
執行一下,就能看到藍色背景的windows下,有一個紅色的三角形
七、開始設置移動,設置移動以前須要把頂點座標設置爲全局變量,這樣好處理,把下面頂點數組放到全局
GLfloat vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,1.0f,0.0f,
};
複製代碼
把這段座標換成下面這段,而後把邊長減少點,便於查看效果
//blockSize 邊長
GLfloat blockSize = 0.1f;
//三角形的3個點座標
GLfloat vVerts[] = {
-blockSize,0.0f,0.0f,
blockSize,0.0f,0.0f,
0.0f,blockSize,0.0f,
};
複製代碼
而後開始實現SpecialKeys函數,這裏拓展一下,頂點較少可使用更新頂點座標這種移動方式,頂點較多的複雜圖形,可使用矩陣進行移動
void SpecialKeys (int key , int x, int y){
GLfloat stepSize = 0.1f;
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;
//更新點的座標 ABC
vVerts[0] = blockX;
vVerts[1] = blockY;
vVerts[3] = blockX + 2 * stepSize;
vVerts[4] = blockY;
vVerts[6] = blockX + stepSize;
vVerts[7] = blockY + stepSize;
triangleBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
複製代碼
其中設置blockX和blockY只是找了第一個點做爲移動座標參照物,而後相對第一個點的座標換算出剩餘兩個點的座標,好比A(-0.1,0,0) B(0.1,0,0),換算成A(blockX,0,0)那此時的B就是(block + 2 * 0.1,0, 0), vVerts[0]這裏面的下標0,表明一維數組中的第一個點的x座標,只上下左右移動,只須要改三個點對應的x,y座標就好了, 三個點想x和y的座標對應的下標分別是0,1和3,4和6,7,這樣思路就很清楚了。
triangleBatch.CopyVertexData3f(vVerts); 這個將頂點數組經過GLBatch幫助類,將頂點數據傳輸到存儲着色器中
**glutPostRedisplay()**這個是手動觸發渲染函數。
而後直接運行,就可以獲得一個能夠用鍵盤控制上下左右移動的三角形。
完整代碼以下
//
// main.cpp
//
// Created by battleMage on 2019/8/11.
// Copyright © 2019 battleMage. All rights reserved.
//
#include "GLShaderManager.h"
#include "GLTools.h"
#include <glut/glut.h>
GLBatch triangleBatch;
GLShaderManager shaderManager;
//blockSize 邊長
GLfloat blockSize = 0.1f;
//三角形的3個點座標
GLfloat vVerts[] = {
-blockSize,0.0f,0.0f,
blockSize,0.0f,0.0f,
0.0f, blockSize,0.0f,
};
void ChangeSize(int w,int h){
glViewport(0,0, w, h);
}
void SpecialKeys (int key , int x, int y){
GLfloat stepSize = 0.1f;
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;
//更新點的座標 ABC
vVerts[0] = blockX;
vVerts[1] = blockY;
vVerts[3] = blockX + 2 * stepSize;
vVerts[4] = blockY;
vVerts[6] = blockX + stepSize;
vVerts[7] = blockY + stepSize;
triangleBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
void SetupRC(){
glClearColor(0.0f,0.0f,1.0f,1.0f);
shaderManager.InitializeStockShaders();
triangleBatch.Begin(GL_TRIANGLES,3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
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);
triangleBatch.Draw();
glutSwapBuffers();
}
int main(int argc,char* argv[]){
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
glutInitWindowSize(800,600);
glutCreateWindow("Triangle");
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;
}
複製代碼
效果以下: