openGL学习笔记:着色器的理解,以及geometry shader的用法

在跟着learnopengl的教程(https://learnopengl.com/Advanced-OpenGL/Geometry-Shader)学习几何着色器(geometry shader)的时候,遇到了一些理解问题,现在解决了,记录一下。

当然中文我也不知道叫啥,但愿差不多吧(希望不要差太多ha)。

在我今天学到进度里,关于着色器的学习有三种,vertex shader, fragment shader, geometry shader,着色器的作用是write data to the GPU card。而这三种着色器的作用又有不同。

1 vertex shader

主要负责to process the primitive vertices里的数据,比如顶点,法线,颜色,深度等信息。因为处理的是原始数据,所以在这里可以做一些变量的声明,比如in, out, sampler2D, uniform,samplerCube, 诸如纹理,也只是坐标和像素组成的,这在纹理坐标texture coordinate中更加直白(纹理的左下角坐标是(0,0),右上角坐标是(1,1), 当使用(0.5,0.5)时,表示一张图片左下1/4的大小)。

2 fragment shader

主要负责to output the color,我理解是每个fragment program每次在screen space里绘图时,只绘制一个像素(所以我一直觉得叫像素处理器之类的,更直白)。 在这里,你可以通过设置模板值等方式,决定是否让fragment shader绘制这个像素。

3 geometry shader

介于前两者中间的,用来处理vertex,colord等信息的中间着色器。开始我一直没理解,后来发现每次在用EndPrimitive()后,传递给 fragment shader的数据是单一的,或者说,处理的时候只处理一个primitive vertex and color(当然,我想内部应该是统一处理统一发送,毕竟是类似数组的结构)。

三者的三角恋关系

也就是工作流程啦。首先是vertex shader的数据被内存中数据绑定和初始化,这个过程涉及绑定和初始化的函数,比如glGen_,glBind_或者glEnable开头的一系列函数,glBindBuffer(), glBindVertexPointer(),glEnableVertexArray()等, 大概的一些套路是,

1 先设置一个复杂点的数组(也许很长),

2 给数组填充各种数据,

3 把数组输入到vertex shader(比如shader用in关键字标识这是从内存输入的,location相当于索引的起始下标) 

#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;

4 vertex shader舔完后给geometry shader舔,

5 geometry shader舔完了交给fragment shader舔,最后丢到屏幕给我们看到。

 

geometry shader之所以叫做第三者,是因为没有它也能做事。但是有了他,事情做的会更刺激...比如从vertex shader输入一个顶点一个颜色,geometry shader能给你生出好多个再交给fragment shader让我们看到(所以这是他迷人的地方吗?)

下面用教程中的vertex shader 和 geometry shader代码分析一下。

首先,从内存(你的代码里)传入四个vertex和color的数组

    float points[] = {
        -0.5f,  0.5f, 1.0f, 0.0f, 0.0f, // top-left
         0.5f,  0.5f, 0.0f, 1.0f, 0.0f, // top-right
         0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // bottom-right
        -0.5f, -0.5f, 1.0f, 1.0f, 0.0f  // bottom-left
    };

第一个收到礼物的是vertex shader,这个小v很懒,他收到礼物拆几乎动都没动,直接丢给了geometry shader兄弟,也不能说没动,他把每一个(0.5,0.5)这样的二维坐标转换成了vec4类型的空间坐标。如下:

gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); 

并且用out  VS_OUT{}结构告诉geometry shader,这是我给你的 ( 你得记知恩图报!)

#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;

out VS_OUT {
    vec3 color;
} vs_out;

void main()
{
    vs_out.color = aColor;
    gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); 
}

geometry shader收到之后呢,知道了这颜色是你给的,为啥呢,有证据啊,名字一样,都叫color,而且上面还标记着in,你给的

in VS_OUT {
    vec3 color;
} gs_in[];

甚至给的是啥都写的明明白白(用points和in告诉geometry shader我啊给了你几个点):

layout (points) in;

geometry shader兄弟很开心啊,收到礼物后迫不及待拆开,发现就只有一个点,可是他还要把这个礼物送给fragment  shader姐姐,一个点也太寒酸了,于是他动手把一个点变成了五个点,并且还给每个点上了不同的颜色。

首先,他在main()里处理从vertex shader给的数据, 用一个build_house()函数

build_house(gl_in[0].gl_Position);//处理每个vertex以及对应的color

在build_house()里呢,他把每个vertex array attribute里的元素(包含一个vertex,一个color)都处理了,不过每次他只能处理一个: 他把一个变成了两个,而且还改变了颜色

    fColor = gs_in[0].color; //保留原来的颜色
    gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0); //把点向左偏移,并且发送这个处理过的点给fragment shader姐姐,她从gl_Position接收
    EmitVertex(); //处理完通知姐姐
    gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0); //把点向右偏移
    fColor = vec3(1.0, 1.0, 1.0);//生成第二个点时,把颜色改成白色
    EmitVertex();//处理完通知姐姐
    EndPrimitive();//全部搞定得说一声

为了让fragment shader姐姐知道这是他改的颜色,他也学vertex shader弟弟,用out表示这是他送的...讨她的欢心

...
out vec3 fColor;
...
build_house(){...}
main(){...}

最后他改成了这个样子:

#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 5) out;

in VS_OUT {
    vec3 color;
} gs_in[];

out vec3 fColor;

void build_house(vec4 position)
{    
    fColor = gs_in[0].color; // gs_in[0] since there's only one input vertex
    gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0); // 1:bottom-left  
    EmitVertex();   
    gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0); // 2:bottom-right
    EmitVertex();
    gl_Position = position + vec4(-0.2,  0.2, 0.0, 0.0); // 3:top-left
	fColor = vec3(0.0, 0.0, 0.0);
    EmitVertex();
    gl_Position = position + vec4( 0.2,  0.2, 0.0, 0.0); // 4:top-right
	fColor = vec3(0.0, 1.0, 1.0);
    EmitVertex();	
    gl_Position = position + vec4( 0.0,  0.4, 0.0, 0.0); // 5:top
    fColor = vec3(1.0, 1.0, 1.0);
    EmitVertex();
    EndPrimitive();
}

void main() {    
    build_house(gl_in[0].gl_Position);
}

而fragment shader姐姐呢,坐在沙发里喝着酒,门上贴了个out,告诉别人她在等着...也许是hanging out~的out

最后等来了geometry shader弟弟的color, 然后甩手就丢到了屏幕(screen space)

#version 330 core
out vec4 FragColor;

in vec3 fColor;

void main()
{
    FragColor = vec4(fColor, 1.0);   
}

最后是这样的

 

 

 

 

 

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值