几何图元
glDrawArrays(GLenum mode, GLint first, GLsizei count);
和 glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
是用于会渲染绘制图形的。
其参数 mode 表示几何图元的描述类型,常见的类型如下:
GL_POINTS
:单个顶点集;为 n
个顶点的每一个都绘制一个点;示意图如下:
GL_LINES
:多组双顶点线段;两个顶点解释为一条直线,直线之间并不连接(如果奇数个顶点,最后一个将忽略);示意图如下:
GL_LINE_LOOP
:闭合折线;从 v1
到 vN
一系列的直线且构成环;示意图如下
GL_LINE_STRIP
:不闭合折线; 从 v1
到 vN
一系列的直线;示意图如下:
GL_TRAINGLES
:多组独立填充三角形;一系列的三角形(3
的倍数个顶点,多余的将忽略);示意图如下:
GL_TRAINGLE_STRIP
:线型连续填充三角形串; (v1,v2,v3)
,(v2,v3,v4)
,依次类推(所有的三角形是按相同方向绘制);示意图如下:
GL_TRAINGLE_FAN
:扇形连续填充三角形串;(v1,v2,v3)
,(v1,v3,v4)
,以此类推(一直是以v1
开始);示意图如下:
几何着色器
几何着色器(Geometry Shader):位于顶点和片段着色器之间的一个 (可选的) 着色器,其输入是一个图元(如点或三角形)的一组顶点;可以在顶点发送到下一着色器阶段之前对它们随意变换。
一个简单的几何着色器例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #version 330 core /* 指定 GLSL 版本3.3,匹配 OpenGL 版本 */
layout (points) in;
layout (line_strip, max_vertices = 2) out;
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(); }
|
几何着色器“输入”的图元类型:
points
:绘制 GL_POINTS
图元时(最小顶点数:1)。
lines
:绘制 GL_LINES
或 GL_LINE_STRIP
时(最小顶点数:2)。
lines_adjacency
:绘制 GL_LINES_ADJACENCY
或 GL_LINE_STRIP_ADJACENCY
时(最小顶点数:4)。
triangles
:绘制 GL_TRIANGLES
、GL_TRIANGLE_STRIP
或 GL_TRIANGLE_FAN
时(最小顶点数:3)。
triangles_adjacency
:绘制 GL_TRIANGLES_ADJACENCY
或 GL_TRIANGLE_STRIP_ADJACENCY
时(最小顶点数:6)。
几何着色器“输出”的图元类型:
- **
points
**。
- **
line_strip
**。
- **
triangle_strip
**。
爆破物体
爆破(Explode)物体:是指将每个三角形图元沿着法向量的方向移动一小段距离(效果就是,整个物体看起来像是沿着每个三角形的法线向量爆炸一样)。
几何着色器大致如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #version 330 core /* 指定 GLSL 版本3.3,匹配 OpenGL 版本 */
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
in VS_OUT { vec2 texCoords; } gs_in[];
out vec2 TexCoords;
uniform float timeValue;
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)); }
vec4 explode(vec4 position, vec3 normal) { float magnitude = 0.5; vec3 direction = normal * ((sin(timeValue) + 1.0) / 2.0) * magnitude; return position + vec4(direction, 0.0); }
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(); }
|
法向量可视化
在写光照着色器的时候,有可能会得到一些奇怪的视觉输出,其原因有可能是法向量错误导致的;法向量错误可能是由于不正确加载顶点数据、错误地将其定义为顶点属性或在着色器中不正确地管理所导致的。
然而有一种很好用的方式可以检测法向量是否正确,那就是 法向量可视化;其实现思路如下:
- 首先不使用几何着色器正常绘制场景;
- 然后只显示通过几何着色器生成的法向量来绘制场景;
几何着色器大致如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #version 330 core /* 指定GLSL版本3.3,匹配 OpenGL 版本 */
layout (triangles) in;
layout (line_strip, max_vertices = 6) out;
in VS_OUT { vec3 normal; } gs_in[];
const float magnitude = 0.1;
void GenerateNormal(int index) { gl_Position = gl_in[index].gl_Position; EmitVertex(); gl_Position = gl_in[index].gl_Position + vec4(gs_in[index].normal, 0.0) * magnitude ; EmitVertex(); EndPrimitive(); }
void main() { for (int index = 0; index < 3; index++) { GenerateNormal(index); } }
|
参考
教程来源:https://learnopengl.com/。