使用以 freeimage 加载的纹理时,OpenGL 四边形显示为黑色
OpenGL quad appears black when using textures loaded with freeimage
我正在使用 OpenGL 4.3,我正在尝试绘制一个四边形,我想在其上应用此纹理(即 "textures/dickbutt.png")。纹理具有 654x654 尺寸。
但是每一种可能的指令组合总是让我有一个黑色的纹理,有时在右下角有一些人工制品。
下面是绘图所在的主要函数的代码。
void Run() {
shader::factory::CompileShaderFile("shaders/test.vert", GL_VERTEX_SHADER);
shader::factory::CompileShaderFile("shaders/test.frag", GL_FRAGMENT_SHADER);
GLuint m_shaderProgram = shader::factory::CreateProgram();
// Set up vertex data (and buffer(s)) and attribute pointers
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f
};
GLfloat texcoords[] = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Position attribute
glEnableVertexAttribArray(0);
glBindVertexBuffer(0, VBO, 0, 3*sizeof(GL_FLOAT));
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(0, 0);
GLuint texVBO;
glGenBuffers(1, &texVBO);
glBindBuffer(GL_ARRAY_BUFFER, texVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords), texcoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glBindVertexBuffer(1, texVBO, 0, 2 * sizeof(GL_FLOAT));
glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(1, 1);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLuint m_textureID =
texture::factory::Create2DTexture("textures/dickbutt.png");
shader::module::RegisterUniform("mytexture", m_shaderProgram);
while (!graphic_context->PollWindowClosedEvent()) {
double dt = timer::chrono::GetTimeElapsedInSeconds();
glActiveTexture(GL_TEXTURE0);
shader::module::Use(m_shaderProgram);
glUniform1i(shader::module::GetUniformLocation("mytexture", m_shaderProgram), 0);
glBindTexture(GL_TEXTURE_2D, m_textureID);
glBindVertexArray(VAO);
glDrawArrays(GL_QUADS, 0, 4);
glBindVertexArray(0);
// Next line renders the XYZ axes in separated shader program, commenting it out changes nothing in the texture display.
scene::Render();
graphic_context->Update();
timer::chrono::Update();
}
}
下面是 texture::factory 的代码,其中加载图像并创建和设置 OpenGL 缓冲区。
GLuint Create2DTexture(const std::string& a_sFileName) {
GLsizei wWidth, wHeight;
unsigned char *wImage = nullptr;
void *wBitMapHandle = nullptr;
if (!LoadImage(a_sFileName, wImage, wWidth, wHeight, wBitMapHandle)) {
std::cerr << "texture_factory::Create2DTexture -> Loading image failed. " << std::endl
<< "Returning 0xFFFFFFFF..." << std::endl;
return 0xFFFFFFFF;
}
// Generate texture
GLuint wTexture;
glGenTextures(1, &wTexture);
// Create texture
glBindTexture(GL_TEXTURE_2D, wTexture);
glTexImage2D(
GL_TEXTURE_2D, // 2D texture target
0, // Base mipmap level
GL_RGBA, // RGBA color components
wWidth, wHeight, // Dimensions
0, // Must be 0...
GL_RGBA, // Pixel data format
GL_UNSIGNED_BYTE, // Depends on what the LoadImage function return type
wImage); // Loaded image
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Commenting-out the next line make the artefacts appear on the quad
// glGenerateMipmap(GL_TEXTURE_2D);
// Free image
FreeImage(wBitMapHandle);
//glBindTexture(GL_TEXTURE_2D, 0);
return wTexture;
}
LoadImage 函数
bool LoadImage(const std::string& a_sFileName,
unsigned char *a_pImage,
GLsizei& a_rWidth,
GLsizei& a_rHeight,
void *a_pBitmapHandle) {
const char *wFilename = a_sFileName.c_str();
//image format
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
//pointer to the image, once loaded
FIBITMAP *dib(0);
//pointer to the image data
BYTE* bits(0);
//image width and height
unsigned int width(0), height(0);
//check the file signature and deduce its format
fif = FreeImage_GetFileType(wFilename, 0);
//if still unknown, try to guess the file format from the file extension
if (fif == FIF_UNKNOWN)
fif = FreeImage_GetFIFFromFilename(wFilename);
//if still unkown, return failure
if (fif == FIF_UNKNOWN)
return false;
//check that the plugin has reading capabilities and load the file
if (FreeImage_FIFSupportsReading(fif))
dib = FreeImage_Load(fif, wFilename);
//if the image failed to load, return failure
if (!dib)
return false;
//retrieve the image data
bits = FreeImage_GetBits(dib);
//get the image width and height
width = FreeImage_GetWidth(dib);
height = FreeImage_GetHeight(dib);
//if somehow one of these failed (they shouldn't), return failure
if ((bits == 0) || (width == 0) || (height == 0))
return false;
a_pImage = bits;
a_rWidth = width;
a_rHeight = height;
a_pBitmapHandle = dib;
return true;
}
以及相关的vertex/frag着色器代码分别
// test.vert
#version 430
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texcoord;
layout (std140, binding = 0) uniform CameraInfo {
mat4 ProjectionView;
vec3 eye;
};
out vec2 tex_coord;
void main()
{
vec4 vertex = vec4(position,1.0);
gl_Position = ProjectionView*vertex;
tex_coord = vec2(texcoord.x, 1.0 - texcoord.y);
}
//test.frag
#version 430
out vec4 color;
in vec2 tex_coord;
// Texture samplers
uniform sampler2D mytexture;
void main()
{
//color = vec4(1.0f,0.0f,0.0f,1.0f); // Prints red quad
color = texture2D(mytexture, tex_coord);
}
我将代码与教程、SO 上的其他帖子和工作示例进行了数十次比较,但我找不到我做错了什么。
您已经传递了 a_rWidth
和 a_rHeight
作为参考。对于 a_pImage
和 a_pBitmapHandle
.
,您必须同样这样做
这一切都归结为为什么会这样:
int a = 1;
test(a);
printf("%d\n", a);
打印 1
而不是 2
鉴于 test()
定义如下:
void test(int a) {
a = 2;
}
因此您需要将 LoadImage
更改为:
bool LoadImage(
const std::string &a_sFileName,
unsigned char **a_pImage,
GLsizei &a_rWidth,
GLsizei &a_rHeight,
void **a_pBitmapHandle) {
[...]
*a_pImage = bits;
a_rWidth = width;
a_rHeight = height;
*a_pBitmapHandle = dib;
并这样称呼它:
LoadImage(a_sFileName, &wImage, wWidth, wHeight, &wBitMapHandle)
另外请注意,FreeImage 将图像解码为 BGR/BGRA 格式。所以你必须使用 GL_BGRA
而不是 GL_RGBA
.
我正在使用 OpenGL 4.3,我正在尝试绘制一个四边形,我想在其上应用此纹理(即 "textures/dickbutt.png")。纹理具有 654x654 尺寸。
但是每一种可能的指令组合总是让我有一个黑色的纹理,有时在右下角有一些人工制品。
下面是绘图所在的主要函数的代码。
void Run() {
shader::factory::CompileShaderFile("shaders/test.vert", GL_VERTEX_SHADER);
shader::factory::CompileShaderFile("shaders/test.frag", GL_FRAGMENT_SHADER);
GLuint m_shaderProgram = shader::factory::CreateProgram();
// Set up vertex data (and buffer(s)) and attribute pointers
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f
};
GLfloat texcoords[] = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Position attribute
glEnableVertexAttribArray(0);
glBindVertexBuffer(0, VBO, 0, 3*sizeof(GL_FLOAT));
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(0, 0);
GLuint texVBO;
glGenBuffers(1, &texVBO);
glBindBuffer(GL_ARRAY_BUFFER, texVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords), texcoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glBindVertexBuffer(1, texVBO, 0, 2 * sizeof(GL_FLOAT));
glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(1, 1);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLuint m_textureID =
texture::factory::Create2DTexture("textures/dickbutt.png");
shader::module::RegisterUniform("mytexture", m_shaderProgram);
while (!graphic_context->PollWindowClosedEvent()) {
double dt = timer::chrono::GetTimeElapsedInSeconds();
glActiveTexture(GL_TEXTURE0);
shader::module::Use(m_shaderProgram);
glUniform1i(shader::module::GetUniformLocation("mytexture", m_shaderProgram), 0);
glBindTexture(GL_TEXTURE_2D, m_textureID);
glBindVertexArray(VAO);
glDrawArrays(GL_QUADS, 0, 4);
glBindVertexArray(0);
// Next line renders the XYZ axes in separated shader program, commenting it out changes nothing in the texture display.
scene::Render();
graphic_context->Update();
timer::chrono::Update();
}
}
下面是 texture::factory 的代码,其中加载图像并创建和设置 OpenGL 缓冲区。
GLuint Create2DTexture(const std::string& a_sFileName) {
GLsizei wWidth, wHeight;
unsigned char *wImage = nullptr;
void *wBitMapHandle = nullptr;
if (!LoadImage(a_sFileName, wImage, wWidth, wHeight, wBitMapHandle)) {
std::cerr << "texture_factory::Create2DTexture -> Loading image failed. " << std::endl
<< "Returning 0xFFFFFFFF..." << std::endl;
return 0xFFFFFFFF;
}
// Generate texture
GLuint wTexture;
glGenTextures(1, &wTexture);
// Create texture
glBindTexture(GL_TEXTURE_2D, wTexture);
glTexImage2D(
GL_TEXTURE_2D, // 2D texture target
0, // Base mipmap level
GL_RGBA, // RGBA color components
wWidth, wHeight, // Dimensions
0, // Must be 0...
GL_RGBA, // Pixel data format
GL_UNSIGNED_BYTE, // Depends on what the LoadImage function return type
wImage); // Loaded image
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Commenting-out the next line make the artefacts appear on the quad
// glGenerateMipmap(GL_TEXTURE_2D);
// Free image
FreeImage(wBitMapHandle);
//glBindTexture(GL_TEXTURE_2D, 0);
return wTexture;
}
LoadImage 函数
bool LoadImage(const std::string& a_sFileName,
unsigned char *a_pImage,
GLsizei& a_rWidth,
GLsizei& a_rHeight,
void *a_pBitmapHandle) {
const char *wFilename = a_sFileName.c_str();
//image format
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
//pointer to the image, once loaded
FIBITMAP *dib(0);
//pointer to the image data
BYTE* bits(0);
//image width and height
unsigned int width(0), height(0);
//check the file signature and deduce its format
fif = FreeImage_GetFileType(wFilename, 0);
//if still unknown, try to guess the file format from the file extension
if (fif == FIF_UNKNOWN)
fif = FreeImage_GetFIFFromFilename(wFilename);
//if still unkown, return failure
if (fif == FIF_UNKNOWN)
return false;
//check that the plugin has reading capabilities and load the file
if (FreeImage_FIFSupportsReading(fif))
dib = FreeImage_Load(fif, wFilename);
//if the image failed to load, return failure
if (!dib)
return false;
//retrieve the image data
bits = FreeImage_GetBits(dib);
//get the image width and height
width = FreeImage_GetWidth(dib);
height = FreeImage_GetHeight(dib);
//if somehow one of these failed (they shouldn't), return failure
if ((bits == 0) || (width == 0) || (height == 0))
return false;
a_pImage = bits;
a_rWidth = width;
a_rHeight = height;
a_pBitmapHandle = dib;
return true;
}
以及相关的vertex/frag着色器代码分别
// test.vert
#version 430
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texcoord;
layout (std140, binding = 0) uniform CameraInfo {
mat4 ProjectionView;
vec3 eye;
};
out vec2 tex_coord;
void main()
{
vec4 vertex = vec4(position,1.0);
gl_Position = ProjectionView*vertex;
tex_coord = vec2(texcoord.x, 1.0 - texcoord.y);
}
//test.frag
#version 430
out vec4 color;
in vec2 tex_coord;
// Texture samplers
uniform sampler2D mytexture;
void main()
{
//color = vec4(1.0f,0.0f,0.0f,1.0f); // Prints red quad
color = texture2D(mytexture, tex_coord);
}
我将代码与教程、SO 上的其他帖子和工作示例进行了数十次比较,但我找不到我做错了什么。
您已经传递了 a_rWidth
和 a_rHeight
作为参考。对于 a_pImage
和 a_pBitmapHandle
.
这一切都归结为为什么会这样:
int a = 1;
test(a);
printf("%d\n", a);
打印 1
而不是 2
鉴于 test()
定义如下:
void test(int a) {
a = 2;
}
因此您需要将 LoadImage
更改为:
bool LoadImage(
const std::string &a_sFileName,
unsigned char **a_pImage,
GLsizei &a_rWidth,
GLsizei &a_rHeight,
void **a_pBitmapHandle) {
[...]
*a_pImage = bits;
a_rWidth = width;
a_rHeight = height;
*a_pBitmapHandle = dib;
并这样称呼它:
LoadImage(a_sFileName, &wImage, wWidth, wHeight, &wBitMapHandle)
另外请注意,FreeImage 将图像解码为 BGR/BGRA 格式。所以你必须使用 GL_BGRA
而不是 GL_RGBA
.