在 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
作为当前活动的纹理单元。你似乎从来没有取消绑定它,所以它在绘制调用时仍然是绑定的,着色器可以访问它。
我正在处理一些示例,我正在尝试将纹理传递给着色器。
要构建一个 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
作为当前活动的纹理单元。你似乎从来没有取消绑定它,所以它在绘制调用时仍然是绑定的,着色器可以访问它。