想必不少人都見過DDS這種文件,它是一個「圖片文件」,若是你安裝了某些看圖軟件,你能夠直接雙擊打開它來進行預覽。windows
那麼,這種DDS文件和咱們常見的TGA/PNG之類的文件有何不一樣呢?ide
DDS和TGA/PNG/JPG之類的「圖片文件」 同樣,支持「壓縮」,減小磁盤空間佔用(把文件變小)。函數
一般咱們要加載一個TGA或者PNG文件到OpenGL的時候,都要先把文件數據還原成RGB格式的像素數據,而後用glTexImage2D把像素數據傳到顯存。這個過程至關於「解壓」,這一般很是消耗CPU資源,速度較慢。工具
可是DDS的壓縮數據不須要「解壓」就能直接傳到顯存,並且傳到顯存以後也不會解壓,這極大減小了顯存的使用量,而且提升了紋理加載速度,有絕對的優點。咱們只須要讀取好壓縮數據,而後使用glCompressedTexImage2D(代替glTexImage2D)就能夠直接把壓縮數據傳到顯存,完成加載。oop
DDS能夠保存許多種格式的像素數據,這裏只講最經常使用的3種(DXT一、DXT三、DXT5)。ui
* 固然DDS文件也能存儲不壓縮的像素數據。spa
爲了在OpenGL中使用DDS壓縮紋理(下文簡稱壓縮紋理),咱們須要一下2個OpenGL擴展:code
GL_ARB_texture_compression
提供函數 「glCompressedTexImage2D」orm
GL_EXT_texture_compression_s3tc
提供如下格式的壓縮紋理支持:
GL_COMPRESSED_RGB_S3TC_DXT1_EXT
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
GL_COMPRESSED_RGBA_S3TC_DXT5_EXTblog
完整的加載過程代碼:
#include <stdio.h> #include <gl/glut.h> #include <gl/glext.h> // Minimum and maximum macros #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB = NULL; #pragma region DDS #define DDPF_ALPHAPIXELS 0x000001 #define DDPF_ALPHA 0x000002 #define DDPF_FOURCC 0x000004 #define DDPF_RGB 0x000040 #define DDPF_YUV 0x000200 #define DDPF_LUMINANCE 0x020000 #define D3DFMT_DXT1 (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24)) #define D3DFMT_DXT3 (('D'<<0)|('X'<<8)|('T'<<16)|('3'<<24)) #define D3DFMT_DXT5 (('D'<<0)|('X'<<8)|('T'<<16)|('5'<<24)) typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwFourCC; DWORD dwRGBBitCount; DWORD dwRBitMask; DWORD dwGBitMask; DWORD dwBBitMask; DWORD dwABitMask; } DDS_PIXELFORMAT; #define DDSD_CAPS 0x000001 #define DDSD_HEIGHT 0x000002 #define DDSD_WIDTH 0x000004 #define DDSD_PITCH 0x000008 #define DDSD_PIXELFORMAT 0x001000 #define DDSD_MIPMAPCOUNT 0x020000 #define DDSD_LINEARSIZE 0x080000 #define DDSD_DEPTH 0x800000 typedef struct { DWORD dwSize; DWORD dwFlags; DWORD dwHeight; DWORD dwWidth; DWORD dwPitchOrLinearSize; DWORD dwDepth; DWORD dwMipMapCount; DWORD dwReserved1[11]; DDS_PIXELFORMAT ddspf; DWORD dwCaps; DWORD dwCaps2; DWORD dwCaps3; DWORD dwCaps4; DWORD dwReserved2; } DDS_HEADER; typedef struct { DWORD dwMagic; DDS_HEADER Header; } DDS_FILEHEADER; // For a compressed texture, the size of each mipmap level image is typically one-fourth the size of the previous, with a minimum of 8 (DXT1) or 16 (DXT2-5) bytes (for // square textures). Use the following formula to calculate the size of each level for a non-square texture: #define SIZE_OF_DXT1(width, height) ( max(1, ( (width + 3) >> 2 ) ) * max(1, ( (height + 3) >> 2 ) ) * 8 ) #define SIZE_OF_DXT2(width, height) ( max(1, ( (width + 3) >> 2 ) ) * max(1, ( (height + 3) >> 2 ) ) * 16 ) #pragma endregion GLuint gl_load_dds(GLvoid *pBuffer) { DDS_FILEHEADER *header; DWORD compressFormat; GLuint texnum; GLvoid *data; GLsizei imageSize; header = (DDS_FILEHEADER *)pBuffer; if (header->dwMagic != 0x20534444) { printf("bad dds file\n"); return 0; } if (header->Header.dwSize != 124) { printf("bad header size\n"); return 0; } if (!(header->Header.dwFlags & DDSD_LINEARSIZE)) { printf("bad file type\n"); return 0; } if (!(header->Header.ddspf.dwFlags & DDPF_FOURCC)) { printf("bad pixel format\n"); return 0; } compressFormat = header->Header.ddspf.dwFourCC; if (compressFormat != D3DFMT_DXT1 && compressFormat != D3DFMT_DXT3 && compressFormat != D3DFMT_DXT5) { printf("bad compress format\n"); return 0; } data = (GLvoid *)(header + 1); // header data skipped glGenTextures(1, &texnum); glBindTexture(GL_TEXTURE_2D, texnum); switch (compressFormat) { case D3DFMT_DXT1: imageSize = SIZE_OF_DXT1(header->Header.dwWidth, header->Header.dwHeight); glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, header->Header.dwWidth, header->Header.dwHeight, 0, imageSize, data); break; case D3DFMT_DXT3: imageSize = SIZE_OF_DXT2(header->Header.dwWidth, header->Header.dwHeight); glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, header->Header.dwWidth, header->Header.dwHeight, 0, imageSize, data); break; case D3DFMT_DXT5: imageSize = SIZE_OF_DXT2(header->Header.dwWidth, header->Header.dwHeight); glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, header->Header.dwWidth, header->Header.dwHeight, 0, imageSize, data); break; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); return texnum; } GLuint g_texnum; void load_textures(void) { FILE *fp; int size; void *data; fp = fopen("028_dxt5.dds", "rb"); if (!fp) { return; } fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); data = malloc(size); if (!data) { fclose(fp); return; } if (fread(data, size, 1, fp) != 1) { free(data); fclose(fp); return; } fclose(fp); // Load DDS to GL texture g_texnum = gl_load_dds(data); free(data); } void init(void) { // GL_ARB_texture_compression // GL_EXT_texture_compression_s3tc glCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)wglGetProcAddress("glCompressedTexImage2DARB"); load_textures(); glClearColor(0, 0, 0, 0); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); RECT rc; rc.left = 10; rc.top = 10; rc.right = rc.left + 1280; rc.bottom = rc.top + 720; glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, g_texnum); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(1, 1, 1, 1); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(rc.left, rc.top); glTexCoord2f(1, 0); glVertex2f(rc.right, rc.top); glTexCoord2f(1, 1); glVertex2f(rc.right, rc.bottom); glTexCoord2f(0, 1); glVertex2f(rc.left, rc.bottom); glEnd(); glutSwapBuffers(); glutPostRedisplay(); } void reshape(int width, int height) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, width, height, 0); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, width, height); } int main(int argc, char **argv) { glutInitWindowPosition(200, 200); glutInitWindowSize(10+1280+10, 10+720+10); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutCreateWindow("OpenGL DDS"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; }
關於如何製做一個DDS文件,可使用Nvidia提供的DXT工具,下載地址:
https://developer.nvidia.com/legacy-texture-tools http://pan.baidu.com/s/1pKKRL3P
如下是文件大小對比:
如下是圖像質量對比:
原圖(TGA,無壓縮):
DXT1(壓縮比:1/8,無Alpha通道,但能夠單色透明):
DXT3(壓縮包:1/4,Alpha通道還原較差):
DXT5(壓縮比:1/4,Alpha通道還原較好):
參考:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb943990(v=vs.85).aspxhttp://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression.txthttp://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_compression_s3tc.txt