OpenGl L21几何着色器

一、几何着色器

输入:一个图元的一组顶点
输出:变换后新的图元的一组顶点
如下:

#version 330 core
layout (points) in;
layout (line_strip, max_vertices = 2) out;  //设置输出的最大顶点数为2

void main() {    
    gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0); 
    EmitVertex();

    gl_Position = gl_in[0].gl_Position + vec4( 0.1, 0.0, 0.0, 0.0);
    EmitVertex();

    EndPrimitive();
}

在几何着色器的顶部,我们使用in关键字声明一个布局修饰符,修饰几何着色器输入的图元类型。

  • points:绘制GL_POINTS图元时
  • lines:绘制GL_LINES或GL_LINE_STRIP时
  • lines_adjacency:GL_LINES_ADJACENCY或GL_LINE_STRIP_ADJACENCY
  • triangles:GL_TRIANGLES、GL_TRIANGLE_STRIP或GL_TRIANGLE_FAN
  • triangles_adjacency:GL_TRIANGLES_ADJACENCY或GL_TRIANGLE_STRIP_ADJACENCY
    同样,我们也可以使用out关键字声明几何着色器的输出图元类型。
  • points
  • line_strip
  • triangle_strip

同样的,当数据很多的时候我们可以定义一个接口块。

in gl_Vertex
{
    vec4  gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];
} gl_in[];

然后,有了顶点着色器阶段的顶点数据后,我们可以使用2个几何着色器中的函数EmitVertexEndPrimitive来生成新的数据。如下,我们生成一个线条图元。

void main() {
    gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0); 
    EmitVertex();

    gl_Position = gl_in[0].gl_Position + vec4( 0.1, 0.0, 0.0, 0.0);
    EmitVertex();

    EndPrimitive();
}

调用EmitVertex,将gl_Position中的向量添加到图元中。
当调用EndPrimitive时,所有输入的顶点会被合成为指定的输出渲染图元。当一个或多个EmitVertex之后重复调用EndPrimitive时,这两个顶点会合成为多个包含两个顶点的线条。
在这里插入图片描述

二、使用几何着色器

  1. 定义顶点坐标
float points[] = {
    -0.5f,  0.5f, // 左上
     0.5f,  0.5f, // 右上
     0.5f, -0.5f, // 右下
    -0.5f, -0.5f  // 左下
};
  1. 配置顶点着色器和片段着色器
//顶点
#version 330 core
layout (location = 0) in vec2 aPos;

void main()
{
    gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); 
}
//片段
#version 330 core
out vec4 FragColor;

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

这时直接绘制的话,会得到黑暗场景中的四个点。

shader.use();
glBindVertexArray(VAO);
glDrawArrays(GL_POINTS, 0, 4);

在这里插入图片描述

  1. 配置几何着色器,接受一个点图元,直接传递到下一个着色器
//几何
#version 330 core
layout (points) in;
layout (points, max_vertices = 1) out;

void main() {    
    gl_Position = gl_in[0].gl_Position; 
    EmitVertex();
    EndPrimitive();
}

编译和链接着色器源码

geometryShader = glCreateShader(GL_GEOMETRY_SHADER);  //几何着色器类型
glShaderSource(geometryShader, 1, &gShaderCode, NULL);
glCompileShader(geometryShader);  
...
glAttachShader(program, geometryShader);
glLinkProgram(program);

然而现在效果还是没变,所以我们需要再进行一些处理。

三、造几个房子

OpenGL中,三角形带(Triangle Strip)是绘制三角形更高效的方式,它使用顶点更少。在第一个三角形绘制完之后,每个后续顶点将会在上一个三角形边上生成另一个三角形:每3个临近的顶点将会形成一个三角形。如下:
在这里插入图片描述
代码如下:

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

void build_house(vec4 position)
{    
    gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0);    // 1:左下
    EmitVertex();   
    gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0);    // 2:右下
    EmitVertex();
    gl_Position = position + vec4(-0.2,  0.2, 0.0, 0.0);    // 3:左上
    EmitVertex();
    gl_Position = position + vec4( 0.2,  0.2, 0.0, 0.0);    // 4:右上
    EmitVertex();
    gl_Position = position + vec4( 0.0,  0.4, 0.0, 0.0);    // 5:顶部
    EmitVertex();
    EndPrimitive();
}

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

在这里插入图片描述

四、爆破物体

像这种效果:
在这里插入图片描述
实现的原理是将每一个三角形沿着法线方向移动一小段距离。

  1. 获取法向量
    利用平行三角的两个不平行的向量a和b,再利用叉乘就可以获取法向量了。
vec3 GetNormal()
{
   vec3 a = vec3(gl_in[0].gl_Position) - vec3(gl_in[1].gl_Position);
   vec3 b = vec3(gl_in[2].gl_Position) - vec3(gl_in[1].gl_Position);
   return normalize(cross(a, b));
}
  1. 设置偏移函数
vec4 explode(vec4 position, vec3 normal)
{
    float magnitude = 2.0;
    vec3 direction = normal * ((sin(time) + 1.0) / 2.0) * magnitude; 
    return position + vec4(direction, 0.0);
}

完整的代码如下:

#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

in VS_OUT {
    vec2 texCoords;
} gs_in[];

out vec2 TexCoords; 

uniform float time;

vec4 explode(vec4 position, vec3 normal) { ... }

vec3 GetNormal() { ... }

void main() {    
    vec3 normal = GetNormal();

    gl_Position = explode(gl_in[0].gl_Position, normal);
    TexCoords = gs_in[0].texCoords;
    EmitVertex();
    gl_Position = explode(gl_in[1].gl_Position, normal);
    TexCoords = gs_in[1].texCoords;
    EmitVertex();
    gl_Position = explode(gl_in[2].gl_Position, normal);
    TexCoords = gs_in[2].texCoords;
    EmitVertex();
    EndPrimitive();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值