OpenGL(2)-初探
2020/7/11 23:08:55
本文主要是介绍OpenGL(2)-初探,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
了解了OpenGL
的相关概念,我们再通过两个小示例来看看OpenGL
的相关API
以及图形的绘制流程。
在实现示例之前,我们需要配置相关的环境:
- 添加
OpenGl.framework
和GLUT.framework
系统库,添加libGLTools.a
静态库, - 引入
CLTools
、glew
,并且在Build Settings
的Header Search Paths
中添加CLTools
的路径, - 移除原来的
main
、AppDelegate
、ViewController
文件,创建一个main.cpp
文件。
这样,我们就可以在main.cpp
实现相关功能了。
三角形
引入工具类
#include "GLTools.h" #include <GLUT/GLUT.h> #include "GLShaderManager.h" 复制代码
GLTools.h
:包含了⼤部分GLTools中类似C语言的独立函数GLUT/GLUT.h
:使用glutGLShaderManager.h
:着⾊器管理器,允许我们使用并管理着色器,另外还提供了一组存储着色器,能够进行一些基本的渲染操作
创建全局变量
着色管理器和GL批处理类:
GLShaderManager shaderManager; GLBatch glBatch; 复制代码
代码实现
-
- 初始化、基础设置操作
-
- 注册窗口调整和渲染的回调函数
-
- 配置三角形的顶点数据
int main(int argc,char* argv[]) { // 设置当前工作目录,针对MAC OS X gltSetWorkingDirectory(argv[0]); // 初始化GLUT库 glutInit(&argc, argv); // 初始化双缓冲窗口 // GLUT_DOUBLE表示双缓冲窗口、GLUT_RGBA表示RGBA颜色模式、GLUT_DEPTH表示深度测试、GLUT_STENCIL表示模板缓冲区 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL); // 设置GLUT窗口大小、标题 glutInitWindowSize(800, 800); glutCreateWindow("Triangle"); // 注册回调函数 // 窗口调整 glutReshapeFunc(reshapeAction); // 渲染操作 glutDisplayFunc(renderAction); // 驱动程序的初始化中容错判断 GLenum error = glewInit(); if(GLEW_OK != error) { fprintf(stderr,"glew error:%s\n",glewGetErrorString(error)); return 1; } // 初始化设置 setupTriangle(); glutMainLoop(); return 0; } void setupTriangle() { // 设置窗口背景颜色 glClearColor(1, 1, 1, 1); // 初始化着色管理器 shaderManager.InitializeStockShaders(); // 设置三角形的顶点坐标 x y z GLfloat vertCoordinates[] = { -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, }; // 批次处理 glBatch.Begin(GL_TRIANGLES, 3); glBatch.CopyVertexData3f(vertCoordinates); glBatch.End(); } // 窗口调整 void reshapeAction(int width, int height) { // glViewport (GLint x, GLint y, GLsizei width, GLsizei height) // x,y 以像素为单位,指定了窗口的左下角位置。width,height表示视口矩形的宽度和高度,根据窗口的实时变化重绘窗口。 glViewport(0, 0, width, height); } // 渲染 void renderAction() { // 清除一个或一组特定的缓冲区 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // 设置颜色 GLfloat vRed[] = {1.0, 0.0, 0.0, 1.0}; // 着色管理器使用存储着色器进行渲染 shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed); glBatch.Draw(); // 双缓冲处理,交换缓冲区指针 glutSwapBuffers(); } 复制代码
固定管线存储着色器
GLT_SHADER_IDENTITY
:单位着色器/单元着色器
使用默认笛卡尔坐标系,坐标范围为(-1.0,1.0),所有片段都应用同一种颜色。使用方法:
shaderManager.UserStockShader(GLT_SHADER_IDENTITY, GLfloat vColor[4]); 复制代码
- 参数1:着色器类型
- 参数2:颜色参数
GLT_SHADER_FLAT
:平面着色器
用以模型/投影变化。可以为几何图形变化指定一个4*4变换矩阵,该矩阵被称为“模型视图投影矩阵”。使用方法:
shaderManager.UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]); 复制代码
- 参数1:着色器类型
- 参数2:4*4变换矩阵
- 参数3:颜色参数
GLT_SHADER_SHADED
:上色着色器
用以将颜色平滑的插入到顶点之间,进行平滑着色。使用方法:
shaderManager.UserStockShader(GLT_SHADER_SHADED,GLfloat vColor[4]); 复制代码
- 参数1:着色器类型
- 参数2:颜色参数
GLT_SHADER_DEFAULT_LIGHT
:默认光源着色器
用来为图形产生阴影和光照效果。使用方法:
shaderManager.UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]); 复制代码
- 参数1:着色器类型
- 参数2:模型视图矩阵
- 参数3:投影矩阵
- 参数4:颜色参数
GLT_SHADER_POINT_LIGHT_DIFF
:点光源着色器
用来为图形产生阴影和光照效果。与默认光源着色器非常类似,区别在与点光源着色器可以指定光源位置。使用方法:
shaderManager.UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]); 复制代码
- 参数1:着色器类型
- 参数2:模型视图矩阵
- 参数3:投影矩阵
- 参数4:视点坐标光源位置
- 参数5:颜色参数
GLT_SHADER_TEXTURE_REPLACE
:纹理替换矩阵着色器
通过给定的模型视图投影矩阵,使用纹理单元来进行填充,其每个像素点的颜色是从纹理中获取。使用方法:
shaderManager.UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit); 复制代码
- 参数1:着色器类型
- 参数2:模型视图矩阵
- 参数3:纹理单元
GLT_SHADER_TEXTURE_MODULATE
:纹理调整着色器
通过给定的模型视图投影矩阵,将一个基本色乘以一个取自纹理单元nTextureUnit
的纹理,将颜色与纹理进行混合后填充到片段中。使用方法:
shaderManager.UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLfloat mvMatrix[16],GLfloat vColor[4],GLint nTextureUnit); 复制代码
- 参数1:着色器类型
- 参数2:模型视图矩阵
- 参数3:颜色参数
- 参数4:纹理单元
GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF
:纹理光源着色器
通过给定的模型视图投影矩阵,将一个纹理通过漫反射照明计算进行调整(相乘)。使用方法:
shaderManager.UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vBaseColor[4],GLint nTextureUnit); 复制代码
- 参数1:着色器类型
- 参数2:模型视图矩阵
- 参数3:视觉空间中的光源位置
- 参数4:几何图形的基本色
- 参数5:需要处理的纹理单元
设置初始显示模式
值 | 对应宏定义 | 含义 |
---|---|---|
GLUT_RGB | 0x0000 | 指定 RGB 颜色模式的窗口 |
GLUT_RGBA | 0x0000 | 指定 RGBA 颜色模式的窗口 |
GLUT_INDEX | 0x0001 | 指定颜色索引模式的窗口 |
GLUT_SINGLE | 0x0000 | 指定单缓存窗口 |
GLUT_DOUBLE | 0x0002 | 指定双缓存窗口 |
GLUT_ACCUM | 0x0004 | 窗口使用累加缓存 |
GLUT_ALPHA | 0x0008 | 窗口的颜色分量包含 alpha 值 |
GLUT_DEPTH | 0x0010 | 窗口使用深度缓存 |
GLUT_STENCIL | 0x0020 | 窗口使用模板缓存 |
GLUT_MULTISAMPLE | 0x0080 | 指定支持多样本功能的窗口 |
GLUT_STEREO | 0x0100 | 指定立体窗口 |
GLUT_LUMINANCE | 0x0200 | 窗口使用亮度颜色模型 |
几何图元
GL_POINTS
:点GL_LINES
:线段,二个点确定线段GL_LINE_STRIP
:第一个点依次连接的线段GL_LINE_LOOP
:和GL_LINE_STRIP
相同,但首尾连接,形成环状GL_POLYGON
:多边形GL_QUADS
:由四个点组成一个四边形GL_QUADS_STRIP
:四边形带GL_TRIANGLES
:三角形,三个点确定GL_TRIANGLE_STRIP
:共用一个条带上的顶点的一组三角形GL_TRIANGLE_FAN
:以一个原点为中心呈扇形排列,公共相邻顶点的一组三角形
可移动的正方形
渲染矩形和渲染三角形在初始化设置上基本一样。实现矩形可以通过修改几何图元的类型即可,下面我们提供两种思路,一种是使用批处理类渲染三角形的方式(GL_TRIANGLES
),将两个三角形拼接成矩形,这样需要6个顶点;另一种是直接使用批处理类渲染矩形的方式(GL_QUADS
或者GL_TRIANGLE_FAN
),需要4个顶点。
GLfloat squareEdge = 0.1; // 给定初始坐标 GLfloat vVerts[] = { -squareEdge, -squareEdge, 0.0, squareEdge, -squareEdge, 0.0, squareEdge, squareEdge, 0.0, -squareEdge, squareEdge, 0.0 }; // 偏移量 GLfloat xPos = 0.0; GLfloat yPos = 0.0; void setupSquare() { glClearColor(1, 1, 1, 1); // 初始化着色管理器 shaderManager.InitializeStockShaders(); // 批次类处理设置为矩形 glBatch.Begin(GL_TRIANGLE_FAN, 4); glBatch.CopyVertexData3f(vVerts); glBatch.End(); } 复制代码
由于我们需要通过键盘控制所绘制矩形的位置,所以我们需要监听键盘的输入,并且修改矩形的位置重新渲染。
// 注册键盘的回调 glutSpecialFunc(squareSpecialKey); 复制代码
此处,我们使用键盘的上下左右键来移动矩形。这里需要做个特殊处理,当矩形移动到窗口的边界时,就需要停止继续移动。注意,这里每次只响应一个键。
void squareSpecialKey(int key, int x, int y) { // 每次移动的步长(距离) GLfloat stepSize = 0.025; // 只响应上下左右键 if (key == GLUT_KEY_UP || key == GLUT_KEY_DOWN || key == GLUT_KEY_LEFT || key == GLUT_KEY_RIGHT) { switch (key) { case GLUT_KEY_UP: yPos += stepSize; break; case GLUT_KEY_DOWN: yPos -= stepSize; break; case GLUT_KEY_LEFT: xPos -= stepSize; break; case GLUT_KEY_RIGHT: xPos += stepSize; break; default: break; } // 边界检测 // -x if (xPos < -1.0 + squareEdge) { xPos = -1.0 + squareEdge; } // x if (xPos > 1.0 - squareEdge) { xPos = 1.0 - squareEdge; } // -y if (yPos < -1.0 + squareEdge) { yPos = -1.0 + squareEdge; } // y if (yPos > 1.0 - squareEdge) { yPos = 1.0 - squareEdge; } glutPostRedisplay(); } } 复制代码
下面就是渲染过程了,考虑到每次移动都需要修改矩阵的坐标,我们可以使用平面着色器,将新的坐标矩阵通过变换之后,直接传给着色器管理器即可。
void squareRender() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // 设置颜色 GLfloat vRed[] = {1.0, 0.0, 0.0, 1.0}; // 矩阵变化 对原来矩形的顶点数组进行变换 将变换之后的结果存入mTransfromMatrix M3DMatrix44f mTransfromMatrix; m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0); shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransfromMatrix, vRed); glBatch.Draw(); glutSwapBuffers(); } 复制代码
圆
渲染一个圆形,我们可以使用几何图元GL_POLYGON
,也就是从圆周上选定无限多个点作为顶点,把这些顶点连接起来,即可组成一个圆。下面示例中,我们选定了10000个顶点。
int n = 10000; GLfloat PI = 3.1415926; // 半径 GLfloat r = 0.5; void setupCircle() { // 设置窗口背景颜色 glClearColor(1, 1, 1, 1); // 初始化着色管理器 shaderManager.InitializeStockShaders(); GLfloat vVerts[30000] = {0}; // 计算顶点 for (int i = 0; i < n; i++) { vVerts[i*3] = r * cos(2 * PI * i / n); vVerts[i*3+1] = r * sin(2 * PI * i / n); vVerts[i*3+2] = 0; } // 批次处理 glBatch.Begin(GL_POLYGON, n); glBatch.CopyVertexData3f(vVerts); glBatch.End(); } 复制代码
这篇关于OpenGL(2)-初探的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-10-05Swift语法学习--基于协议进行网络请求
- 2022-08-17Apple开发_Swift语言地标注释
- 2022-07-24Swift 初见
- 2022-05-22SwiftUI App 支持多语种 All In One
- 2022-05-10SwiftUI 组件参数简写 All In One
- 2022-04-14SwiftUI 学习笔记
- 2022-02-23Swift 文件夹和文件操作
- 2022-02-17Swift中使用KVO
- 2022-02-08Swift 汇编 String array
- 2022-01-30SwiftUI3.0页面反向传值