在现代计算机图形学中,3D图形的渲染和交互是两个非常重要的领域。本文将介绍如何使用MFC(Microsoft Foundation Classes)和OpenGL来实现3D图形的显示、渲染加速、线框叠加、平滑细分以及鼠标交互。
VRML(Virtual Reality Modeling Language)是一种用于描述三维交互式矢量图形的语言。在MFC应用程序中,可以通过解析VRML文件来构建3D场景。这个过程涉及到读取文件、解析文件中的节点和属性,以及将这些信息转换为OpenGL可以理解的格式。
显示列表是OpenGL提供的一种优化渲染性能的技术。通过将一系列的OpenGL命令编译成一个列表,然后在渲染循环中调用这个列表,可以显著提高渲染效率。
创建显示列表的一般步骤如下:
int list = glGenLists(1); // 请求一个空闲的ID号
glNewList(list, GL_COMPILE_AND_EXECUTE); // 开始编译列表
glBegin(GL_TRIANGLES); // 开始绘制三角形
// 标准OpenGL调用,填充顶点、法线、颜色等
glEnd();
glEndList(); // 结束列表
使用显示列表的一般步骤如下:
if(glIsList(list) == GL_TRUE) {
glCallList(list); // 调用显示列表
}
在3D网格类中,每个网格都包含一个列表编号,当网格被修改时,可以通过标志位来重新构建列表。
有时候,希望在平滑着色的网格上叠加线框,以便于观察网格的结构。这可以通过OpenGL的glPolygonOffset命令来实现,该命令可以创建一个z-buffer偏移。
渲染场景时,如果需要叠加线框,可以进行两次渲染:第一次使用光照平滑模式渲染网格,第二次关闭光照,设置线框模式,并设置z-buffer偏移,然后再次绘制网格。
为了改善3D网格的几何外观,可以使用Charles Loop平滑细分算法。该算法将每个三角形细分为四个三角形,并通过过滤函数来平滑网格。
在文档中,可以通过调用CMeshDoc类的OnMeshLoop方法来实现平滑细分。
void CMeshDoc::OnMeshLoop() {
BeginWaitCursor();
int NbObject = m_SceneGraph.NbObject();
for(int i = 0; i < NbObject; i++) {
CObject3d *pObject3d = m_SceneGraph[i];
if(pObject3d->GetType() == TYPE_MESh2D) {
CMesh2d *pMesh = (CMesh2d *)pObject3d;
pMesh->SubdivisionLoop();
}
}
UpdateAllViews(NULL);
EndWaitCursor();
}
通过平滑细分,可以看到网格的视觉效果得到了显著提升。
在3D视图中,鼠标交互是非常重要的。可以通过在视图中插入一些变量和命令来实现鼠标交互。
例如,左键按下时可以进行x/y平移,右键按下时可以进行z轴平移。鼠标移动时,如果同时按下左右键,可以进行旋转。
void CMeshView::OnLButtonDown(UINT nFlags, CPoint point) {
m_LeftButtonDown = TRUE;
m_LeftDownPos = point;
SetCapture();
CView::OnLButtonDown(nFlags, point);
}
void CMeshView::OnMouseMove(UINT nFlags, CPoint point) {
if(m_LeftButtonDown && m_RightButtonDown) {
// 旋转操作
}
else if(m_LeftButtonDown) {
// x/y平移操作
}
else if(m_RightButtonDown) {
// z轴平移操作
}
CView::OnMouseMove(nFlags, point);
}