码迷,mamicode.com
首页 > 其他好文 > 详细

OpenGL教程翻译 第十四课 相机控制(一)

时间:2015-04-08 16:37:33      阅读:231      评论:0      收藏:0      [点我收藏+]

标签:3d   ogl   opengl   三维   图形   

OpenGL教程翻译 第十四课 相机控制(一)

原文地址:http://ogldev.atspace.co.uk/(源码请从原文主页下载)

Background

在之前的教程中我们学习了如何在三维场景中的任何地方放置相机。那么我们下一步就应该学着去控制这个相机。相机可以向任何方向自由移动。我们可以用鼠标和键盘控制相机——鼠标控制视口方向,键盘控制我们的位置。这些都和第一人称视角相似。这一章我们主要来学习鼠标和键盘的控制。

我们仍然使用上下左右四个方向键。记住,我们的相机的变换取决于位置、target 向量和up 向量。当我们使用键盘移动时,我们只改变了我们的位置信息。上下左右的操作不会导致相机倾斜或旋转,所以target vector up vector都不受影响。

控制键盘我们用到另一个GLUT APIglutSpecialFunc()。当一个“特定”键被敲击的时候,这个函数就会注册一个因之触发的回调。这些特定的键包括:功能键、方向键和PAGE-UP/PAGE-DOWN/HOME/END/INSERT键。如果你想要捕获常规键(字符或者数字),那么请使用glutKeyboardFunc()。

Code Walkthru

相机的功能封装在相机类内。这个类存储相机的属性,并且可以通过接收到的移动事件改变这些属性。管线类获取这些属性并通过它们产生变换矩阵。

    (Camera.h)

class Camera

{
public:

    Camera();
    Camera(const Vector3f& Pos, const Vector3f& Target, const Vector3f& Up);
    bool OnKeyboard(int Key);
    const Vector3f& GetPos() const
    const Vector3f& GetTarget() const
    const Vector3f& GetUp() const

private:

    Vector3f m_pos;
    Vector3f m_target;
    Vector3f m_up;
};

这是相机类的声明。它存储着定义相机类的三个属性——位置向量、target vector up vector。有两个构造函数。默认的那个构造函数简单地将相机摆放在从原点看向Z轴正方向,up 向量指向“天空”(0,1,0)点位置。我们还可以选择创建一个具有特定属性值的相机。OnKeyboard()函数给相机类提供了键盘事件。它返回一个布尔值用来显示该事件是否由相机类接受。如果点击的按键与我们定义的响应事件相关,则返回true,否则返回false。这样,你可以建立一条客户端链用来接收键盘事件,在获取响应特定事件的第一个客户端后停止。

 

(Camera.cpp:42)

bool Camera::OnKeyboard(int Key)
{
    bool Ret = false;

    switch (Key) {

    case GLUT_KEY_UP:
    {
        m_pos += (m_target * StepSize);
        Ret = true;
    }
    break;

    case GLUT_KEY_DOWN:
    {
        m_pos -= (m_target * StepSize);
        Ret = true;
    }
    break;

    case GLUT_KEY_LEFT:
    {
        Vector3f Left = m_target.Cross(m_up);
        Left.Normalize();
        Left *= StepSize;
        m_pos += Left;
        Ret = true;
    }
    break;

    case GLUT_KEY_RIGHT:
    {
        Vector3f Right = m_up.Cross(m_target);
        Right.Normalize();
        Right *= StepSize;
        m_pos += Right;
        Ret = true;
    }
    break;
    }

    return Ret;
}

这个函数根据键盘事件移动相机。GLUT定义了与方向键相应的宏命令,而上面的switch语句正是基于此。不幸的是,这些宏定义的类型都是只是“int”类型,而不是枚举类型。

向前向后的移动是最简单的。因为移动总是沿着target vector,我们就只需要让当前位置加上或者减去target vector就可以了。target vector本身不改变。注意,在加上或者减去target vector之前,我们用一个叫做“StepSize”的常数来缩放它。对所有的方向键,我们都做如此处理。StepSize提供了一个改变速度的中心点(在后面我们也许将会把这个值添加到类属性中)。为使步长一致,我们要确保我们总是乘上单位长度的向量(即我们必须确保目标和up向量是单位长度的)。

         向侧面移动有些复杂。这是一种沿着垂直于target vectors up vectors所确定的平面的矢量的移动。这个平面将三维空间分成了两个部分,并且有两个向量垂直于它,这两个向量方向相反。我们称其中的一个向量为“left”,另一个为“right”。这两个向量是由target vectors up vectors的叉积的两种可能的组合分别产生的——target vectors×up vectorsup target vectors×target  vectors(叉积运算没有交换律——也就是说,在叉积运算中,改变参数的顺序会得到不同的结果)。得到left/right向量之后,我们用StepSize常量将其规范化,用StepSize放缩,最后添加到position(可以将相机向左右方向移动)上。此外,target vectorsup vectors没有受到影响。

         注意,这个函数的内部操作里使用了一些新的运算符,比如被添加到Vector3f 类中的“+=”和“-=”。

   (tutorial14.cpp:73)

static void SpecialKeyboardCB(int Key, int x, int y)
{
    GameCamera.OnKeyboard(Key);
}


static void InitializeGlutCallbacks()
{
    glutDisplayFunc(RenderSceneCB);
    glutIdleFunc(RenderSceneCB);
    glutSpecialFunc(SpecialKeyboardCB);
}

这里,我们注册一个新的回调函数来处理特殊的键盘事件。在按键被触发的时候,回调函数接收按键和鼠标的位置信息。我们忽略鼠标的位置,并且把这个事件传递给成相机类的一个实例,这个实例早已分配给该文件的全局部分。

(tutorial14.cpp:55)

p.SetCamera(GameCamera.GetPos(), GameCamera.GetTarget(), GameCamera.GetUp());

以前,我们在管线类中用硬编码的向量初始化相机参数。现在,我们不再使用这些向量,而是从Camera类直接获取相机属性。

技术分享

OpenGL教程翻译 第十四课 相机控制(一)

标签:3d   ogl   opengl   三维   图形   

原文地址:http://blog.csdn.net/vcube/article/details/44940903

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!