程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 浮動窗體中的OpenGL多視圖的實現

浮動窗體中的OpenGL多視圖的實現

編輯:關於VC++

由於在工作中需要結合浮動窗體實現OpenGL的多視圖,用於得到三維實體的三視圖觀察效果,通過參考其它資料,設計了一個程序框架,在此基礎之上大家可以根據自己的需要進行擴充,實現需要的功能。

本程序中浮動窗體的實現從以下網站得到支持:www.datamekanix.com

程序實現效果圖

關鍵技術實現介紹:

一、OpenGL多視圖的實現

平常我們的程序大部分都是建立一OpenGL設備上下文,但在本程序中,由於要實現三維實體的多視圖觀察功能,因此,需要建立多OpenGL設備上下文,並在需要的時候進行切換。

同一般的OpenGL程序一樣,我們在每個視圖類中都定義了每個視圖所對應的設備描述上下文並在視圖創建的時候建立了這個設備描述上下文。

//add in the header file of view class
public:
CClientDC* m_pDC;
HGLRC m_hRC;
//add in the init() function of view class
m_hRC = wglCreateContext(m_pDC->GetSafeHdc());

接著在某個視圖需要更新的時候(一般在每個視圖的OnDraw()函數中),將這個視圖的設備上下文設為OpenGL當前的渲染上下文(OpenGL Rendering context)

//add in the OnDraw() function of view class
//set current device
wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);

二、視圖類型的切換及當前視圖類型的判斷

由於同一視圖在不同的時刻根據用戶的需要可能有不同的功能,因此需要在幾個視圖之間進行功能的切換。本程序選取一個視圖作為主視圖,而另外兩個視圖作為子視圖。視圖的類有一下幾種:上、下視圖,前、後視圖,左、右視圖。為此設計了枚舉類型變量用於指示視圖的類型。為了保證不同視圖類型之間的有效切換,即不會產生重復的類型,設計了一個類用於操作視圖之間的類型切換。

為了減小程序編制的負擔,所有子視圖共享一個視圖類,而每個視圖的當前類型是存儲在這個視圖類之外的,因此在每個視圖繪制的時候都需要判斷自己的類型。這樣便出現了無法在子視圖類中判斷自己當前的視圖類型的情況。為此在子視圖類中增加了一個成員變量用於記錄自己的類型。

//add in the header file of child view class
//view ID, it will be assigned by parentframe when this program begin
//[childviewA id = 1; childviewB id = 2]
int m_ViewID

然後在程序運行之初,浮動窗體創建之後,對每個浮動窗體所包含的子視圖的類型進行設置。

//add in the OnCreate() function of CMainFrame class
AssignViewID();
//the definition of AssignViewID()
void CMainFrame::AssignViewID()
{
CEdit3DMDoc* pdoc = (CEdit3DMDoc*)m_pMainView->GetDocument();
if(pdoc)
{
POSITION pos = pdoc->GetFirstViewPosition();
CView* pview;
int tempid = 1;
while (pos != NULL)
{
pview = pdoc->GetNextView(pos);
if (pview->IsKindOf(RUNTIME_CLASS(CChildOGLView)))
{
CChildOGLView* pchildview = (CChildOGLView*)pview;
pchildview->m_ViewID = tempid;
tempid += 1;
}
}
}
}

我們看到這裡需要從文檔類中檢索出所有子視圖(CChildOGLView),因此,在子視圖創建的時候需要把自己加入到文檔中。

//add in the OnCreate() function of child view class
AddMetoDoc();
//the definition of AddMetoDoc()
void CChildOGLView::AddMetoDoc()
{
CEdit3DMDoc* pdoc = (CEdit3DMDoc*)GetDocument();
if(pdoc != NULL)
{
pdoc->AddView(this);
}
}

至此,本程序的關鍵功能已經實現,在主視圖和子視圖的繪制函數部分便可以通過判斷當前視圖的類型進行不同內容的繪制。

//in the DrawScene() function of main view
//To get the current view type
ViewType currentviewtype;
CMainFrame* pframe = (CMainFrame*)GetParentFrame();
currentviewtype = pframe->m_ViewArrange.m_MainViewType;
glViewport(0, 0, m_oldRect.right, m_oldRect.bottom);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
CEdit3DMDoc* pdoc = GetDocument();
if(pdoc != NULL)
{
pdoc->m_3DMani.SetProjection(currentviewtype, 0);
pdoc->m_3DMani.DrawBound(currentviewtype);
}
glFinish();
SwapBuffers(wglGetCurrentDC());
//in the DrawScene() function of child view
ViewType currentviewtype;
CMainFrame* pframe = (CMainFrame*)AfxGetMainWnd();
if(m_ViewID == 1)
{
currentviewtype = pframe->m_ViewArrange.m_ChildViewAType;
}
else if(m_ViewID == 2)
{
currentviewtype = pframe->m_ViewArrange.m_ChildViewBType;
}
glViewport(0, 0, m_oldRect.right, m_oldRect.bottom);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
CEdit3DMDoc* pdoc = GetDocument();
if(pdoc != NULL)
{
pdoc->m_3DMani.SetProjection(currentviewtype, 0);
pdoc->m_3DMani.DrawBound(currentviewtype);
}
glFinish();
SwapBuffers(wglGetCurrentDC());

各位讀者可以在此基礎之上根據各自的需要實現不同的功能。需要指出的是,程序中包含了我們在系統開發中所需要的三維實體模型類,你可以對它進行修改或者替換為自己的數據結構,歡迎大家對本文提出建議,期待與大家進行合作!

本文配套源碼

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved