欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenGL:使用FBO为渲染对象并从GPU取出存图

程序员文章站 2022-07-04 11:37:34
...

OpenGL 使用FBO为渲染对象并从GPU取出存图的代码

#include "gl/glew.h"
#include "gl/glut.h"
#include <fstream>
#define isize 512
const char* vertexShaderSource = "#version 460 \n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char* fragmentShaderSource = "#version 460 \n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(0.0f, 1.0f, 1.0f, 1.0f);\n"
"}\n\0";

void saveToBMP24(void* packBuffer, const std::string& img);
int main(int argc, char** argv)
{
    argc;argv;

    
    //初始化窗口以及渲染上下文


    //创建viewport
    int iViewportIndex = 0;
    float fv4Viewport[4] = {0.0f,0.0f,512.0f,512.0f};
    glViewportIndexedfv(iViewportIndex, fv4Viewport);
    //创建FBO绑定的纹理
    GLuint texName;
    glGenTextures(1, &texName);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texName);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, GLint(0), GL_RGBA, isize, isize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    
    //创建FOB
    GLuint FramebufferName;
    glGenFramebuffers(1, &FramebufferName);
    glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texName, 0);
    
    //三角形的三个顶点数据
    float vertices[] = {
        -0.5f, -0.5f, 0.0f, // left  
        0.5f, -0.5f, 0.0f, // right 
        0.0f, 0.5f, 0.0f  // top   
    };

    //创建VAO VBO 
    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    //初始化program,shader
    int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    //清背景
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    //设置绘制buffer,数组形式设置
    GLuint a[] = { GL_COLOR_ATTACHMENT0 };
    glDrawBuffers(1, a);
    glUseProgram(shaderProgram);
    //绑定VAO
    glBindVertexArray(VAO);
    //绘制三角形
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    //备份
    int iOldPixelPackAlignment(1);
    glGetIntegerv(GL_PACK_ALIGNMENT, &iOldPixelPackAlignment);
    //设置新的对齐
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    //绑定fbo,读取数据
    glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferName);
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    void* pImage = new char[isize * isize * 4];
    glReadPixels(0, 0, isize, isize,
        GL_RGBA, GL_UNSIGNED_BYTE, pImage);
    glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
    //存图 bmp格式
    saveToBMP24(pImage, "/usr/sss1.bmp");
  
    return 0;
}



void saveToBMP24(void* packBuffer, const std::string& img)
{
    using namespace std;
    //读入一个bmp格式文件,创建头用,todo:尺寸和位数对应
    fstream in("/usr/123.bmp", ios_base::in | ios_base::binary);
    if (!in)
    {
        return;
    }
    char bmpHeader[54] = { 0 };
    in.read(bmpHeader, sizeof(bmpHeader));

    char* pBuffer = new char[isize * isize *3];
    in.read(pBuffer, isize * isize * 3);
    in.close();
    
    fstream out(img.c_str(), ios_base::out | ios_base::binary | ios_base::trunc);
    if (!out)
    {
        in.close();
        delete[] pBuffer;
        return;
    }
    
    //RGB数据拷贝,A丢弃
    for (size_t i = 0; i < isize*isize; i++)
    {
        int num = i * 4;
        int numI = i * 3;
        pBuffer[numI] = ((char*)packBuffer)[num + 2];
        pBuffer[numI+1] = ((char*)packBuffer)[num + 1];
        pBuffer[numI+2] = ((char*)packBuffer)[num ];
    }

    *((int*)&bmpHeader[0x12]) = isize;
    *((int*)&bmpHeader[0x16]) = isize;
    
    //bmp对齐
    int totals = (isize) * 3;
    while (totals % 4 != 0)
        ++totals;
    totals = totals * (isize);
    out.write(bmpHeader, sizeof(bmpHeader));
    
    out.write(pBuffer, totals);
    out.close();
    delete[]pBuffer;
}