在第3章中,用到了GLU.gluOrtho2D来定义二维显示。在三维显示中需要用到投影的概念。对于计算机屏幕来说,三维物体实际还是以二维平面的形式在显示,因此需要对三维物体进行二维投影变换。变换的方式有透视投影和正投影两种。透视投影与日常生活中看物体一样,同样大小的物体,近处看,大一些;远处看,小一些。而正投影则没有这样的效果,物体的远近显示都一样。在计算机辅助设计软件开发中,我们不希望视景的远近对物体尺寸、角度等产生显示偏差,因此往往会采用正投影的方式。正投影的创建函数是GL.glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)。图4-1为程序运行案例,投影后的视景并没有随着位置的远近而发生变化。GL.glOrtho函数的参数如图4-1所示。
图4-1 正投影示意图
在二维投影中的GLU.gluOrtho2D函数,实际上是将GL.glOrtho函数中的值设置为-1.0,far值设置为1.0。二维物体的 Z 坐标为0,因此物体就会在投影区中显示完全。
图4-2用到3个视图区,包括主视图区、图例示图区、标尺视图区,其中,显示飞机本体的为主视图区,3个视图区全部为正投影,3个前向的near值都是一致的。在绘制图例与标尺图形时,其 Z 坐标为near值,保证了左侧的图例示图区与底下的标尺视图区能够在飞机本体前面显示。
图4-2 3个视图区
在绘制图4-2的子绘图区时,如果采用GLU.gluOrtho2D则可能出现主绘图区对子绘图区的遮蔽(见图4-3圆圈部分)。对圆圈部分依次采用GLU.gluOrtho2D与GL.glOrtho不同的投影函数可避免该遮蔽(见图4-4圆圈部分)。
图4-3 图例区被遮蔽
图4-4 图例区没有被遮蔽
在做旋转缩放的时候,这个投影区域也要跟着发生变化以保证旋转投影的剪切区域正常显示。此时需使用动态的正投影代码:
glOrtho -POthoX - PmQuadX, POthoX - PmQuadX, _ -POthoY - PmQuadY, POthoY - PmQuadY, _ -POthoX * PsQuad * 2# - PmQuadZ, _ POthoY * PsQuad * 2# - PmQuadZ
其中,PmQuadX、PmQuadY、PmQuadZ是移动变化量,PsQuad是缩放的调整量,POthoX、POthoY是坐标宽、高的预设值。在鼠标操作的介绍中会给出相应的处理代码。
从图4-5和图4-6可以看出,图例显示(左侧)不随物体的缩放而变化,标尺显示(底下)随着物体的变化而改变。
图4-5 缩小
图4-6 放大
图例投影代码如下:
GL.glGetIntegerv glgViewport, MyViewPort(1) glMatrixMode mmModelView glLoadIdentity GL.glViewport 20, 100, 100, MyViewPort(4)- 200 glMatrixMode mmProjection glLoadIdentity GL.glOrtho 0, 100, -10, 100, -POthoX, POthoX
上述代码中,首先需要定义一个整数型变量数组MyViewPort(),通过GL.glGetIntegerv函数获取显示区域的尺寸信息。在VB中,没有指针的概念,因此把数组的第一个索引作为变量代入函数就能返回整个数组值。然后需要为GL.glViewport函数定义一个显示区域,再在显示区域中定义投影区域。
GL.glGetIntegerv函数可获取状态的值,我们选择的是获取显示尺寸,即glgViewport,然后显示尺寸就填充到了MyViewPort()数组中。其中,MyViewPort(1)是显示区域 X 轴原点坐标,MyViewPort(2)是 Y 轴原点坐标,MyViewPort(3)是宽度,MyViewPort(4)是高度。GL.glGetIntegerv函数获取的是主视图区的显示信息,其中MyViewPort(1)、MyViewPort(2)都为0。通过GL.glViewport 20,100,100,MyViewPort(4)-200,与主显示区交联。
标尺区绘制代码如下:
Public Sub MeterLegend() glMatrixMode mmModelView glLoadIdentity GL.glViewport 0, 0, MyViewPort(3), 50 glMatrixMode mmProjection glLoadIdentity GL.glOrtho -POthoX, POthoX, 0, 100, -POthoX, POthoX Dim Dx As Double Dim Dt As Double Dim DD As Double '标尺区随主视图区尺寸变化而变化,其中MLX初始值为1。 DD = (1 / MLX)* PsQuad If DD * 4 >= POthoX Then MLX = MLX * 2 End If If DD * 4 <= POthoX * 0.5 Then MLX = MLX * 0.5 End If DD = (1 / MLX)* PsQuad For i = 1 To 6 t = i Mod 2 GL.glBegin bmLineStrip GL.glColor3f 0#, 0#, 0# GL.glVertex3f (i - 1)* DD - 3 * DD, 10, POthoX GL.glVertex3f (i - 1)* DD - 3 * DD, 50, POthoX GL.glVertex3f (i)* DD - 3 * DD, 50, POthoX GL.glVertex3f (i)* DD - 3 * DD, 10, POthoX GL.glVertex3f (i - 1)* DD - 3 * DD, 10, POthoX GL.glEnd '填充标尺区的正方形部分,隔一个框填充黑色。 GL.glBegin bmQuads GL.glColor3f 1 * t, 1 * t, 1 * t GL.glVertex3f (i - 1)* DD - 3 * DD, 10, POthoX GL.glVertex3f (i)* DD - 3 * DD, 10, POthoX GL.glVertex3f (i)* DD - 3 * DD, 50, POthoX GL.glVertex3f (i - 1)* DD - 3 * DD, 50, POthoX GL.glEnd Next i '绘制标尺区的字符 For i = 0 To 6 GL.glPushMatrix GL.glRasterPos3f i * DD - 3 * DD, 60, POthoX TStr = Format(1 / MLX * i, "0.####")+ "m" GL.glColor3f 0#, 0#, 0# For j = 1 To Len(TStr) GLUT.glutBitmapCharacter GLUT.GLUT_BITMAP_HELVETICA_18, Asc(Right(Left(TStr, j), 1)) Next j GL.glPopMatrix Next i End Sub