一步步学OpenGL(一)(3)

2020-04-18 03:41

/**

* 渲染回调函数 */

static void RenderScenceCB(){ // 清空颜色缓存

glClear(GL_COLOR_BUFFER_BIT);

// 开启顶点属性

glEnableVertexAttribArray(0);

// 绑定GL_ARRAY_BUFFER缓冲器

glBindBuffer(GL_ARRAY_BUFFER, VBO); // 告诉管线怎样解析bufer中的数据

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

// 开始绘制几何图形(绘制一个三角形,三个顶点) glDrawArrays(GL_TRIANGLES, 0, 3);

// 禁用顶点数据

glDisableVertexAttribArray(0);

// 交换前后缓存 glutSwapBuffers();

glFlush(); } /**

* 创建顶点缓冲器 */

static void CreateVertexBuffer() {

// 创建含有3个顶点的顶点数组 Vector3f Vertices[3];

// 三角形的三个顶点位置

Vertices[0] = Vector3f(-1.0f, -1.0f, 0.0f); Vertices[1] = Vector3f(1.0f, -1.0f, 0.0f); Vertices[2] = Vector3f(0.0f, 1.0f, 0.0f);

// 创建缓冲器

glGenBuffers(1, &VBO);

// 绑定GL_ARRAY_BUFFER缓冲器

glBindBuffer(GL_ARRAY_BUFFER, VBO); // 绑定顶点数据

glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW); } /**

* 主函数 */

int main(int argc, char ** argv) {

// 初始化GLUT glutInit(&argc, argv);

// 显示模式:双缓冲、RGBA

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

// 窗口设置

glutInitWindowSize(480, 320); // 窗口尺寸 glutInitWindowPosition(100, 100); // 窗口位置 glutCreateWindow(\ // 窗口标题

// 开始渲染

glutDisplayFunc(RenderScenceCB);

// 缓存清空后的颜色值

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

// 检查GLEW是否就绪,必须要在GLUT初始化之后! GLenum res = glewInit(); if (res != GLEW_OK) {

fprintf(stderr, \ return 1; }

// 创建顶点缓冲器 CreateVertexBuffer();

// 通知开始GLUT的内部循环 glutMainLoop();

return 0; }

四 着色器

背景:

从这篇教程开始,我们将使用shader着色器来实现每一个效果和技术点。着色器是目前做3D图形最流行的方式。在某种程度上我们可以说这是一个“退步”吧,或者说技术实现上的一个回退,因为本来多数固定功能管线提供的那些3D功能(开发者只需要定义配置参数即可实现的功能函数)现在开发者必须自己通过shader着色器来实现,然而同时,这个可编程性也使我们的开发更加灵活和具有创新性。

PS:理解这篇文章的介绍,对OpenGL的渲染管线整个流程就很清晰了!

OpenGL的可编程管线可以通过下面的图示来表示:

顶点处理器—>几何处理器—>裁剪器—>光栅器(片段处理器)

Vertex Processor顶点处理器阶段负责执行处理经过管线的每一个顶点的vertex shader顶点着色代码(顶点的数量取决于draw call的参数)。顶点着色器还并不知道渲染的图元的topology拓扑结构是怎样的。另外你不可以在顶点着色处理器阶段删除丢弃顶点。每个顶点有且只有一次经过顶点处理器,经过变换后继续进入管线的下一步。

下一个阶段是Geometry Processor几何处理器阶段。在这个阶段,图元的完整数据(比如:所有的顶点数据)和相邻顶点的数据全部都提供给shader着色器,这样可以使其必须考虑除了顶点本身的其他的一些额外的更全面完整的信息。几何处理器还可以将输出的图形拓扑结构转换成在draw call中选择的另一种结构。比如:你可以提供一系列的点来产生由两个三角形所构成的图形(像四边形),也就是顶点链接成三角形图元,两个三角形图元可以构成四边形(一种叫做billboarding公告板技术的技术)。另外,你也可以直接给几何着色器提供多个顶点然后根据你选择的输出拓扑结构产生多种图元。

在管线的下一个阶段就要开始clip裁剪工作了。这是一个固定功能单元的很明确的一个任务:像前面教程中一样它将所有图元裁剪到那个单位化的盒子模型内,它另外还会将图元裁剪在Z轴的远近平面范围内(也就是说太远或太近都不显示)。同时也提供用户自定义的裁

剪平面进行自定义的裁剪。经过裁剪后保留下来的顶点现在会被映射到屏幕空间坐标系上,光栅器将会根据他们的拓扑结构把他们渲染到屏幕上。举个例子:对于三角形的裁剪就是发现三角形内部所有可见的点,对每个点rasterizer光栅器都会触发fragment processor片段处理器,现在你可以对每个片段像素定义颜色,颜色可以从一张材质上取或者使用其他取色技术方式。

上面这三个可编程阶段(vertex processor顶点处理、geometry processor几何处理和fragment processor片段处理)都是可选的而不是必须的。如果你不在这几个处理器上绑定你自己的shaer着色器,那么就会执行一些默认的函数功能,也就是备胎着色器。

Shader着色器的使用跟C/C++程序的创建过程类似。首先你要写一个shader着色器文本并使其在你的程序中有效可用,这个过程可以通过依次简单的引用这些源码脚本或者从外部文件中加载,注意都是以字符串数组的形式。然后一个个的编译这些shader文本成shader对象。然后你就可以将这些shader着色器连接到单个程序中并加载到GPU中。链接这些shader可以使驱动器能够有机会精减这些shader并根据他们的关系优化他们。例如:可能一个顶点着色器发出的法向量在相应的片段着色器阶段中被忽视,这样驱动中的GLSL编译器就会移除着色器中与这个法向量相关的函数功能从而更快的执行这个顶点着色器。如果之后那个着色器又匹配了需要用到那个法向量的片段着色器,然后连接到其他程序后会产生一个不同的顶点着色器。

源代码详解

(1)GLuint ShaderProgram = glCreateProgram();

我们通过创建程序对象来建立shader着色器程序。我们将把所有的着色器连接到这个对象上。

(2)GLuint ShaderObj = glCreateShader(ShaderType);

使用上面的函数创建两个shader着色器对象。其中一个使用的ShaderType为GL_VERTEX_SHADER,另一个的类型为GL_FRAGMENT_SHADER。这两个着色器对象的shader脚本源定义和他们的编译方式是一样的。 (3)

const GLchar* p[1]; p[0] = pShaderText; GLint Lengths[1];

Lengths[0]= strlen(pShaderText);

glShaderSource(ShaderObj, 1, p, Lengths);

在编译shader对象之前我们必须先定义它的代码源。函数glShaderSource以shader对象为参数,使你可以灵活的定义代码来源。shader源代码(也就是我们所常说的shader脚本)可以由多个字符串数组排布组合而成,你需要提供一个指针数组来对应指向这些字符窜数组,同时要提供一个整型数组来对应表示每个数组的长度。为了简单,我们这里只使用一个字符串数组来保存所有的shader源代码,并且分别用数组的一个元素来分别指向这个字符串数组和表示数组的长度。

第二个参数表示的是这两个数组的元素个数(我们的例子中则只有1个)。


一步步学OpenGL(一)(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:张静中学中考历史复习资料5

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: