您当前的位置: 首页 >  ar

Jave.Lin

暂无认证

  • 3浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

LearnGL - 02.1 - DrawTriangle_Extension - VBO/Shader

Jave.Lin 发布时间:2020-06-07 00:10:17 ,浏览量:3

文章目录
  • 什么是 shader ?
  • 给顶点添加颜色(attribute, varying)
    • 添加顶点数据
    • 着色器也添加对应的顶点属性(添加 VS:attribute,varying,FS:varying)
    • 在应用程序设置顶点颜色的属性(设置:VS:attribute)
    • 绘制效果
  • 让三角型旋转起来(使用:uniform)
    • 在顶点着色器添加 uniform 的矩阵
      • 先获取 uniform 变量的 location
    • 再根据 location 设置 uniform 变量
    • 运行效果
    • 换y轴来旋转
      • 查看面向剔除
      • 设置面向剔除
  • 注意
  • 完整源码
  • References
LearnGL - 学习笔记目录

本人才疏学浅,如有什么错误,望不吝指出。

上一篇:LearnGL - 02 - DrawTriangle,学会了如何画一个最最基本的三角形。

这一篇:我将在上一篇简单的例子的基本上添加一些功能,便于学习 shader。

什么是 shader ?

shader 直译是:着色器。

shader 是用 GLSL 编写的(OpenGL Shading Language,的简写, 意思是 OpenGL 着色器语言 )

GLSL 是一种 CLike 语言,所以与 C语言非常类似。

在 OpenGL 中,我们用 GLSL 编写的 shader 编译好后,都会链接到一个 Program(程序)对象中,OpenGL 调用该程序对象中链接到的 shader 来处理对应阶段的逻辑。

Program(程序)对象的 Shader 对应有几个阶段:

  • Vertex Shader(顶点着色器)
  • Tessellation Control Shader(细分控制着色器)
  • Tessellation Evaluation Shader(细分计算着色器)
  • Geometry Shader(几何着色器)
  • Fragment Shader(片段/片元着色器)

其中顶点、片元着色器是必须的,其他都是可选的。

之前的文章 LearnGL - 01.1 - OpenGL 概述 & 管线概述 中我也有列出对应 OpenGL 的简述渲染管线图解,这里再引用一下: 在这里插入图片描述 由上面图解所示,箭头流向也就是阶段执行的顺序。

每个阶段的输入,就是上个阶段的输出。

这也是目前着色器中唯一能在着色器之间单向通讯的规则。

另外,着色器的 编译、链接 在之前的文章也有简述 LearnGL - 02 - DrawTriangle - VBO,这里不在说明。

下面使用 shader 来给之前的三角形的每个顶点添加一些不同的颜色,首先是在应用程序层添加顶点的颜色数据。

给顶点添加颜色(attribute, varying) 添加顶点数据

我们原来的顶点数据是:

float vertices[] = {
	// x,	y,	  z
	-0.5f, -0.5f, 0.0f,
	 0.5f, -0.5f, 0.0f,
	 0.0f,  0.5f, 0.0f,
};

现在需要添加颜色,而在GLSL中颜色值最终的输出都是0.0~1.0范围的,都是float浮点型,所以我们在此基础上有添加了3个颜色分量,RGB

float vertices[] = {
	// x,	y,	  z			r,	  g,	b
	-0.5f, -0.5f, 0.0f,		1.0f, 0.0f, 0.0f,
	 0.5f, -0.5f, 0.0f,		0.0f, 1.0f, 0.0f,
	 0.0f,  0.5f, 0.0f,		0.0f, 0.0f, 1.0f,
};
着色器也添加对应的顶点属性(添加 VS:attribute,varying,FS:varying)

下面是原本的两着色器:顶点、片元着色器

前面有说着色器的输入,就是上一个阶段的输出。反过来讲:着色器的输出,就是下个阶段的输入。

但有一些另外,就是着色器阶段中的 头部 着色器,与 尾部 着色器。

  • 头部 着色器就是我们的:顶点着色器 vertex shader,它的上个着色器阶段是不存在的,对它输入数据的就是应用程序层,在这里就是我们在 C++ 写的代码来设置 vertex shader 的 vertex attribute(顶点属性)的部分,就是应用层对顶点着色器的数据输入。
  • 尾部 着色器就是我们的:片元/片段着色器 fragment shader,它的下个着色器阶段是不存在的,它的输出数据是可以指向 帧缓存目标写入数据的(输出数据)。

在这里我们使用的是 attributevarying 关键字。也可以使用 inout 关键字。

  • 在 顶点着色器中
    • attribute 是专门给顶点着色器 定义 输入数据的变量用的。
    • varying 是顶点着色器输出给片元着色器用的(或是存在下一个可选着色器阶段的话,会先传给下个阶段)。而 在顶点着色器的 varying 变量有个特定,它在会在光栅化阶段对其他生成的片元中,对该 varying 变量进行顶点之间的插值得来的。
  • 在 片元着色器中
    • 不使用 attribute 关键字定义变量,否则会报错。因为 attribute 只能在顶点着色器中使用。
    • varying 是上个着色器阶段传入的片元。一般都会经过顶点之间的插值得到的。

在下面我们对原来的顶点、片元着色器添加了对应的输入、输出变量。

static const char* vertex_shader_text =
"#version 450 compatibility\n"
"attribute vec3 vPos;\n"
"void main() {\n"
"    gl_Position = vec4(vPos, 1.0);\n"
"}\n";

static const char* fragment_shader_text =
"#version 450 compatibility\n"
"void main() {\n"
"    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";

下面因为需要填加颜色的顶点的颜色输出,需要增加3个float分量的attribute、还有varying属性:

static const char* vertex_shader_text =
"#version 450 compatibility\n"
"attribute vec3 vPos;\n"
"attribute vec3 vCol;\n"
"varying vec3 fCol;\n"
"void main() {\n"
"   gl_Position = vec4(vPos, 1.0);\n"
"	fCol = vCol;\n"
"}\n";

static const char* fragment_shader_text =
"#version 450 compatibility\n"
"varying vec3 fCol;\n"
"void main() {\n"
"   gl_FragColor = vec4(fCol, 1.0);\n"
"}\n";

这里再次强调说明一下,顶点着色器添加了:attribute vec3 vPos; varying vec3 fCol; 两个属性,前者是attribute的,用于顶点着色器输入的,后者varying用于顶点传递到片元着色器用的属性,外部不需要设置,我们只要在顶点的main函数里对varying赋值就好,这样片元着色器中的 varying 变量会得到顶点之间的插值数据,只要顶点着色器的varying的变量名称 与 片元着色器中的varying的变量名称对应上就可以传递了,否则会有着色器程序的链接错误。

如果我给片元着色器中的 varying vec3 fCol; 改为 varying vec3 fColAAA; ,后者多加了 AAA 三个字符的变量名。 运行的话就会得到着色器程序链接的错误提示(还记得我们上一篇有讲得如何输出错误把?)

修改了变量名后的片元着色器

static const char* fragment_shader_text =
"#version 450 compatibility\n"
"varying vec3 fColAAA;\n"
"void main() {\n"
"   gl_FragColor = vec4(fColAAA, 1.0);\n"
"}\n";

运行后的报错: 在这里插入图片描述

  • Program Linking 的错误
  • fColAAA 有错误相关的变量名
  • previous 前一个shader,即fColAAA的前一个shader,在这里就是vertex shader顶点着色器
  • not write 就是说前面的vertex shader没有对fColAAA写入数据
在应用程序设置顶点颜色的属性(设置:VS:attribute)
GLint vcol_location;
...
vpos_location = glGetAttribLocation(program, "vPos");		// 获取 顶点着色器中的顶点 attribute 属性的 location
vcol_location = glGetAttribLocation(program, "vCol");		// 获取 顶点着色器中的顶点 attribute 属性的 location

glVertexAttribPointer(vpos_location, 3, GL_FLOAT, GL_FALSE, // 设置 顶点属性 vPos 格式
	sizeof(float) * 6, (void*)0);
glEnableVertexAttribArray(vpos_location);					// 启用 顶点缓存 location 位置的属性

glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE, // 设置 顶点属性 vCol 格式
	sizeof(float) * 6, (void*)(sizeof(float) * 3));
glEnableVertexAttribArray(vcol_location);					// 启用 顶点缓存 location 位置的属性

注意 glVertexAttribPointer 函数调用时:

  • 第一个参数 设置对应的 location 索引值 vpos_locaiton 的不变,vcol_location 的也是通过 glGetAttribLocation 来获取即可。
  • 第二个参数 还是填入 3 即可,因为颜色也是RGB三个分量。
  • 第三个参数 和 第四个参数 都不变
  • 第五个参数 原始是 sizeof(float) * 3 的,现在因为每个顶点属性都添加了一个三个分量的RGB,所以6 个 float 的字节大小。改为: sizeof(float) * 6就可以了。
  • 第六个参数 主要是设置 vcol_location 的需要该为 (void*)(sizeof(float)*3),因为从偏移3个float的字节数开始,因为前面3个float的字节数据都是 vPos 用的。

这时 顶点属性(Vertex Attribute) 有两个,对应到着色器中就是:一个是:vPos,另一个是 vCol

另外 顶点属性的数量也是有限的,可以通过以下 API 查看你的 OpenGL 环境支持多少个:

int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout             
关注
打赏
1664331872
查看更多评论
0.0558s