如何将OpenGL渲染的图片保存到本地(正常渲染和离屏渲染)

关于如何将OpenGL渲染的图片保存到本地

标签(空格分隔):CG opengl

转载请说明出处:http://blog.csdn.net/hust_sheng/article/details/75268056


  • 主要就是使用函数 glReadPixels()

    
    #define BMP_Header_Length 54
    
    
    void saveFrameBuff(const char* fileName)
    {
        FILE* pDummyFile;
        FILE* pWritingFile;
        GLubyte* pPixelData;
        GLubyte BMP_Header[BMP_Header_Length];
        GLint i, j;
        GLint PixelDataLength;
    
        // 因为是窗口渲染,此处设置读取的数据来源于“前端窗口”(也可以是后端,详细见http://blog.csdn.net/hust_sheng/article/details/75268410)
        //glReadBuffer(GL_BACK);
        glReadBuffer(GL_FRONT);
    
        // 计算像素数据的实际长度
        // 默认是3通道
        i = width * 3;      // 得到每一行的像素数据长度
        while (i % 4 != 0)  // 补充数据,直到 i 是的倍数
            ++i;
    
        PixelDataLength = i * height;
    
        // 但这里仅追求直观,对速度没有太高要求PixelDataLength = i * WindowHeight;
        // 分配内存和打开文件
        pPixelData = (GLubyte*)malloc(PixelDataLength);
        if (pPixelData == 0)
            exit(0);
    
        pDummyFile = fopen("ground.bmp", "rb");
        if (pDummyFile == 0)
            exit(0);
    
        pWritingFile = fopen(fileName, "wb");
        if (pWritingFile == 0)
            exit(0);
    
        // 读取像素
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
        glReadPixels(0, 0, width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, pPixelData);
    
        // 把 dummy.bmp 的文件头复制为新文件的文件头
        fread(BMP_Header, sizeof(BMP_Header), 1, pDummyFile);
        fwrite(BMP_Header, sizeof(BMP_Header), 1, pWritingFile);
        fseek(pWritingFile, 0x0012, SEEK_SET);
        i = width;
        j = height;
        fwrite(&i, sizeof(i), 1, pWritingFile);
        fwrite(&j, sizeof(j), 1, pWritingFile);
    
        // 写入像素数据
        fseek(pWritingFile, 0, SEEK_END);
        fwrite(pPixelData, PixelDataLength, 1, pWritingFile);
    
        // 释放内存和关闭文件
        fclose(pDummyFile);
        fclose(pWritingFile);
        free(pPixelData);
    }

    
    
    #define BMP_Header_Length 54
    
    
    static void saveFrameBuff1(const int outImageNo)
    {
        // 因为是离屏渲染,此处设置读取的数据来源于我们自己设置的m_FboID对应的FBO
        glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FboID);
    
        // GPU -> CPU 数据读取异步操作,详细见:http://blog.csdn.net/hust_sheng/article/details/75268410
        glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[0]);
        glReadPixels(0, 0, width, height * 30, GL_BGR_EXT, GL_UNSIGNED_BYTE, 0);
        GLubyte* image_src = (GLubyte*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
    
        if (image_src){
            glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
        }
    
        FILE* pDummyFile;
        FILE* pWritingFile;
        GLubyte BMP_Header[BMP_Header_Length];
    
        //GLubyte* pPixelData;
        GLint i, j, k;
        GLint PixelDataLength;
    
        // 计算像素数据的实际长度
        i = width * 3; // 得到每一行的像素数据长度
        while (i % 4 != 0) // 补充数据,直到 i 是的倍数
            ++i;
    
        PixelDataLength = i * height;
    
        // 同时渲染以及传输多张图片
        for (k = 0; k < 30; k++){
            char outFileStr[OUTIMAGE_FILENAME_LEN];
    
            sprintf_s(outFileStr, 20, "outView_GL%d_x.bmp", outImageNo + 1 - OPENGL_FBO_PARALLELNUM + k);
            pWritingFile = fopen(outFileStr, "wb");
            if (pWritingFile == 0)
                exit(0);
    
            pDummyFile = fopen("ground.bmp", "rb");
            if (pDummyFile == 0)
                exit(0);
    
            // 把 dummy.bmp 的文件头复制为新文件的文件头
            fread(BMP_Header, sizeof(BMP_Header), 1, pDummyFile);
            fwrite(BMP_Header, sizeof(BMP_Header), 1, pWritingFile);
            fseek(pWritingFile, 0x0012, SEEK_SET);
            i = width;
            j = height;
            fwrite(&i, sizeof(i), 1, pWritingFile);
            fwrite(&j, sizeof(j), 1, pWritingFile);
    
            // 写入像素数据
            fseek(pWritingFile, 0, SEEK_END);
    
            fwrite(image_src + width*height * 3 * k, PixelDataLength, 1, pWritingFile);
    
            // 释放内存和关闭文件
            fclose(pDummyFile);
            fclose(pWritingFile);
        }
    }

    上述两段代码,前者是一般的过程,也是窗口渲染的过程,后者是离屏渲染且加上了异步优化。基本的思路都是先读取GPU图片数据,再读取本地的*.bmp文件的头部54个byte的信息,将两者拼接得到新的bmp文件,保存在本地。贴图渲染和异步优化见链接

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值