我是OpenGL的新手,目前正在学习。
使用SOIL 2,我正在加载一个纹理,并试图在屏幕上渲染它。我像这样加载纹理:
GLuint texture;
texture = SOIL_load_OGL_texture(("resources/textures/" + fileName + ".png").c_str(),
SOIL_LOAD_AUTO, //Problem
SOIL_CREATE_NEW_ID,
SOIL_FLAG_INVERT_Y | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_NTSC_SAFE_RGB);
glBindTexture(GL_TEXTURE_2D, texture);
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_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, NULL);
问题是,当我尝试用SOIL_LOAD_AUTO或SOIL_LOAD_LA加载纹理时,我得到一个黑色的正方形。也就是说,如果我使用SOIL_LOAD_RGBA,则显示灰度纹理。
互联网搜索什么也没有找到,我倾向于相信我不明白“灰度”模式是如何工作的。
目前我的代码看起来像这样(是的,它有点错误,但现在我正在尝试理解OpenGL缓冲区,纹理加载和着色器是如何工作的,所以我没有完美地做每件事):
渲染:
void Render::runGame() {
logger->info("Running content rendering...");
glfwShowWindow(window);
World world(width, height, &logger);
GLfloat data[] = {
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, //Top left
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, //Bottom left
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, //Top right
0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f //Bottom right
};
GLubyte edata[6] = { 0, 1, 2, 2, 1, 3 };
world.getNormalizedCoord(0, height, 0, data);
world.getNormalizedCoord(0, 0, 8, data);
world.getNormalizedCoord(width, height, 16, data);
world.getNormalizedCoord(width, 0, 24, data);
GLuint VBO;
glGenBuffers(1, &VBO);
GLuint EBO;
glGenBuffers(1, &EBO);
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(edata), edata, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*) 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*) (2 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*) (6 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glBindVertexArray(NULL);
Shader shader = Shader("tile", &logger);
shader.create();
Texture texture = Texture("tile", &logger);
texture.create();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glClear(GL_COLOR_BUFFER_BIT);
if (texture.use() && shader.use()) {
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL);
glBindVertexArray(NULL);
}
shader.free();
texture.free();
glfwSwapBuffers(window);
}
destroy();
}
纹理类别:
//Constructor...
Texture::~Texture() noexcept { glDeleteTextures(1, &texture); }
void Texture::create() {
if (hasLogger()) logger->info("Loading «" + fileName + "» texture...");
if (isCreated()) {
if (hasLogger()) logger->warn("Attempt to create texture «" + fileName + "» that is already created");
return;
}
GLuint texture;
texture = SOIL_load_OGL_texture(("resources/textures/" + fileName + ".png").c_str(),
SOIL_LOAD_AUTO, //Problem
SOIL_CREATE_NEW_ID,
SOIL_FLAG_INVERT_Y | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_NTSC_SAFE_RGB);
if (texture == 0) {
if (hasLogger()) logger->fatal("Failed to create texture «" + fileName + "»: " + SOIL_last_result());
return;
}
glBindTexture(GL_TEXTURE_2D, texture);
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_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
this->texture = texture;
created = true;
}
GLuint Texture::getTexture() const noexcept { return texture; }
bool Texture::use() const {
if (!isCreated()) {
if (hasLogger()) logger->warn("Texture «" + fileName + "» using before creating");
return false;
}
else {
glBindTexture(GL_TEXTURE_2D, texture);
return true;
}
}
void Texture::free() const noexcept { glBindTexture(GL_TEXTURE_2D, NULL); }
bool Texture::isCreated() const noexcept { return created; }
bool Texture::hasLogger() const noexcept { return logger != nullptr; }
顶点着色器:
#version 330 core
layout (location = 0) in vec2 position;
layout (location = 1) in vec4 color;
layout (location = 2) in vec2 texCoord;
out vec4 fragColor;
out vec2 fragTexCoord;
void main() {
gl_Position = vec4(position, 0.0f, 1.0f);
fragColor = color;
fragTexCoord = texCoord;
}
片段着色器:
#version 330 core
in vec4 fragColor;
in vec2 fragTexCoord;
out vec4 color;
uniform sampler2D fragTexture;
void main() {
color = texture(fragTexture, fragTexCoord);
}
纹理:x1c 0d1x
使用SOIL_LOAD_AUTO或SOIL_LOAD_LA
得到的结果
我想要得到的结果,目前只有SOIL_LOAD_RGBA才有可能:
我真的不明白这是怎么回事,有什么原因会有如此奇怪的行为?
P.S.我的OpenGL版本是3.3核心配置文件和向前兼容性
解决方案:
我听从了接受答案的建议,放弃了SOIL。我使用了std_image,并正确地将纹理加载到OpenGL中。我的渲染代码没有改变,纹理加载代码现在看起来像这样:
void Texture::create() noexcept {
if (hasLogger()) logger->info("Loading «" + fileName + "» texture...");
if (isCreated()) {
if (hasLogger()) logger->warn("Attempt to create texture «" + fileName + "» that is already created");
return;
}
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); //flip y for opengl render correctly
stbi_uc* data = stbi_load(("resources/textures/" + fileName + ".png").c_str(), &width, &height, &nrChannels, 0);
if (data) {
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
GLenum format;
switch (nrChannels) {
case 1: { //L
format = GL_RED;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); //Texture swizzle parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); //for correct store and render
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); //image with different channels
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
break;
}
case 2: { //LA
format = GL_RG;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_GREEN);
for (int i = 0; i < 2 * width * height; i += 2) { //Multiply alpha
data[i] = (data[i] * data[i + 1] + 128) >> 8;
}
break;
}
case 3: default: { //RGB
format = GL_RGB;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
break;
}
case 4: { //RGBA
format = GL_RGBA;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
for (int i = 0; i < 4 * width * height; i += 4) { //Multiply alpha
data[i + 0] = (data[i + 0] * data[i + 3] + 128) >> 8;
data[i + 1] = (data[i + 1] * data[i + 3] + 128) >> 8;
data[i + 2] = (data[i + 2] * data[i + 3] + 128) >> 8;
}
break;
}
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, format == GL_RGBA || format == GL_RG ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, format == GL_RGBA || format == GL_RG ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, NULL);
stbi_image_free(data);
this->texture = texture;
created = true;
}
else {
if (hasLogger()) logger->fatal("Failed to create texture «" + fileName + "»");
}
}
我做了加载四种纹理类型,如Luminous,Luminous/Alpha,RGB,RGBA。为此,我必须使用GL_TEXTURE_SWIZZLE。此外,我没有找到SOIL_FLAG_MULTIPLY_ALPHA的类似物,没有它,透明纹理看起来与我预期的有点不同。所以我添加了代码来处理这个细节
1条答案
按热度按时间h6my8fg21#
可加载的图像格式(force_channels)(SOIL.h)。
*SOIL_LOAD_AUTO(
=0
)将保留找到的任何格式的图像。*SOIL_LOAD_LA(
=2
)强制图像加载为带Alpha的Luminous*SOIL_LOAD_RGBA(
=4
)强制图像加载为绿色蓝Alpha在函数SOIL_internal_create_OGL_texture的第1187行中,您将看到,如果通道计数为
1
或2
,则SOIL使用GL_LUMINANCE
和GL_LUMINANCE_ALPHA
符号。唯一的问题是,
GL_LUMINANCE
和GL_LUMINANCE_ALPHA
对于当前的OpenGL版本(4.6)是未知的。另一方面,在Legacy OpenGL和OpenGL ES中,glTexImage2D
将这些符号识别为format
参数。解决方案:
SOIL_LOAD_AUTO
),SOIL_LOAD_RGB(A)
(适用于所有OpenGL版本)或示例(使用stb_image):