• 3D场景画面放大输出的方法[OpenGL]


    需求描述: 普通的OpenGL输出BMP图像的分辨率就是窗口尺寸(w*h),现在要求将窗口场景放大n倍输出分辨率为((w*n)*(h*n))的BMP图像,并且BMP画面内容  要与窗口场景一致。

    需求分析: 首先相机位置不能移动,因为对透视投影来说,同一个物体从不同位置看到的结果是不同的,这样渲染出的场景是无法拼接到一起的。

    功能实现: 思路一:改变ViewPort的大小为原来的n*n倍,起始位置x,y变化,从而得到分块的场景。限制条件就是Viewport的最大值MAX_VIEWPORT跟显卡硬件相关[4096],不能无限放大输出.
                  思路二:改变投影参数,将小块场景投射到整个窗口渲染输出,然后拼接在一起从而实现大分辨率输出。
                  正交投影下实现此功能很简单,只需要分别设置投影的左右上下面的值,分块渲染并得到场景数据(glReadPixels),然后将分块数据合成一个整个的大的BMP输出。
                  透视投影比较复杂,如果当前的投影模式用的是对称投影gluperspective,那么首先要将其转为对应的非对称投影gluFrustum, 根据得到的left,right,top,bottom值分割渲染得到场景数据, 然后将分块数据合成一个整个的大的BMP输出。

    代码实现:

    //// Get the requested extents. 相当于glufrustum的left , right ,top ,bottom, near, far
    int inExtent[4]; //这里似乎不应该是int值

    inExtent[0] = 0;
    inExtent[1] = w*Magnification;
    inExtent[2] = 0;
    inExtent[3] = h*Magnification;

    int inWindowExtent[4];
    // convert the request into windows
    inWindowExtent[0] = inExtent[0]/w;
    inWindowExtent[1] = inExtent[1]/w;
    inWindowExtent[2] = inExtent[2]/h;
    inWindowExtent[3] = inExtent[3]/h;           

    int LineLength, TotalLength;
    int nExtentWidth = abs(inExtent[1]-inExtent[0]);
    int nExtentHeight = abs(inExtent[3]-inExtent[2]);

    LineLength = nExtentWidth * BytesPerPixel; // 每行数据长度大致为图象宽度乘以
    while( LineLength % 4 != 0 ) // 修正LineLength使其为4的倍数
        ++LineLength;
    // 每像素的字节数
    TotalLength = LineLength * abs(inExtent[3]-inExtent[2]); // 数据总长 = 每行长度 * 图象高度

    pData = new unsigned char[TotalLength];    //建立一个大的数据buffer用于写入
    int x,y;
    // render each of the tiles required to fill this request
    int row = 0;
    double cx,cy;
    int offset = 0;
    CString strFilePath;
    for (y = inWindowExtent[2]; y < inWindowExtent[3]; y++)
    {
        int col = 0;
        for (x = inWindowExtent[0]; x < inWindowExtent[1]; x++)
        {
            cx = x*2 - Magnification*(1-windowCenter[0]) + 1;
            cy = y*2 - Magnification*(1-windowCenter[1]) + 1;

            pCamera->SetWindowCenter(cx,cy);

            pMapView->Render();
            // add
            //pView->Render();

            // 读到的是pMainView的图像
            glReadPixels(0,0,w,h,GL_BGR_EXT,GL_UNSIGNED_BYTE,pPixelData);

            //BSTR filename = (col > 0) ? _bstr_t("f:\\test1.bmp") : _bstr_t("f:\\test2.bmp");
            //if (!WriteBmpFile(w,h,pPixelData,filename))
            //    return false;   

            for (int i = 0; i < h; i++)
            {
                offset = row*h*LineLength + col*w*BytesPerPixel + i*LineLength;
                memcpy((unsigned char*)pData+offset,(unsigned char*)pPixelData+(i*nBlockLineLength),nBlockLineValidDataLength);
            }
            col++;
        }           
        row++;
    }   

    // 输出为BMP文件
    if (!WriteBmpFile(nExtentWidth,nExtentHeight,pData,str))
             return S_FALSE;       

     

     

    bool CSaveImageTool::WriteBmpFile(int w, int h, unsigned char *pdata, BSTR filename)//char *pBmpFileName)
    {
        unsigned char header[COLORTABLE] = {

            0x42, 0x4d, 0, 0, 0, 0, 0, 0, 0, 0,

            54, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0,

            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

            0, 0, 0, 0

        };

        long file_size = (long)w * (long)h * 3 + 54;

        header[2] = (unsigned char)(file_size &0x000000ff);

        header[3] = (file_size >> 8) & 0x000000ff;

        header[4] = (file_size >> 16) & 0x000000ff;

        header[5] = (file_size >> 24) & 0x000000ff;

        long width = w;

        header[18] = width & 0x000000ff;

        header[19] = (width >> 8) &0x000000ff;

        header[20] = (width >> 16) &0x000000ff;

        header[21] = (width >> 24) &0x000000ff;

        long height = h;

        header[22] = height &0x000000ff;

        header[23] = (height >> 8) &0x000000ff;

        header[24] = (height >> 16) &0x000000ff;

        header[25] = (height >> 24) &0x000000ff;

        FILE *pWritingFile = NULL;

        //pWritingFile = fopen(pBmpFileName, "wb");
        _bstr_t bFileName = filename;
        char* pBmpFileName = bFileName;
        pWritingFile = fopen(pBmpFileName, "wb");

        if( pWritingFile == NULL )
            return false;

        fwrite(header, sizeof(unsigned char), 54, pWritingFile);

        int BytesPerPixel = 3;
        int LineLength, TotalLength;
        LineLength = w * BytesPerPixel; // 每行数据长度大致为图象宽度乘以
        // 每像素的字节数
        while( LineLength % 4 != 0 ) // 修正LineLength使其为4的倍数
            ++LineLength;
        TotalLength = LineLength * h; // 数据总长 = 每行长度 * 图象高度

        fwrite(pdata, sizeof(unsigned char), (size_t)(long)TotalLength,  pWritingFile);

        // 释放内存和关闭文件    
        fclose(pWritingFile);    

        return true;
    }

  • 相关阅读:
    小内存 linux 主机部署 mysql
    IIS enable HTTP PUT and DELETE
    使用Topshelf部署.net core windows服务 Demo
    Windows Template Studio 创建 .net core wpf应用
    vue笔记——vue生命周期
    (转)idea如何快速查看接口的实现类
    vue项目设置启动自动打开浏览器
    批量添加题目功能(正则表达式的使用案例)
    markdown的diff效果
    SVN提交时取消某个文件的提交
  • 原文地址:https://www.cnblogs.com/mazhenyu/p/1702921.html
Copyright © 2020-2023  润新知