Qt/OpenGL中的着色器问题

Issues with shaders in Qt/OpenGL

本文关键字:问题 OpenGL Qt      更新时间:2023-10-16

如何在片段着色器中使用不同的颜色输出?

比如说,我的vshader是这样的:

#version 330
uniform mat4 mvpmatrix;
layout(location=0) in vec4 position;
layout(location=1) in vec2 texcoord;
out vec2 out_texcoord;
void main()
{
    gl_Position = mvpmatrix * position;    
    out_texcoord = texcoord;
}
//fshader

#version 330
uniform sampler2D texture;
in vec2 out_texcoord;
out vec4 out_color;
out vec4 out_color2;
void main()
{        
    out_color = texture2D(texture, out_texcoord);
   // out_color2 = vec3(1.0, 1.0, 1.0, 1.0);
}

像这样访问:

m_program->enableAttributeArray(0);  // position
m_program->setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(Data));
m_program->enableAttributeArray(1); // texture
m_program->setAttributeBuffer(1, GL_FLOAT, sizeof(QVector3D), 2, sizeof(Data));
到目前为止,所有内容都使用片段着色器的默认输出,这是一个纹理。但是如何访问不同的片段输出呢?我还需要使用布局吗?而且,这可能是个愚蠢的问题……但是vshader/fshader的布局位置是否相互绑定?所以,如果我在AttributeArray(1)上启用缓冲区,我被迫使用两个着色器的布局位置1 ?

你可以绑定另一个属性位置来发送颜色信息到你的片段着色器,但让我告诉你另一个技巧:)

我使用了2个location属性,一个用来表示顶点的位置,另一个用来表示顶点的颜色。

glBindAttribLocation(program_, 0, "vs_in_pos");
glBindAttribLocation(program_, 1, "vs_in_col");

这是我的网格定义,其中顶点包含两个3D向量:

Vertex vertices[] = {
        {glm::vec3(-1, -1,  1), glm::vec3(1, 0, 0)},
        {glm::vec3(1, -1,  1), glm::vec3(1, 0, 0)},
        {glm::vec3(-1,  1,  1), glm::vec3(1, 0, 0)},
        {glm::vec3(1,  1,  1), glm::vec3(1, 0, 0)},
        {glm::vec3(-1, -1, -1), glm::vec3(0, 1, 0)},
        {glm::vec3(1, -1, -1), glm::vec3(0, 1, 0)},
        {glm::vec3(-1,  1, -1), glm::vec3(0, 1, 0)},
        {glm::vec3(1,  1, -1), glm::vec3(0, 1, 0)},
    };
    GLushort indices[] = {
        // Front
        0, 1, 2,  2, 1, 3,
        // Back
        4, 6, 5,  6, 7, 5,
        // Top
        2, 3, 7,  2, 7, 6,
        // Bottom
        0, 5, 1,  0, 4, 5,
        // Left
        0, 2, 4,  4, 2, 6,
        // Right
        1, 5, 3,  5, 7, 3
    };

这将表示一个立方体。我将这个预定义的颜色与计算值混合。这意味着立方体的颜色会因其位置而改变。为RGB值设置一个3D矢量,并设置在片段着色器中使用它:

loc_col_ = glGetUniformLocation(program_, "color");

现在在我的渲染函数中,我将立方体放置在一个2D圆圈中,移动它们,旋转它们:

for (int i = 0; i < num_of_cubes_; ++i) {
        double fi = 2 * PI * (i / (double) num_of_cubes_);
        glm::mat4 position = glm::translate<float>(cubes_radius_ * cos(fi), cubes_radius_ * sin(fi), 0);
        glm::mat4 crackle = glm::translate<float>(0, 0.1 * (sin(2 * PI * (SDL_GetTicks() / 500.0) + i)), 0);
        glm::mat4 rotate = glm::rotate<float>(360 * (SDL_GetTicks() / 16000.0), 0, 0, 1);
        world_ = position * crackle * rotate;
        glm::vec3 color = glm::vec3((1 + cos(fi)) * 0.5, (1 + sin(fi)) * 0.5, 1 - ((1 + cos(fi)) * 0.5));
        glUniformMatrix4fv(loc_world_, 1, GL_FALSE, &(world_[0][0]));
        glUniform3fv(loc_col_, 1, &(color[0]));
        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
    }

你可以看到这里我不仅发送了世界矩阵,还发送了颜色向量。片段着色器中的线性插值是通过mix()函数实现的:

#version 130
in vec3 vs_out_col;
in vec3 vs_out_pos;
out vec4 fs_out_col;
uniform vec3 color;
void main() {
        fs_out_col = vec4(mix(color, vs_out_col, 0.5), 1);
}

颜色是在渲染中传递的值,而vs_out_col来自顶点着色器,它在"通道"1中到达那里。

希望你能理解我。

顶点着色器和片段着色器的布局位置是独立的。QT可能会误导enableAttributeArray,因为在OpenGL中这个函数被称为glEnableVertexAttribArray - vertex是这里的关键字。所以你只能将每个顶点的数据传递到顶点着色器,然后使用in/out(插值)将其传递到片段着色器。

如果你想从片段着色器中使用多个输出,你必须使用位置和输出缓冲区。

这个链接应该也很有帮助,我稍后会总结。