gpt4 book ai didi

c - OpenGL中的位图渲染方法?

转载 作者:行者123 更新时间:2023-12-04 05:16:37 27 4
gpt4 key购买 nike

我最近一直在用纯 C 语言研究一点位图解析器,只是为了了解更简单图像格式的低级工作原理。到目前为止,使用维基百科的article在位图文件上,我已经能够(至少我认为)正确解析信息 - 至少,大部分。

问题是我不太确定从那里做什么:因为我一直在使用 3.1 环境,所以我可以访问更多现代化的功能,这很好,尽管我仍然迷路了。我有一个带有 GLFW 的窗口设置,到目前为止还没有真正呈现任何东西,因为我一直专注于解析/低级细节。

由于我非常努力地避免查看实际的代码示例,如果有人可以向我解释仅使用 OpenGL/GLFW 和 ISO C 标准库渲染位图所涉及的过程,那就太好了。

虽然我有几个着色器,并且我能够毫无问题地加载它们,但我认为我需要做的是渲染一个符合尺寸(宽度,高度)的[不可见]四边形图像本身,然后将像素数据传递给 OpenGL。然而,主要问题是着色器的设置如下:

顶点着色器

#version 150
#extension GL_ARB_separate_shader_objects : enable

layout(location = 0) in vec2 Position;
layout(location = 1) in vec2 UV_In;

out vec2 UV;

void main()
{
gl_Position = vec4( Position, 0.0f, 1.0f );
UV = UV_In;
}

片段着色器
#version 150
#extension GL_ARB_separate_shader_objects : enable

in vec2 UV;

out vec3 Output;

uniform sampler2D TheSampler;

void main()
{
Output = texture2D( TheSampler, UV ).rgb;
}

而且我不确定如何获得着色器所需的实际 UV 坐标。我想我需要生成顶点,将它们存储在一个数组中,然后按照 glVertexAttribPointer(...) 的行调用一些东西对于 UV 坐标,但我不确定我应该使用图像中的哪些数据来获取它,甚至不确定我是否已经在函数中解析了它。我想这将涉及使用内部/外部 for 循环(外部表示 x,内部表示 y)以行/列方式抓取图像。不过,我对此感到有些困惑,我不确定这是否是我需要的。

无论哪种方式,任何有关如何做到这一点的建议都将不胜感激。

解析图像的实际代码( HEADER_LENGTH = 54 bytes):
GLuint Image_LoadBmp( const char* fname, image_bmp_t* data )
{
uint8_t header[ HEADER_LENGTH ];

FILE* f = fopen( fname, "rb" );

if ( !f )
{
printf( "ERROR: file \"%s\" could not be opened [likely] due to incorrect path. :/ \n", fname );

return 0; // return false
}

data->filename = strdup( fname ); // TODO: write a wrapper for strdup which exits program on NULL returns

const size_t num_bytes_read = fread( ( void* )header, sizeof( uint8_t ), HEADER_LENGTH, f );

if ( num_bytes_read != HEADER_LENGTH )
{
printf( "ERROR: file \"%s\" could not be opened due to header size being " _SIZE_T_SPECIFIER " bytes; "\
"this is an invalid format. \n", fname, num_bytes_read );

return 0;
}

if ( header[ 0 ] != *( uint8_t* )"B" || header[ 1 ] != *( uint8_t* )"M" )
{
printf( "ERROR: file \"%s\" does NOT have a valid signature \n", fname );

return 0;
}

data->image_size = *( uint32_t* )&( header[ 0x22 ] );
data->header_size = ( uint32_t )( header[ 0x0E ] );
data->width = ( uint32_t )( header[ 0x12 ] );
data->height = ( uint32_t )( header[ 0x16 ] );
data->pixel_data_pos = ( uint32_t )( header[ 0x0A ] );
data->compression_method = ( uint8_t )( header[ 0x1E ] );
data->bpp = ( uint8_t )( header[ 0x1C ] );

// TODO (maybe): add support for other compression methods

if ( data->compression_method != CM_RGB )
{
puts( "ERROR: file \"%s\" does NOT have a supported compression method for this parser; \n" \
"\t Currently, the compression methods supported are: \n" \
"\t - BI_RGB \n\n"
);

return 0;
}



return 1;
}

根据从当前图像收集的图像信息,我的调试输出如下所示:
Info for "assets/sprites/nave/nave0001.bmp" {  
Size = 3612 Header Size = 40
Width = 27 Height = 43
Pixel Array Address = 54 Compression Method = 0
Bits Per Pixel = 24
}

最佳答案

首先让我说:您阅读标题的方法几乎是完美的。唯一的缺点:您的代码不处理 Endianess,并且您正在截断标题的字段(对于任何尺寸大于 255 的图像,它都会中断。

这是一个修复

data->image_size = (uint32_t)header[0x22] | (uint32_t)header[0x23] << 8 | (uint32_t)header[0x24] << 16 | (uint32_t)header[0x25] << 24;

大于 8 位的所有其他字段的模式相同。每个 header 字段的强制转换对于防止截断是必要的。将其转换为目标变量类型。也不必担心性能,现代编译器会将其变成非常高效的代码。

到目前为止,您的功能仍然缺乏读取图像数据。我只是假设数据将在一个字段中 data->pixels稍后的。

读入图像后,您可以将其传递给 OpenGL。 OpenGL 在所谓的“纹理对象”中管理其图像。通常的节是:
  • 使用 glGenTextures
  • 创建纹理对象名称
  • 使用 glBindTexture
  • 绑定(bind)纹理对象
  • 在所有 GL_UNPACK_… 参数上使用 glPixelStorei 设置像素传输参数
  • 使用 glTexImage2D 上传纹理
    5.
  • mipmapping

  • 或者
  • 生成 Mipmap。

  • 这如下
    GLuint texName;
    glGenTexture(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);

    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
    glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // could also be set to image size, but this is used only
    glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); // if one wants to load only a subset of the image
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
    glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
    glPixelStorei(GL_UNPACK_SKIP_ALIGNMENT, 4); // that one's pretty important. For TrueColor DIBs the alignment is 4

    GLenum internalformat;
    switch(data->bpp) {
    case 24:
    internalformat = GL_RGB; break;

    case 32:
    internalformat = GL_RGBA; break;
    }

    glTexImage2D(GL_TEXTURE_2D, 0, internalformat,
    data->width, data->height, 0
    GL_BRGA, GL_UNSIGNED_INT_8_8_8_8, data->pixels);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    GL_UNSIGNED_INT_8_8_8_8 类型需要解释。你看,DIB 将 32 位无符号整数视为复合颜色结构。事实上,在 Windows 中,您可以找到一种颜色类型,它是一个类型定义的整数。这就是 DIB 中包含的内容。通过使用具有 4×8 分量整数类型的 BGRA 格式,我们使 OpenGL 以该格式解压缩像素。

    关于c - OpenGL中的位图渲染方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14187783/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com