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;
}

原文地址:https://www.cnblogs.com/mazhenyu/p/1702921.html