在 OpenGL 中将纹理传递给着色器

Passing texture to shader in OpenGL

我正在处理一些示例,我正在尝试将纹理传递给着色器。

要构建一个 VAO,我有这段代码:

void PlaneShaderProgram::BuildVAO()
{
    // Generate and bind the vertex array object
    glGenVertexArrays(1, &_vao);
    glBindVertexArray(_vao);

    // Generate and bind the vertex buffer object
    glGenBuffers(1, &_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, _vbo);
    glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), _coordinates, GL_STATIC_DRAW);

    // Generate and bind the index buffer object
    glGenBuffers(1, &_ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLuint), _indexes, GL_STATIC_DRAW);

    // Generate and bind texture
    _texture = LoadTexture("floor.bmp");

    LoadAttributeVariables();

    glBindVertexArray(0);
}

这是我加载着色器属性的方式:

void PlaneShaderProgram::LoadAttributeVariables()
{
    GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
    glEnableVertexAttribArray(VertexPosition_location);

    glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
}

void PlaneShaderProgram::LoadUniformVariables()
{
    // OpenGL Matrices
    GLuint ModelViewProjection_location = glGetUniformLocation(GetProgramID(), "mvpMatrix");
    glUniformMatrix4fv(ModelViewProjection_location, 1, GL_FALSE, glm::value_ptr(_ModelViewProjection));

    // Floor texture
    // glActiveTexture(GL_TEXTURE0);
    // glBindTexture(GL_TEXTURE_2D, _texture);
    // GLint Texture_location = glGetUniformLocation(GetProgramID(), "texture");
    // glUniform1i(Texture_location, 0);
}

还有我的LoatTexture

GLuint ProgramManager::LoadTexture(const char* imagepath)
{
    unsigned char * data = LoadBMP(imagepath, &width, &height);

    GLuint textureID;
    glGenTextures(1, &textureID);
    glBindTexture(GL_TEXTURE_2D, textureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    return textureID;
}

最后,我在 OpenGL 主循环中调用的绘制函数如下:

void PlaneShaderProgram::DrawPlane(const glm::mat4 &Projection, const glm::mat4 &ModelView)
{
    _ModelViewProjection = Projection * ModelView;
    _ModelView = ModelView;

    Bind();

    glBindVertexArray(_vao);
    LoadUniformVariables();
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

    UnBind();
}

我没有得到的是,即使我没有设置我的着色器使用的统一纹理(在代码中注释),平面仍然是使用纹理绘制的。这对我来说毫无意义。一旦着色器需要 sample2D,我认为这不应该工作并且 return 一些错误。

顶点着色器:

uniform mat4 mvpMatrix;
in vec4 vPosition;

smooth out vec2 uvCoord;

void main() 
{
   uvCoord = vPosition.xz;
   gl_Position = mvpMatrix * vPosition;
}

片段着色器:

uniform sampler2D texture;
in vec2 uvCoord;

out vec4 fragColor;
void main()
{ 
    fragColor.rgb = texture(texture, uvCoord).rgb;
};

我错过了什么吗?不知何故,我不明白为什么,但我真的很喜欢。

GLSL 中的 sampler 数据类型引用纹理 unit,而不是纹理 object。默认情况下,uniform 会被初始化为 0,所以如果你没有设置 sampler uniform,它们将从纹理单元 0(这也是默认单元)采样。在您的 ProgramManager::LoadTexture() 方法中,您绑定了新创建的纹理,很可能您仍在使用 GL_TEXTURE0 作为当前活动的纹理单元。你似乎从来没有取消绑定它,所以它在绘制调用时仍然是绑定的,着色器可以访问它。