正文

虚拟相机的绘制方法(一)2010-05-14 16:49:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/yuqiexing/51130.html

分享到:

  一般,我们经常把看到的三维场景类比于相机拍照(OpenGL编程指南第四版),因此视点变换也称为相机变换。后来有些人总是误解“视点”的概念,因为视点既可以理解为“相机(眼睛)所在的位置”,也可以理解为“相机(眼睛)所看到的地方”。前者是指相机位置,而后者则是场景中心(参见gluLookAt函数)。为了方便起见,本文不采用“视点”的概念,而用相机位置来代替说明。     三维漫游的过程实际上就是相机运动的过程,包括相机位置和相机视线的运动改变。人眼所看到的三维动画就好比看到的DV录像。要知道,相机拍照是不会拍到自己的。(除非有镜子,排除这种情况)。但是有些时候,我们希望从全局看到相机本身的运动过程。因此,我们希望在场景中虚拟出这样一个对象来模拟相机的运动,称为“虚拟相机”(Virtual Camera).这样做有2个优点:一来可以帮助我们更好的宏观上了解和定制漫游路线和漫游效果,比如我们想指定,当相机经过A楼大门前,视线必须经过对面马路的红绿灯;另外,也可以检查漫游效果是否平滑,以及不平滑出现的位置和时间等。     虚拟相机的绘制包括两个部分:视锥体和相机体。(参见下图:3DSMax中的虚拟相机)。其中视锥体为由近裁切面和远裁切面为底面构成的棱锥台,其轴线为视线方向。为方便模拟,一般近裁切面直接表示为一个点,该点位于相机体镜头的中心。而远裁切面由于一般设置很大,我们只需要控制在一定距离内进行示意即可,例如100m,或者在路径漫游时,如果用户设定了相机路径和目标路径,那么可以直接把“远裁切面”中心设置在目标路径上。                                               图:3DSMax中的虚拟相机       在运动过程中,相机体本身会发生位置和姿态变化,但形态不会变化,因此可以从外部文件(obj,3ds)导入已经制作好的几何模型来表示,但是本文不建议这么做。因为数据量可能很大,降低场景绘制效率;而视锥体的形态、位置和姿态都在发生变化,可以每帧都直接绘制棱锥台来表示。因此本文建议整个虚拟相机都采用简单的几何体(primitive)来组合进行示意,包括镜身,连接处和镜头三个部分;同时绘制时建议采用线框模式。如果用填充方式,会产生一些不必要的场景遮挡,同时影响对相机运动过程的观察。       本文将给出两种绘制方法。一种是直接利用GLU库进行绘制,另一种是根据应用程序自行设计的线、面绘制来进行组装(暂时略)。     我们首先给出以Z轴为轴线,镜头中心在原点的虚拟相机绘制。因为相机的其他姿态可以直接通过平移和旋转变换得到。   long CRenderEngine::Draw3DCamera(CVirtualCamera* pCam, int m_nDrawMode) {        // 将相机位置从大地坐标系投影到OpenGL绘制坐标系          CPoint3d camPoint = pCam->m_ptCamPos;          m_pProject->Project(camPoint);               // 将场景中心从大地坐标系投影到OpenGL绘制坐标系          CPoint3d tarPoint = pCam->m_ptTarPos;          m_pProject->Project(tarPoint);               // 绘制颜色          float rgb[3];               // 计算视线长度和方向,并进行单位化          CPoint3d vVec = tarPoint - camPoint;          double dDis  = vVec.Length();          vVec /= dDis;                            glPushMatrix();        {                    // 绘制虚拟相机轴线                 if(pCam->m_bShowAxies)               {                      if(pCam->GetDrawMode() == MODE_HIGHLIGHT) // 高亮模式绘制                      memcpy(rgb,pCam->m_camSelColor,sizeof(float)*3);                        else // 普通模式绘制                               memcpy(rgb,pCam->m_camPathColor,sizeof(float)*3);                                           glColor3f(rgb[0],rgb[1],rgb[2]);                        // 直接用LineStrip绘制                        glBegin(GL_LINE_STRIP);                        glVertex3f(0,0,0);                        glVertex3f(0,0,dViewLength);                        glEnd();               }                             // 绘制虚拟相机视椎体和相机体                 if(pCam->m_bShowFrustum)               {                      GLUquadricObj *qObj;                        qObj = gluNewQuadric();                        gluQuadricDrawStyle(qObj,GLU_SILHOUETTE);                                           // 获得当前相机fov                        double currentFov = m_camera.GetFov();                        // 获得当前相机宽高比                        double dPerRatio = m_camera.GetAspectRatio();                        // 计算当前相机在目标点处的裁切面高度                        double dPerHeight = 2 * dDis * tan((currentFov/2) * MathEx::dDegToRad);                                // 绘制视椎体                        glPushMatrix();                      {                                                         glScalef(dPerRatio,1.0,1.0);                                                           glRotatef(45,0,0,1);                             // 绘制以z轴为中心线的圆柱,底面位于平面z=0上,顶面位于z = dDis上。                               gluCylinder(qObj,0,dPerHeight,dDis,4,4);                        }                        glPopMatrix();                                           // 绘制镜头                        double dBomR = pCam->m_dBaseLength; // 虚拟相机基本大小                        double dTopR = dBomR / 2.0;                        double dHeight = dBomR / 1.5;                        glPushMatrix();                        {                             glScalef(1.5,1.0,1.0);                               glRotatef(45,0,0,1);                               gluCylinder(qObj,dBomR,dTopR,dHeight,4,4);                      }                        glPopMatrix();                                           glPushMatrix();                        {                             double dCylHeight = pCam->m_dBaseLength / 2;                               // 绘制连接处1                               glTranslatef(0,0,dHeight);                               glPushMatrix();                               {                                    glRotatef(45,0,0,1);                                      gluCylinder(qObj,dTopR / 1.2,dTopR /   1.2,dCylHeight,4,4);                               }                               glPopMatrix();                                                         dCylHeight *= 1.2;                               // 绘制连接处2                               glTranslatef(0,0,dCylHeight);                               glPushMatrix();                               {                                    glRotatef(45,0,0,1);                                      gluCylinder   (qObj,dTopR/1.5,dTopR/1.5,dCylHeight,4,4);                               }                               glPopMatrix();                                         }                        glPopMatrix();                                           gluDeleteQuadric(qObj);//释放内存空间                 }                 glPopMatrix();          }               return 1; }          这样我们就可以绘制一个位置在原点、视线方向与z轴平行、up分量与x轴平行的虚拟相机了。    

阅读(5998) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册