所以我目前正在使用SDL2与OpenGL(glew)制作游戏,并使用SOIL加载图像,我正在使用现代opengl技术与顶点数组对象和着色器等等。我目前正试图只渲染一个纹理到窗口,但我似乎无法做到这一点。我查了很多教程和解决方案,但我似乎无法理解我应该如何正确地做到这一点。我不确定这是问题的着色器,还是我的代码本身。我将在下面发布所有必要的代码,并且需要更多代码我很乐意提供它。欢迎任何答案和解决方案。对于将来的上下文,为了方便起见,我有一个用于存储VAO数据的类。代码:
以下是加载纹理的代码:
void PXSprite::loadSprite() {
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
int imagew, imageh;
//The path is a class variable, and I haven't received any errors from this function, so I can only assume it's getting the texture file correctly.
unsigned char* image = SOIL_load_image(path.c_str(), &imagew, &imageh, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imagew, imageh, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
//Don't worry about this code. It's just to keep the buffer object data.
//It works properly when rendering polygons.
spriteVAO.clear();
spriteVAO.addColor(PXColor::WHITE());
spriteVAO.addColor(PXColor::WHITE());
spriteVAO.addColor(PXColor::WHITE());
spriteVAO.addColor(PXColor::WHITE());
spriteVAO.addTextureCoordinate(0, 0);
spriteVAO.addTextureCoordinate(1, 0);
spriteVAO.addTextureCoordinate(1, 1);
spriteVAO.addTextureCoordinate(0, 1);
glGenVertexArrays(1, &spriteVAO.vaoID);
glGenBuffers(1, &spriteVAO.posVBOid);
glBindBuffer(GL_ARRAY_BUFFER, spriteVAO.posVBOid);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*12, nullptr, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &spriteVAO.colVBOid);
glBindBuffer(GL_ARRAY_BUFFER, spriteVAO.colVBOid);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 16, &spriteVAO.colors[0], GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &spriteVAO.texVBOid);
glBindBuffer(GL_ARRAY_BUFFER, spriteVAO.texVBOid);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, &spriteVAO.texCoords[0], GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
这是我渲染纹理的代码:
void PXSprite::render(int x, int y) {
spriteVAO.clear(PXVertexArrayObject::positionAttributeIndex);
spriteVAO.addPosition(x, y);
spriteVAO.addPosition(x+width, y);
spriteVAO.addPosition(x, y+height);
spriteVAO.addPosition(x+width, y+height);
glBindTexture(GL_TEXTURE_2D, textureID);
glBindVertexArray(spriteVAO.vaoID);
glBindBuffer(GL_ARRAY_BUFFER, spriteVAO.posVBOid);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat)*12, &spriteVAO.positions[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindTexture(GL_TEXTURE_2D, 0);
}
这是我的顶点着色器:
#version 330 core
in vec3 in_Position;
in vec4 in_Color;
in vec2 in_TexCoord;
out vec4 outPosition;
out vec4 outColor;
out vec2 outTexCoord;
void main() {
gl_Position = vec4(in_Position.x, in_Position.y*-1.0, in_Position.z, 1.0);
outTexCoord = in_TexCoord;
outColor = in_Color;
}
这是我的片段着色器:
#version 330 core
in vec2 outTexCoord;
in vec4 outColor;
out vec4 glFragColor;
out vec4 glTexColor;
uniform sampler2D pxsampler;
void main() {
vec4 texColor = texture(pxsampler, outTexCoord);
//This outputs the color of polygons if I don't multiply outColor by texColor, but once I add texColor, no colors show up at all.
glFragColor = texColor*outColor;
}
最后,这里有一些代码可以参考我在加载着色器时在正确的时间使用的VAO属性指针:
glBindAttribLocation(ProgramID, 0, "in_Position");
glBindAttribLocation(ProgramID, 1, "in_Color");
glBindAttribLocation(ProgramID, 2, "in_TexCoord");
欢迎任何帮助或建议。如果需要任何额外的代码,我会添加它。如果这个问题看起来多余,我很抱歉,但我找不到任何帮助我的方法。如果有人能够向我解释渲染纹理的代码究竟是如何工作的,那就太棒了,因为从我读过的教程中他们通常不解释什么是什么,所以我知道怎么再做,所以我'我不清楚我在做什么。再次,任何帮助表示赞赏。谢谢!
答案 0 :(得分:1)
最好简化问题以追踪问题。例如,您可以只分配width*heigth*3
缓冲区并使用127
填充以获取灰色图像(或粉红色以使其更明显),而不是加载实际图像。尝试使用uv
坐标对片段进行着色,而不是使用采样器来查看这些值是否设置正确。
我认为你应该在绘制调用之前启用顶点属性数组:
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
此外,在将纹理绑定到纹理单元之前,您应该指定要使用的单位而不是依赖于默认值:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
并确保将您的采样器绑定到该纹理单元:
glUniform1i(glGetUniformLocation(ProgramID, "pxsampler"), 0);
对于采样器制服,我们直接设置索引而不是GL_TEXTURE*
值。因此,GL_TEXTURE0
在设置制服时需要索引0
,而不是 GL_TEXTURE0
。
答案 1 :(得分:1)
我在这段代码中发现了一些问题。部分已在其他答案/评论中提及,部分未提及。
主要问题是您在设置顶点属性时未绑定VAO。请参阅此代码序列:
glGenVertexArrays(1, &spriteVAO.vaoID);
glGenBuffers(1, &spriteVAO.posVBOid);
glBindBuffer(GL_ARRAY_BUFFER, spriteVAO.posVBOid);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*12, nullptr, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
在这里,您创建了一个VAO(或更准确地说,是VAO的id),但不要绑定它。 glVertexAttribPointer()
调用建立的状态存储在当前绑定的VAO中。此调用实际上应该在核心配置文件上下文中给出GL_INVALID_OPERATION
错误,因为在创建时需要绑定VAO。
要解决此问题,请在创建ID后绑定VAO:
glGenVertexArrays(1, &spriteVAO.vaoID);
glBindVertexArray(spriteVAO.vaoID);
...
glGenerateMipmap()
在错误的地方正如评论中所指出的,此次通话属于 {/ 1}} glTexImage2D()
之后。它根据当前纹理内容生成mipmap,这意味着您需要首先指定纹理数据。
此错误不会对您当前的代码造成直接伤害,因为您实际上并未使用mipmap。但是如果你设置GL_TEXTURE_MIN_FILTER
值来使用mipmapping,这就很重要了。
glEnableVertexAttribArray()
在错误的地方这需要在<{strong> glDrawArray()
调用之前发生,因为显然必须为绘图启用属性。
不是在绘制调用之前移动它们,而是将它们放在属性设置代码中,沿着glVertexAttribPointer()
调用更好。在VAO中跟踪启用/禁用状态,因此不需要每次都进行这些调用。只需在设置过程中设置一次所有状态,然后在绘制调用之前简单地绑定VAO将再次设置所有必要状态。
glVertexAttribPointer()
来电无害,但render()
方法中的此调用是多余的:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
同样,在VAO中跟踪此状态,因此一旦您解决了上面列出的问题,在安装过程中进行一次调用就足够了。