opengl離屏渲染(不需要和視窗繫結,僅當作一個可以渲染一張圖片的API使用)+ opencv顯示
【原文:http://www.csdn123.com/html/itweb/20130919/127140_127126_127133.htm】
具體過程參考的是這篇BLOG:
http://wiki.woodpecker.org.cn/moin/lilin/swig-glBmpContext
這一片BLOG的程式碼有個 BOOL SaveBmp(HBITMAP hBitmap, string FileName) 的函式,功能為儲存成BMP格式的圖片,我的程式碼中也就省去了這部分,用opencv來處理,這樣使得熟悉opencv的人也能比較好了解吧,畢竟Windows的API一些結構體確實看起來比較生澀難懂。
#include <windows.h>
#include <iostream>
#include <gl/gl.h>
#include <gl/glu.h>
#include <string>
#include <time.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
void mGLRender()
{
glClearColor(0.9f,0.9f,0.3f,1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, 1.0, 1.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, -5, 0, 0, 0, 0, 1, 0);
glBegin(GL_TRIANGLES);
glColor3d(1, 0, 0);
glVertex3d(0, 1, 0);
glColor3d(0, 1, 0);
glVertex3d(-1, -1, 0);
glColor3d(0, 0, 1);
glVertex3d(1, -1, 0);
glEnd();
glFlush(); // remember to flush GL output!
}
void mGLRender1()
{
glClearColor(0.3f,0.3f,0.3f,1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, 1.0, 1.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, -5, 0, 0, 0, 0, 1, 0);
glBegin(GL_TRIANGLES);
glColor3d(1, 0, 0);
glVertex3d(0, 1, 0);
glColor3d(0, 1, 0);
glVertex3d(-1, -1, 0);
glColor3d(0, 0, 1);
glVertex3d(1, -1, 0);
glEnd();
glFlush(); // remember to flush GL output!
}
int main(int argc, char* argv[])
{
clock_t clockBegin, clockEnd;
const int WIDTH = 400;
const int HEIGHT = 400;
// Create a memory DC compatible with the screen
HDC hdc = CreateCompatibleDC(0);
if (hdc == 0) cout<<"Could not create memory device context";
// Create a bitmap compatible with the DC
// must use CreateDIBSection(), and this means all pixel ops must be synchronised
// using calls to GdiFlush() (see CreateDIBSection() docs)
BITMAPINFO bmi = {
{ sizeof(BITMAPINFOHEADER), WIDTH, HEIGHT, 1, 32, BI_RGB, 0, 0, 0, 0, 0 },
{ 0 }
};
unsigned char *pbits; // pointer to bitmap bits
HBITMAP hbm = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void **) &pbits,
0, 0);
if (hbm == 0) cout<<"Could not create bitmap";
//HDC hdcScreen = GetDC(0);
//HBITMAP hbm = CreateCompatibleBitmap(hdcScreen,WIDTH,HEIGHT);
// Select the bitmap into the DC
HGDIOBJ r = SelectObject(hdc, hbm);
if (r == 0) cout<<"Could not select bitmap into DC";
// Choose the pixel format
PIXELFORMATDESCRIPTOR pfd = {
sizeof (PIXELFORMATDESCRIPTOR), // struct size
1, // Version number
PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL, // use OpenGL drawing to BM
PFD_TYPE_RGBA, // RGBA pixel values
32, // color bits
0, 0, 0, // RGB bits shift sizes...
0, 0, 0, // Don't care about them
0, 0, // No alpha buffer info
0, 0, 0, 0, 0, // No accumulation buffer
32, // depth buffer bits
0, // No stencil buffer
0, // No auxiliary buffers
PFD_MAIN_PLANE, // Layer type
0, // Reserved (must be 0)
0, // No layer mask
0, // No visible mask
0, // No damage mask
};
int pfid = ChoosePixelFormat(hdc, &pfd);
if (pfid == 0) cout<<"Pixel format selection failed";
// Set the pixel format
// - must be done *after* the bitmap is selected into DC
BOOL b = SetPixelFormat(hdc, pfid, &pfd);
if (!b) cout<<"Pixel format set failed";
// Create the OpenGL resource context (RC) and make it current to the thread
HGLRC hglrc = wglCreateContext(hdc);
if (hglrc == 0) cout<<"OpenGL resource context creation failed";
wglMakeCurrent(hdc, hglrc);
// Draw using GL - remember to sync with GdiFlush()
clockBegin = clock();
mGLRender();
GdiFlush();
//SaveBmp(hbm,"output.bmp");
clockEnd = clock();
printf("%d\n", clockEnd - clockBegin);
clockBegin = clock();
mGLRender1();
GdiFlush();
//SaveBmp(hbm,"output1.bmp");
clockEnd = clock();
printf("%d\n", clockEnd - clockBegin);
/*
Examining the bitmap bits (pbits) at this point with a debugger will reveal
that the colored triangle has been drawn.
*/
//opencv show img
Mat img(HEIGHT,WIDTH,CV_8UC4,(void *)pbits);
imshow("img",img);
waitKey();
destroyWindow("img");
// Clean up
wglDeleteContext(hglrc); // Delete RC
SelectObject(hdc, r); // Remove bitmap from DC
DeleteObject(hbm); // Delete bitmap
DeleteDC(hdc); // Delete DC
system("pause");
return 0;
}
以上的程式碼可以直接編譯執行,記得加上opengl32.lib和glu32.lib(還有加上opencv的配置,如果不需要的話可以直接註釋掉和OpenCV有關的程式碼,原始程式碼可以參考文章開頭給出的blog)
還有值得注意的是pbits指向的是從影象左下角開始,由下至上的畫素點的排列,和opencv的由上至下剛好相反,所以opencv顯示的圖片是水平映象的。
簡單得說吧,要進行離屏渲染,win32下需要做下面的幾個步驟:
1.建立一個記憶體 DC
2.建立一個點陣圖
3.把點陣圖選入DC
4.設定DC的像元格式
5.通過DC建立OpenGL的渲染上下文RC
6.開始渲染.
其中有個GdiFlush()的函式,其作用是提供一個mutex的機制,給GDI objects提供一個保護機制,因為opengl在執行glFlush()繪製的時候,是可以沒有等待繪製完就返回的(可以百度glFlush和glFinish的區別),如果這時候訪問了GDI object可能會訪問的是一個未完成的結果,或者產生讀寫衝突。
MSDN的解釋是這樣的:
An application should call GdiFlush before a thread goes away if there is a possibility that there are pending function calls in the graphics batch queue. The system does not execute such batched functions when a thread goes away.
A multithreaded application that serializes access to GDI objects with a mutex must ensure flushing the GDI batch queue by calling GdiFlush as each thread releases ownership of the GDI object. This prevents collisions of the GDI objects (device contexts, metafiles, and so on).
但是目前為止,還沒發現過使用glFlush和glFinish的差異(難道是現在的顯示卡都太快了,繪製自己寫的場景用的時間很短),如果大家有什麼見解歡迎討論哈。
相關文章
- 從顯示一張圖片開始學習OpenGL ES
- iOS 離屏渲染的研究iOS
- 關於UI事件傳遞,影像顯示,效能優化,離屏渲染UI事件優化
- go語言遊戲程式設計-Ebiten渲染一張圖片Go遊戲程式設計
- iOS效能優化中的離屏渲染iOS優化
- iOS介面卡頓之離屏渲染iOS
- OpenGL/OpenGL ES入門: 影象渲染實現以及渲染問題
- 一個簡易的渲染迴圈結構
- iOS 和常見的離屏渲染Say Goodbye!iOSGo
- (一)opencv 視屏讀寫OpenCV
- Android字型渲染器——使用OpenGL ES進行高效文字渲染Android
- win10系統開機鎖屏介面只顯示一張圖片不顯示日期時間如何解決Win10
- Stats渲染資料統計視窗
- 如何使用 Javascript 將圖示字型渲染為圖片JavaScript
- opencv圖片上如何顯示兩個小圖片OpenCV
- OpenGL實現GPU體渲染GPU
- 一張圖瞭解瀏覽器渲染頁面的過程瀏覽器
- 一文詳解 OpenGL ES 3.x 渲染管線
- 在Unity中渲染一個黑洞Unity
- Opengl ES之YUV資料渲染
- 教你實現GPUImage【OpenGL渲染原理】GPUUI
- IDEA整個視窗不顯示Idea
- blender python api 使用指令碼對一個靜幀 進行全方位渲染PythonAPI指令碼
- 實現一個前向渲染的Phong模型(一)模型
- OpenGL的渲染成紋理技術(轉)
- Echarts自適應:當視窗大小發生變化時,重新渲染圖表Echarts
- 大文件首屏渲染的一些思考和嘗試
- 離屏Canvas——製作水印圖片Canvas
- Python opencv 將一張圖片任意 N 等分並儲存_opencv 等分影像PythonOpenCV
- 如何在Mac上的一個“預覽”視窗中顯示若干檔案呢?Mac
- 如何在mfc對話方塊中新增一個顯示網頁的視窗 .網頁
- 這是一個可以顯示Linux命令的工具Linux
- qt視窗居中顯示QT
- 通過OpenGL理解前端渲染原理(1)前端
- GitHub#C#:在終端裡面顯示一個UI視窗(TerminalGfx)GithubC#UI
- iOS 效能優化思路:介面離屏渲染、圖層混色iOS優化
- table列表渲染時,內容要渲染多個值且包含圖示
- Vue 動態繫結圖片 src 屬性閃屏 白屏 無內容顯示 BUG 小記Vue