第二十一课,几何着色器(基础篇)

几何着色器的作用

输入

输入类型

从顶点着色器接收下列任何一个图元值:

类型 数组大小
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_PositionEmitVertex()提交到图元的顶点。

提交输出集

 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);

实验结果

在这里插入图片描述

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片