在OpenGL中,任何事物都在3D空间中,而屏幕和窗口却是2D像素数组,这导致OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线
管理的。
学习目标:
- 图形渲染管线基础知识;
- 图形渲染管线的工作流程;
图形渲染管线基础知识
在OpenGL中,任何事物都在3D空间中,而屏幕和窗口等都是2D像素组,所以需要进行转换。
-
概念:
- 一堆原始图形数据途经
一个输送管道
,期间经过各种变化处理 最终出现在屏幕的过程. - (图形渲染管线接受一组3D坐标,然后把它们转变为你屏幕上的有色2D像素输出。)
- 一堆原始图形数据途经
-
图形渲染管线主要有两方面工作:
- 把3D坐标转换为2D坐标;
- 把2D坐标转变为实际的有颜色的像素;
图形渲染管线的工作流程
- 图形渲染管线的主要流程分为
6
大步骤:- 顶点输入
- 顶点着色器
- 编译着色器
- 片段着色器
- 链接顶点属性
- 索引缓冲对象
接下来我们一起一一学习里面具体的步骤,并且了解每一步骤主要职能。
- 顶点输入
-
定义
顶点数据 (vertext data)
(3D坐标),将顶点数据坐标进行标准化设备坐标(有效范围内 --OpenGL的可见区域)
;- 标准化设备坐标(Normalized Device Coordnates,NDC)
- 任何坐落在范围外的坐标都会被丢弃/裁剪,不会显示在屏幕上。
- 标准化设备坐标接着会变换为屏幕空间坐标(Screen -space Coordinates)-- [通过glViewport函数提供的数据,进行视口变换(viewport transform)完成的]
- 标准化设备坐标(Normalized Device Coordnates,NDC)
-
将
顶点数据
作为输入发送给图形渲染管线的第一个处理阶段:顶点着色器。 -
把顶点数据 存储在显卡内存中,使用VBO(顶点缓冲对象)管理。
- 使用顶点缓冲对象管理内存的原因是一次性可以发送大量数据到显卡上。
- 顶点缓冲对象(vertex buffer objects,VBO)管理内存-- 在GPU中存储大量的顶点数据。
-
顶点缓冲对象的创建步骤:
- 创建VBO对象;glGenBuffer()
- 将VBO对象绑定到顶点缓冲对象中; glBindBuffer()
- 将用户输入的顶点数据复制到缓冲内存中; glBufferData()
- 要点:
-
OpenGL有很多缓冲对象类型,其中顶点缓冲对象类型是GL_ARRAY_BUFFER
-
glBufferData函数--把顶点数据(用户定义的数据) 复制到 缓冲的内存 中。
-
glBufferData:第四个参数,指名显卡如何管理给定的数据:
- GL_STATIC_DRAW:数据不会或者几乎不变;
- GL_DYNAMIC_DRAW:数据会被改变多次;
- GL_STREAM_DRAW:数据每次绘制时都会改变;
// 创建vbo对象 unsigned int VBO;//VBO对象id glGenBuffer(1,&VBO); //把新创建的缓冲 绑定到GL_ARRAY_BUFFER目标上 //GL_ARRAY_BUFFER--顶点缓冲对象的缓冲类型 glBindBuffer(GL_ARRAY_BUFFER,VBO); //配置 当前绑定的缓冲(VBO) --调用glBufferData函数 glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW)
-
- 顶点着色器
-
在现代OpenGL中至少需要设置一个顶点和一个片段着色器。
-
使用GLSL(OpenGL Shading Language)编写顶点着色器,然后编译这个着色器,最后在程序中使用。
-
- 创建顶点着色器
```c
#version 330 core
layout (location=0) in vec 3 aPos;
void main(){
gl_Position=vec4(aPos.x,aPos.y,aPos.z,1.0)
}
```
1. 着色器版本 OpenGL 3.3以及更高版本,使用核心模式。
2. in关键字 --代表输入顶点属性(Input Vertex Attribute),数据位置location ( layout (location=0) ),使用vec3 三维浮点向量。
3. 设置顶点着色器的输出;
- 编译着色器
```js
const char *vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "void main()\n" "{\n" " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" "}\0";
```
为了使用OpenGL使用它,必须在 运行时动态编译它的源代码。
- 编译步骤:
1. 创建着色器对象,使用ID来引用;
-- glCreateShader(GL_VERTEX_SHADER);
2. 把着色器源码 附加到这个着色器对象中;
-- glShadderSource();
3. 编译着色器
-- glCompileShader(vertexShader);
4. 检测编译状态 -- glGetShaderiv()
```c
unsigned int vertexShader;
vertexShader=glClreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader,1,&vertexShader,NULL);
glCompileShader(vertexShader);
//检测编译着色器状态 --是否编译成功
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
//如果编译失败
if(!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
```
- 片段着色器(Fragment Shader)
- 计算像素最后的颜色输出。
- 在计算机图形中颜色被表示为有4个元素的数组:红色、绿色、蓝色和alpha(透明度)分量,通常缩写为RGBA。当在OpenGL或GLSL中定义一个颜色的时候,我们把颜色每个分量的强度设置在0.0到1.0之间
- 三种颜色分量的不同调配可以生成超过1600万种不同的颜色!
- 创建片段着色器源码
#version 330 core out vec4 FragColor; void main() { FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); }
- 编译片段着色器
unsigned int fragmentShader; fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader);
图形学基础目录
- OpenGL -- 入门笔记 (juejin.cn)
- OpenGL入门基础(二)--图形渲染管线
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!