【问题标题】:DDS file loader in OpenGL, corrupted imagesOpenGL中的DDS文件加载器,损坏的图像
【发布时间】:2015-02-24 10:26:34
【问题描述】:

我编写了一个简单的程序,它使用“glCompressedTexImage2D”函数在 OpenGL 中加载压缩和 mipmap 的 DDS 文件。我只使用 DXT1、DXT3 或 DXT5 文件格式。在某些 DDS 文件上效果很好,在其他文件上,部分或大部分 mipmap 已损坏。我比较了一个有效的 dds 文件与一个损坏且标题相同的 dds 文件。这些图像是一个完美的正方形 512x512。有几次我会采用损坏的 dds,转换为几种不同的格式,也许执行轻微的高斯模糊,将其改回 dds,然后它工作得很好,没有损坏。有谁知道我做错了什么?对于 OpenGL,是否有更好的压缩绑定替代 DDS 文件?

I32 DDSFileDecoder::BindDDSFile(const I8 *name)
{
FILE *dds_file;
DDSHeader header;
I32 image_x = 0;
I32 image_y = 0;
I32 image_z = 0;
I32 mipmap_x = 0;
I32 mipmap_y = 0;
I32 factor = 0;
U32 divide = 1;
U32 blocks = 1;
U32 internal_format = 0;
B8 is_compressed = false;
B8 has_alpha_element = false;
B8 is_mipmap = false;
B8 is_cubemap = false;
I32 mipmap_count = 0;
DDS_TYPE dds_type;
U32 handle = 0;

// Open DDS file name
fopen_s(&dds_file, name, "r");
if (dds_file == NULL)
    return -1;

// Read in the DDS Header data
fread(&header, sizeof(header), 1, dds_file);

// DDS Magic must be for little Endian " SDD", Big Endian "DDS "
ASSERT(header.dds_magic == DDS_MAGIC_LITTLE_ENDIAN, "DDS Magic Number Invalid!\n");

// Header size must be 124 bytes long
ASSERT(header.dds_size == 124, "DDS Size Number Invalid!\n");

// Header flags must contain 0x1007 A texture file.
ASSERT((header.dds_flags & DDS_HEADER_FLAGS_TEXTURE) == DDS_HEADER_FLAGS_TEXTURE, "DDS is not a Texture!\n");

// Pixel Format must be 32 bytes
ASSERT(header.dds_pixel_format.dds_size == 32, "DDS Pixel Format Invalid!\n");

// Is the DDS Compressed
is_compressed = ((header.dds_pixel_format.dds_flags & DDPF_FOURCC) != 0);

// Does the DDS have an alpha element
has_alpha_element = ((header.dds_pixel_format.dds_flags & DDPF_ALPHAPIXELS) != 0);

// Is the DDS a mipmap
is_mipmap = ((header.dds_caps1 & DDSCAPS_MIPMAP) && (header.dds_mipmap_count > 1));
if (is_mipmap == true)
    mipmap_count = header.dds_mipmap_count;
else
    mipmap_count = 1;

// Is the DDS a cubemap
is_cubemap = (header.dds_caps2 & DDSCAPS2_CUBEMAP);

// Obtain Image width and height
image_x = header.dds_width;
image_y = header.dds_height;
image_z = header.dds_depth;

//Determine DDS type (note: Only going to support DXT1, DXT3, or DXT5)
if ((header.dds_pixel_format.dds_flags & DDPF_FOURCC) != 0)
{
    if (header.dds_pixel_format.dds_fourCC == D3DFMT_DXT1)
    {
        dds_type = DDS_DXT1;
        divide = 4;
        blocks = 8;
        factor = 4;
        internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1;
    }
    else if (header.dds_pixel_format.dds_fourCC == D3DFMT_DXT3)
    {
        dds_type = DDS_DXT3;
        divide = 4;
        blocks = 16;
        factor = 4;
        internal_format = GL_COMPRESSED_RGBA_S3TC_DXT3;
    }
    else if (header.dds_pixel_format.dds_fourCC == D3DFMT_DXT5)
    {
        dds_type = DDS_DXT5;
        divide = 4;
        blocks = 16;
        factor = 4;
        internal_format = GL_COMPRESSED_RGBA_S3TC_DXT5;
    }
    else
    {
        ASSERT(false, "Attempting to Bind unsupported DDS format\n");
        dds_type = UNKNOWN;
    }
}
else
{
    ASSERT(false, "Attempting to Bind unsupported DDS format\n");
    dds_type = UNKNOWN;
}

// Set up Mipmap x and y
mipmap_x = image_x;
mipmap_y = image_y;

glBindTexture(GL_TEXTURE_2D, 0);
glGenTextures(1, &handle);
glBindTexture(GL_TEXTURE_2D, handle);

// In the event mipmap is missing, set to texture max quality
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmap_count - 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

if (is_compressed == true)
{
    image_was_bound = true;

    U32 size = Max(1, ((mipmap_x + 3) / divide)) * Max(1, ((mipmap_y + 3) / divide)) * blocks * factor;
    U32 offset = 0;

    if (dds_was_startup == false)
        Startup(size);

    fread(&(data[0]), 1, size, dds_file);

    for (U32 i = 0; i < mipmap_count; i++)
    {
        size = Max(1, ((mipmap_x + 3) / divide)) * Max(1, ((mipmap_y + 3) / divide)) * blocks;

        extensions->glCompressedTexImage2D(GL_TEXTURE_2D, i, internal_format, mipmap_x, mipmap_y, 0, size, &data[offset]);

        offset += size;

        mipmap_x >>= 1;
        mipmap_y >>= 1;

    }

    Shutdown();
}
else
{
    ASSERT(false, "Texture is not compressed!\n");
    return -1;
}

return handle;

} // 结束 BindDDSFile

【问题讨论】:

  • 如果您提供“错误”文件的样本,可能会有所帮助。 DXT1/3/5 的偏移计算看起来是正确的,但 DDS 可以容纳非常广泛的格式变化。
  • 不幸的是,Stackoverflow 不允许我发布任何图片,因为我的分数太低。也许是我用来生成 dds 文件的程序是问题所在。我正在使用一个名为“paint.net 4.0.5”的程序。我无法让 GIMP 中的 DDS 扩展工作。
  • 但可以将图片上传到 dropbox/googledrive/whatever 并为您的问题添加链接。

标签: opengl dds-format


【解决方案1】:

这更像是一种解决方法而不是答案。我发现通过将损坏的图像转换为 jpeg 然后稍微降低质量,然后转换为 mipmapped DDS,似乎可以解决问题。

【讨论】:

  • 我把它提高了 50%。现在大多数 DDS 文件都在工作,但我仍然有 25% 的时间文件损坏。我“读取”整个 dds 文件、标题和所有内容,然后将偏移量设置为 128。我将其发送到“glCompressedTexImage2D”。我也尝试使用“glCompressedTexSubImage2D”,但结果完全相同。我尝试使用几种不同的 DDS 转换,结果相同。
猜你喜欢
  • 2018-01-28
  • 2020-05-20
  • 1970-01-01
  • 2020-07-03
  • 1970-01-01
  • 2015-12-11
  • 2010-12-15
  • 2012-08-03
  • 2012-06-21
相关资源
最近更新 更多