我目前正在尝试使用libpng加载png图像,然后将其转换为随后绘制的OpenGL纹理。
现在,首先,要做一个快速测试,看看是否有任何纹理被绘制成一个简单的测试四边形,我做了这个纹理:
glGenTextures(1, &textureHandle);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureHandle);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, 4, 4);
const GLubyte myTexture[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGB, GL_UNSIGNED_BYTE, myTexture);
然后在我的四边形上绘制一个白色纹理。这非常有效。因此,它似乎表明片段着色器和顶点着色器工作正常,以及我的绘图逻辑的其余部分。
对于任何感兴趣的人来说,这是使用纹理进行绘图的主循环:
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(theProgram);
GLuint samplerLoc = glGetUniformLocation(theProgram, "tex");
if (samplerLoc == -1)
printf("Location name could not be found...\n");
glUniform1i(samplerLoc, 0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(16 * sizeof(float)));
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
现在,我使用libpng从png加载OpenGL纹理的函数就是这个:OpenGL Texture Load Function
我提供链接的原因是这篇文章不会无法阅读:)
基本上,我加载纹理并绑定它的代码部分是:
GLuint myImage = png_texture_load("niks.png", &width, &height);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, myImage);
GLuint mySampler;
glGenSamplers(1, &mySampler);
glBindSampler(0, mySampler);
这发生在主循环之前。
值得注意的是,我已经使用 glGetError 函数进行了大量调试,并且它根本不返回任何错误。另外,我已经逐步完成了 png_texture_load 函数,并成功返回了OpenGL纹理。
此外,我正在加载的图像是2的幂。它的尺寸为64x64。
我似乎完全不知道为什么,当我自己的文字纹理显示得很好时,它只是一个黑色纹理?
修改 的
这是libpng图像函数的一部分,它根据加载的数据创建纹理:
// Generate the OpenGL texture object
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, format, temp_width, temp_height, 0, format, GL_UNSIGNED_BYTE, image_data);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, temp_width, temp_height, GL_RGB, GL_UNSIGNED_BYTE, image_data);
答案 0 :(得分:0)
如果你喜欢,可以尝试一下吗?我很久以前写过它..
#include <fstream>
#include <stdexcept>
#include <cstdint>
typedef union RGBA
{
std::uint32_t Colour;
struct
{
std::uint8_t R, G, B, A;
};
} *PRGB;
void ReadFromStream(png_structp PngPointer, std::uint8_t* Data, std::size_t Length)
{
std::ifstream* Stream = reinterpret_cast<std::ifstream*>(png_get_io_ptr(PngPointer));
Stream->read(reinterpret_cast<char*>(Data), Length);
}
void LoadPngImage(const char* FilePath, std::vector<RGBA> &Pixels, std::uint32_t &width, std::uint32_t &height, std::uint16_t &BitsPerPixel)
{
Pixels.clear();
std::fstream hFile(FilePath, std::ios::in | std::ios::binary);
if (!hFile.is_open())
{
throw std::invalid_argument("File Not Found.");
}
std::uint8_t Header[18] = {0};
hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header));
hFile.seekg(8, std::ios::beg);
if (png_sig_cmp(Header, 0, 8))
{
hFile.close();
throw std::invalid_argument("Error: Invalid File Format. Required: Png.");
}
png_structp PngPointer = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!PngPointer)
{
hFile.close();
throw std::runtime_error("Error: Cannot Create Read Structure.");
}
png_infop InfoPointer = png_create_info_struct(PngPointer);
if (!InfoPointer)
{
hFile.close();
png_destroy_read_struct(&PngPointer, nullptr, nullptr);
throw std::runtime_error("Error: Cannot Create InfoPointer Structure.");
}
png_infop EndInfo = png_create_info_struct(PngPointer);
if (!EndInfo)
{
hFile.close();
png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr);
throw std::runtime_error("Error: Cannot Create EndInfo Structure.");
}
if (setjmp(png_jmpbuf(PngPointer)))
{
hFile.close();
png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr);
throw std::runtime_error("Error: Cannot Set Jump Pointer.");
}
png_set_sig_bytes(PngPointer, 8);
png_set_read_fn(PngPointer, &hFile, ReadFromStream);
png_read_info(PngPointer, InfoPointer);
channels = png_get_channels(PngPointer, InfoPointer);
png_get_IHDR(PngPointer, InfoPointer, &width, &height, &bitdepth, &colortype, &interlacetype, nullptr, nullptr);
png_set_interlace_handling(PngPointer);
png_set_strip_16(PngPointer);
png_set_packing(PngPointer);
switch (colortype)
{
case PNG_COLOR_TYPE_GRAY:
{
png_set_expand_gray_1_2_4_to_8(PngPointer);
png_set_gray_to_rgb(PngPointer);
png_set_bgr(PngPointer);
break;
}
case PNG_COLOR_TYPE_PALETTE:
{
png_set_palette_to_rgb(PngPointer);
if (png_get_valid(PngPointer, InfoPointer, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(PngPointer);
else
png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER);
png_set_bgr(PngPointer);
BitsPerPixel = 24;
break;
}
case PNG_COLOR_TYPE_GRAY_ALPHA:
{
png_set_gray_to_rgb(PngPointer);
break;
}
case PNG_COLOR_TYPE_RGB:
{
png_set_bgr(PngPointer);
png_set_filler(PngPointer, 0xFF, PNG_FILLER_AFTER);
BitsPerPixel = 24;
break;
}
case PNG_COLOR_TYPE_RGBA:
{
png_set_bgr(PngPointer);
BitsPerPixel = 32;
break;
}
default:
png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr);
throw std::runtime_error("Error: Png Type not supported.");
break;
}
png_read_update_info(PngPointer, InfoPointer);
channels = png_get_channels(PngPointer, InfoPointer);
int bitdepth, colortype, interlacetype;
png_get_IHDR(PngPointer, InfoPointer, &width, &height, &bitdepth, &colortype, &interlacetype, nullptr, nullptr);
Pixels.resize(width * height);
std::vector<std::uint8_t*> RowPointers(height);
std::uint8_t* BuffPos = reinterpret_cast<std::uint8_t*>(Pixels.data());
for (size_t I = 0; I < height; ++I)
{
RowPointers[I] = BuffPos + (I * width * sizeof(RGBA));
}
png_read_image(PngPointer, RowPointers.data());
png_read_end(PngPointer, InfoPointer);
png_destroy_read_struct(&PngPointer, &InfoPointer, nullptr);
hFile.close();
}
答案 1 :(得分:0)
首先,将glTexImage2D和glTexSubImage2D的params转储到调试输出,这样就可以验证temp_width,temp_height,image_data和format都包含合理的值。问题可能出在你的OpenGL使用上,但它可能很容易落在你的libpng用法中,所以你需要检查两者。您如何设置format
,temp_width
和temp_height
以及输入此代码时它们的值是多少?
接下来,为什么要调用两个纹理加载函数?
glTexImage2D(GL_TEXTURE_2D, 0, format, temp_width, temp_height, 0, format, GL_UNSIGNED_BYTE, image_data);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, temp_width, temp_height, GL_RGB, GL_UNSIGNED_BYTE, image_data);
这两个都应该具有相同的效果,所以我不明白为什么你这两个都叫它们。如果您只打算第一次调用分配存储,则应将0作为最终参数传递,或者调用glTexStorage2d
。
另外,一般来说,除非你有充分的理由不这样做,你应该为纹理格式指定GL_RGBA8(glTexImage2D中的第三个参数),但几乎肯定不是图像数据格式(第3到最后一个参数)在glTexImage2D和glTexSubImage2D)中,所以我对在两个地方都使用格式的glTexImage2D调用非常怀疑。
最后,您是否尝试在各种调用之后调用glGetError
以查看是否有任何错误产生错误? glGetError
可能是一个昂贵的调用,因此将它包装在预处理器宏中通常是一个好主意,您可以轻松地禁用它以进行发布或性能测试构建
我有一个宏GL_CHECK_ERROR,它调用一个像这样定义的内联函数
static inline void check() {
#ifdef GL_DEBUG
GLenum errorCode = glGetError();
if (errorCode != 0) {
throw error(errorCode);
}
#endif
}