【OpenGL】着色器 Shader

写在前面

前面的几个例子使用的都是固定管线,又叫立即渲染模式,这个模式下 opengl 把渲染的细节封装隐藏起来,开发人员使用起来非常容易,但效率比较低且不够灵活。现代 opengl 使用的大多是可编程管线,又叫核心模式,从 opengl3.2 开始,固定管线就已经被废弃了,所以学习现代 opengl 就必须学可编程管线。虽然可编程管线上手比较难,但它能让我们操控 opengl 的底层,更有利于学习计算机图形学。

使用可编程管线需要用到“着色器”,也就是大名鼎鼎的 shader。着色器是运行在 GPU 中的,opengl 提供了一门着色器语言 GLSL,即 opengl shader language,还提供了相应的编译器,shader 程序必须编译后才能在 GPU 上运行。

shader

首先看看图形渲染管线的流程

image

GPU 接受一级顶点数据,经过一系列过程之后生成屏幕上显示的像素。管线包括下面几个过程

  • 顶点着色器(Vertex Shader):它接收单一的顶点作为输入,然后把 3D 坐标转换成另一个 3D 坐标,主要做变换操作;顶点着色器允许我们对顶点属性做一些基本处理。

  • 图元装配(Primitive Assembly):它接收顶点着色器输出的顶点作为输入,然后把顶点装配成指定的图元形状,如果是 GL_POINTS 是装配成点,如果是 GL_TRIANGLES,则装配成三角形。

  • 几何着色器(Geometry Shader):它接收图元装配生成的图元的一系列顶点作为输入,通过产生新顶点构造出新的图元形状。

  • 光栅化阶段(Rasterization Stage):它接收几何着色器生成的图元,将图元映射为屏幕上显示的像素,生成供下个阶段使用的片段(Fragment);在这个阶段会对片段进行裁切,把屏幕之外的片段丢弃掉。

  • 片段着色器(Fragment Shader):它接收光栅化之后的片段数据,一个片段就是一个像素所需的所有数据;片段着色器计算一个片段(像素)的最终颜色,通常片段着色器包含 3D 场景的数据(如光照、阴影、光的颜色等),这些因素会影响像素最终的颜色。

  • Alpha 测试和混合(Blending)阶段:它检测片段的深度值,以确定该像素是在其它物体前面还是后面;还会检查 alpha 值并进行混合(blend),所以片段着色器处理过的颜色还不是最终的颜色,alpha 测试和混合也会影响颜色。

可以看到一个管线要经过上面六个过程,其最终目的是确定屏幕上绘制的像素点及其颜色,其中从顶点着色器到光栅化是根据顶点数据生成屏幕上的像素;片段着色器和混合是确定像素的最终颜色。这六个阶段使用到了三个着色器,这三个着色器是我们可以自定义的,其中顶点着色器和片段着色器是最重要的,也是我们必须自定义的,因为 GPU 中并没有默认的顶点着色器和片段着色器(这是针对可编程管线的,固定管线则不用我们自己定义任何着色器)。

前面介绍了固定管线是如何在屏幕上绘制图元的,现在知道了可编程管线的过程和 shader,我们再看看可编程管线如何一步步绘制图元。

输入顶点数据

无论是绘制一个点还是一个三角形,或是更复杂的模型,都需要先传入顶点数据(再复杂的模型也是由一个个顶点组成的)。顶点的一个最重要属性就是位置,位置在 opengl 中以 3D 坐标表示,所以一个顶点需要三个浮点数,表示它的位置。如果有多个顶点,可以以多维数组的方式来组织数据

GLfloat vertices[][3] = {
    { -0.5f, -0.5f, 0.0f },
    { 0.5f, -0.5f, 0.0f },
    { 0.0f,  0.5f, 0.0f }
};

也可以以一维数组的方式来组织数据

GLfloat vertices[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f
};
标准化坐标

顶点位置经过顶点着色器处理之后,其坐标应该是标准化设备坐标,否则该顶点不会进行绘制;标准化坐标指 x,y,z 值都在范围 -1.0~1.0 之间,超出这个范围的顶点将被丢弃(这一步在光栅化的时候处理)。

image

这些顶点数据将会传给顶点着色器,它将在 GPU 中创建内存(显存)来存储这些顶点数据,通常是经过顶点缓冲对象(VBO)来管理顶点。使用顶点缓冲对象的好处是可以一次性发送大批顶点数据到显卡,数据从 CPU 发送 GPU 速度是很慢的。

回顾 VBO

前面已经介绍过 VBO 的使用了,这里再复习一下。首先要创建顶点缓冲对象,创建的方法是给对象一个名字

GLuint VBO;
glGenBuffers(1, &VBO);

然后将对象绑定到 context,绑定的目标是 GL_ARRAY_BUFFER,绑定之后针对 GL_ARRARY_BUFFER 的操作都将作用于这个 VBO 上,直到我们绑定新的对象或者将这个 VBO 解绑。然后我们要把顶点数据复制到缓冲内存中,此时在 GL_ARRAY_BUFFER 上的缓冲调用都是配置当前绑定的 VBO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值