几何着色器的作用
输入
输入类型
从顶点着色器接收下列任何一个图元值:
类型 | 数组大小 |
---|---|
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 |
补充:lines_adjacency 图元装配的时候每次总是4个顶点的数量a,b,c,d。实际上真正绘制的点是b和c,其他的点是提供邻接关系的点。
triangles_adjacency作为图元输入时,每个图元由6个顶点组成,opengl可以通过绘制命令传入GL_TRIANGLES_ADJACENCY, GL_TRIANGLES_STRIP_ADJACENCY来控制,为了说明怎么工作的盗两张图
作者:纳尼情况zhuzhu
链接:https://www.jianshu.com/p/8bca19bc5ade
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
具体怎么样,以后再补充QwQ。
输入布局修饰符
这需要在in关键字前声明一个布局修饰符(Layout Qualifier)
layout (points) in;
point表示输入的类型为顶点。
输出
输出类型
然后输出下面的图元类型。
- points ——————————点
- line_strip ————————–线
- triangle_strip———————-三角形
输出布局修饰符
几何着色器同时希望我们设置一个它最大能够输出的顶点数量(如果你超过了这个值,OpenGL将不会绘制多出的顶点),这个也可以在out关键字的布局修饰符中设置。
layout (line_strip, max_vertices = 2) out;
表示输出为line strip(线条),最大顶点数为2(即只有一条线段)。
作用
它接受一个图元(例如point,line)作为输入,以这个点/线为初始数据,创建较为复杂的图元。
几何着色器的构建
输入布局
layout (points) in;
输入数据块
GeometryShader
在GeometryShader中接收输入块,该块是一个数组,接收所有在vertexShader中输出的VS_OUT块。
in VS_OUT {
vec3 color;
} gs_in[];
color可以为数组,为几何着色器提供图元不同顶点的颜色输出。
vertexShader
在vertexShader有
out VS_OUT {
vec3 color;
} vs_out;
vs_out.color = aColor;
内建变量
即不会写出来,但存在这样的变量。
in gl_Vertex
{
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
} gl_in[];
这里可以看出,几何着色器的输入是一个图元的所有顶点。
修改原数据,并添加到输出的顶点集中
gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0);
fColor = gs_in[0].color;//
EmitVertex();//提交该顶点到图元
此处使用第一个顶点的位置确定了当前顶点的位置,以及使用自定义接口块确定了当前顶点的颜色,并将这个顶点提交到图元。
注意:gl_in[i].gl_Position
为顶点着色器输出几何着色器的第i个顶点的位置
gl_Position
为EmitVertex()
提交到图元的顶点。
提交输出集
EndPrimitive();
将当前存储的图元提交到fragment片元着色器中,一个图元的最大顶点数在输出布局修饰符中指定。
输出布局
layout (triangle_strip, max_vertices = 5) out;
几何着色器的使用
创建着色器程序
Shader shader("9.1.geometry_shader.vs", "9.1.geometry_shader.fs", "9.1.geometry_shader.gs");
这显然用之前着色器类的构造函数是不行的。
LearnOpenGL网站代码方法
Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::string geometryCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
gShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
try
{
// open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
// if geometry shader path is present, also load a geometry shader
if(geometryPath != nullptr)
{
gShaderFile.open(geometryPath);
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometryCode = gShaderStream.str();
}
}
catch (std::ifstream::failure& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char * fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader
unsigned int geometry;
if(geometryPath != nullptr)
{
const char * gShaderCode = geometryCode.c_str();
geometry = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(geometry, 1, &gShaderCode, NULL);
glCompileShader(geometry);
checkCompileErrors(geometry, "GEOMETRY");
}
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
if(geometryPath != nullptr)
glAttachShader(ID, geometry);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
if(geometryPath != nullptr)
glDeleteShader(geometry);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(GLuint shader, std::string type)
{
GLint success;
GLchar infoLog[1024];
if(type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\\n" << infoLog << "\\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if(!success)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\\n" << infoLog << "\\n -- --------------------------------------------------- -- " << std::endl;
}
}
}
};
传入数据
与之前一样
float points[] = {
-0.5f, 0.5f, // 左上
0.5f, 0.5f, // 右上
0.5f, -0.5f, // 右下
-0.5f, -0.5f // 左下
};
unsigned int VBO, VAO;
glGenBuffers(1, &VBO);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), &points, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
glBindVertexArray(0);
shader.use();
glBindVertexArray(VAO);
glDrawArrays(GL_POINTS, 0, 4);
暂无评论内容