• 纹理压缩


    在OpenGL中使用纹理压缩

    OpenGL 2008-07-14 18:08:45 阅读25 评论0   字号: 订阅

     纹理压缩技术已经广泛应用在各种3D游戏之中,它们包括:DXTC(Direct X Texture Compress,DirectX纹理压缩,以S3TC为基础)、S3TC(S3 Texture Compress,S3纹理压缩,仅支持S3显卡)、VTC(Volume Texture Compression,体积纹理压缩)、PTC(Palletized Texture Compression,并行纹理压缩)、VQTC(Vector-Quantization Texture Compression,向量纹理压缩)、YAB NCTC(Narrow Channel Texture compression,狭窄通道纹理压缩)、FXT 1。下面,我为各位介绍OpenGL中使用纹理压缩的两种主要方法:ARB纹理技术扩展和S3TC。

    一、概述

      与其它压缩技术一样,ARB可以把高分辨率纹理放入未压缩前只能存储低分辨率纹理的空间,并提供渲染管道优化,特点有:

    - 增加渲染速度

    - 减低纹理内存需求

    - 快速纹理下载到纹理内存

    - 低磁盘存储空间需求和高速磁盘存取

    纹理压缩通常分为纹理生成层和运行时间层二部分,纹理生成又分成两种方法:

    - 通常方法:使用GL来压缩图像,存储到磁盘

    - S3TC DDS文件格式:使用ISV的S3TC压缩工具来处理图像,在GL中载入DDS文件

    运行时间层的主要工作分三步:

    - 从磁盘载入压缩图像

    - 上载压缩图像到GL

    - 不压缩动态纹理

    二、具体过程

      最理想的压缩纹理技术是在游戏的开头画面预压缩所有的纹理,减少磁盘存储需要,加速纹理载入速度。下面是用两种不同的方法处理纹理位图,第一种方法使用OpenGL压缩,第二种使用直接支持OpenGL的ISV S3TC文件格式。

    ARB允许未压缩的纹理通过glTexImage2D呼叫来进行纹理压缩,并设置内部格式参数。图1的上半部分为常规方式,下半部分为S3TC扩展集,基本内部格式通过压缩后将变成压缩内部格式。

    1、常规压缩

      使用代理纹理可以在压缩前指示欲压缩的纹理图像,然后再以glGetTexLevelParameteriv加上$#@60;pname$#@62;到GL_TEXTURE_COMPRESSED_ARB,来检查图像是否进行适当的压缩。如果纹理已经得到正确处理,会返回一个非零参量,若是纹理压缩出错,则变回相应的基本内部格式。

      使用普通压缩内部格式,查询OpenGL会自动选择内部格式作为$#@60;internalFormat$#@62;,具体过程是 鰃lGetTexLevelParameteriv再加上$#@60;pname$#@62;参数,变成GL_TEXTURE_INTERNAL_FORMAT。

      下一步,查询OpenGL会通过glGetTexLevelParameteriv呼叫获得压缩纹理图像的容量,然后用$#@60;pname$#@62;生成GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB,建立返回尺寸的缓冲区。glGetCompressedTexImageARB呼叫可取得压缩纹理数据,再用$#@60;img$#@62;取得缓冲区地址。压缩纹理到磁盘后,OpenGL会把下列属性加入到压缩纹理本身之中,以备运行时间层调用,属性包括:

    - 缓冲区容量

    - 压缩内部格式

    - 宽度

    - 高度

    - 边界$#@60;border$#@62;(非S3TC)

    - 深度$#@60;depth$#@62;(3D纹理和非S3TC技术)

      如果使用S3TC,压缩内部格式完成时,$#@60;border$#@62;将变设置为零。这意味着$#@60;border$#@62;不为零会导致“glCompressedTexImage2DARB”发生“INVALID_OPERATION(内部操作)”错误。若是图像仅适用于2D纹理,$#@60;depth$#@62;与S3TC格式无关,一旦$#@60;internalFormat$#@62;(内部格式)变成了S3TC,“glCompressedTexImage1DARB”和“glCompressedTexImage3DARB”会生成“INVALID_ENUM”错误。

      在另一平台使用压缩纹理,压缩内部格式不属于标准的话,必须让平台支持特殊的格式。比如用

    “glGetIntegerv”呼叫加上“GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB”和“GL_COMPRESSED_TEXTURE_FORMATS_ARB”。下面是一段支持压缩内部格式的代码:

    GLint * compressed_format;

    GLint num_compressed_format;

    glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, &num_compressed_format);

    compressed_format = (GLint*)malloc(num_compressed_format * sizeof(GLint));

    glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS_ARB, compressed_format);

      S3TC无须列出所支持的格式,也不用特殊的扩展集,因此S3TC不提供“GL_COMPRESSED_RGBA_S3TC_DXT1_EXT”格式,所有变化都会被自动认成是“正常”的RGBA格式。

    随后的语句概括了压缩未压缩图像和把它存储进硬盘的过程:

    glBindTexture(GL_TEXTURE_2D, compressed_decal_map);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_ARB, width, height,

    0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);

    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB, &compressed);

    /* if the compression has been successful */

    if (compressed == GL_TRUE)

    {

    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT,

    &internalformat);

    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB,

    &compressed_size);

    img = (unsigned char *)malloc(compressed_size * sizeof(unsigned char));

    glGetCompressedTexImageARB(GL_TEXTURE_2D, 0, img);

    SaveTexture(width, height, compressed_size, img, internalFormat, 0);

    }

      有多种方法可以评估压缩扩展集的画质,比如:图像质量参数RED_BITS, GREEN_BITS等,或压缩纹理映象,或用glGetTexImage呼叫存取非压缩图像缓冲区。

    2、S3TC DDS文件格式

      ISV工具(如:S3的Adobe PhotoShop Plug-in插件和微软DirectX的Dxtex)可以把普通文件格式转换成dds文件。故名思义,DDS(Direct Draw Surface,直接绘画表面)的基本操作是把内存的数据通过DirectX DDS接口下载到硬盘。DDS文件读取程度包含在DirectX的ddraw.h中,还可以得到DDSURFACEDESC2定义。此外,DirectX的架构与OpenGL不同,其屏幕原始坐标也不一样,DirectX的原始屏幕坐标位于左上角,OpenGL则位于左下角。在转换图像或纹理调整之前,必须改变纹理的垂直方向。

    下面是一段DDS读取程序的源码:

    #include $#@60;ddraw.h$#@62;

    gliGenericImage *

    ReadDDSFile(const char *filename, int * bufsize, int * numMipmaps)

    {

    gliGenericImage *genericImage;

    DDSURFACEDESC2 ddsd;

    char filecode[ 4];

    FILE *fp;

    /* try to open the file */

    fp = fopen(filename, "rb");

    if (fp == NULL)

    return NULL;

    /* verify the type of file */

    fread(filecode, 1, 4, fp);

    if (strncmp(filecode, "DDS ", 4) != 0) {

    fclose(fp);

    return NULL;

    }

    /* get the surface desc */

    fread(&ddsd, sizeof(ddsd), 1, fp);

    genericImage = (gliGenericImage*) malloc(sizeof(gliGenericImage));

    memset(genericImage,0,sizeof(gliGenericImage));

    /* how big is it going to be including all mipmaps? */

    *bufsize = ddsd.dwMipMapCount $#@62; 1 ? ddsd.dwLinearSize * 2 : ddsd.dwLinearSize;

    genericImage-$#@62;pixels = (unsigned char*)malloc(*bufsize * sizeof(unsigned char));

    fread(genericImage-$#@62;pixels, 1, *bufsize, fp);

    /* close the file pointer */

    fclose(fp);

    genericImage-$#@62;width = ddsd.dwWidth;

    genericImage-$#@62;height = ddsd.dwHeight;

    genericImage-$#@62;components = (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1) ? 3 : 4;

    *numMipmaps = ddsd.dwMipMapCount;

    switch(ddsd.ddpfPixelFormat.dwFourCC)

    {

    case FOURCC_DXT1:

    genericImage-$#@62;format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;

    break;

    case FOURCC_DXT3:

    genericImage-$#@62;format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;

    break;

    case FOURCC_DXT5:

    genericImage-$#@62;format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;

    break;

    default:

    free(genericImage-$#@62;pixels);

    free(genericImage);

    return NULL;

    }

    /* return data */

    return genericImage;

    }

      当DDS文件被看成是MIP映射时,它会压缩所有的映射图像,此问题通常发生于GL在一段时间内取出一个映射的时候。DDS文件的缓冲区读取不能直接由GL控制,你必须精确计算每一个MIP映射在缓冲区的偏移量,传递正确的数据地址和属性给

    glCompressedTexImage2DARB,代码如下:

    /* load the .dds file */

    ddsimage = ReadDDSFile("flowers.dds",&ddsbufsize,&numMipmaps);

    height = ddsimage-$#@62;height;

    width = ddsimage-$#@62;width;

    offset = 0;

    div = (ddsimage-$#@62;format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 1 : 0;

    glBindTexture(GL_TEXTURE_2D, dds_compressed_decal_map);

    /* load the mipmaps */

    for (i = 0; i $#@60; numMipmaps && (width $#@62; 1 && height $#@62; 1); ++i)

    {

    size = width * height;

    size $#@62;$#@62;= div;

    glCompressedTexImage2DARB(GL_TEXTURE_2D, i, ddsimage-$#@62;format, width, height,

    0, size, ddsimage-$#@62;pixels + offset);

    GLErrorReport();

    offset += size;

    width $#@62;$#@62;= 1;

    height $#@62;$#@62;= 1;

    }

      最后,大家会注意到微软的DirectX SDK DXTex工具提供了把立体位图(带MIP映射)压缩到单个DDS文件的能力。因为DirectX围绕一个立体位图需要的所有数据而设计,压缩非常容易实现,而且DDS文件阅读器还能按照位图的不同自由定制。如果一个立体位图与DirectX相匹配,那么,它也能够用在OpenGL身上。

  • 相关阅读:
    less的安装使用
    bootStrap
    响应式布局——媒体查询
    发光渐变器
    好看的按钮
    CSS3:2D、3D属性
    CSS3渐变
    background
    过渡transition、opacity的兼容性
    【未完成】【java异常】java.lang.IllegalStateException: No suitable default RequestUpgradeStrategy
  • 原文地址:https://www.cnblogs.com/lizhengjin/p/1917409.html
Copyright © 2020-2023  润新知