zoukankan      html  css  js  c++  java
  • OpenGL观察轴

    旋转矩阵可以通过观察向量构造,观察向量可以是3D空间的两个或三个点。如果一个处于P1点的对象面向P2点,则观察向量就是P2-P1,如下图:

    首先,前轴向量通过归一化的观察向量简单计算而来。

    其次,左轴通过指定向上方向向量与前轴的差乘计算而来。向上方向向量用于确定对象的roll角度。并且她不必与前轴垂直。如果我们不考虑对象的roll旋转,我们可以使用(0,1,0)。这就是说对象始终向上站立着。

    实际上,与前轴与左轴都正交的上轴向量可以动过另外前轴与左轴向量的差乘计算出来。为了拥有单位长度的向量,左轴与上轴在差乘之后需要归一化。

    下面是从观察向量计算左轴、上轴与前轴的C++代码。第一段代码块是Vector3结构体变量的最简便实现。第二代码块从两点(位置与目标向量)计算3个轴。最后一个代码块从3点(位置、目标向量与向上向量)计算3轴。

    // Vector3结构体的最简化实现
    struct Vector3
    {
        float x;
        float y;
        float z;
    
        Vector3() : x(0), y(0), z(0) {};              // 构造函数
        Vector3(float x, float y, float z) : x(x), y(y), z(z) {};
    
        // 函数
        Vector3& normalize();                         //
        Vector3  operator-(const Vector3& rhs) const; // 减法
        Vector3  operator*(const Vector3& rhs) const; // 差乘
        Vector3& operator*=(const float scale);       // 缩放与更新
    };
    
    Vector3& Vector3::normalize() {
        float invLength = 1 / sqrtf(x*x + y*y + z*z);
        x *= invLength;
        y *= invLength;
        z *= invLength;
        return *this;
    }
    
    Vector3 Vector3::operator-(const Vector3& rhs) const {
        return Vector3(x-rhs.x, y-rhs.y, z-rhs.z);
    }
    
    Vector3 Vector3::cross(const Vector3& rhs) const {
        return Vector3(y*rhs.z - z*rhs.y, z*rhs.x - x*rhs.z, x*rhs.y - y*rhs.x);
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // 从对象的位置与目标点计算变换轴
    ///////////////////////////////////////////////////////////////////////////////
    void lookAtToAxes(const Vector3& position, const Vector3& target,
                      Vector3& left, Vector3& up, Vector3& forward)
    {
        // 计算前向量
        forward = target - position;
        forward.normalize();
    
        // 基于前向量计算临时上向量
        // 注意向上/下观察角度为90°的情况
        // 例如:前向量在Y轴上
        if(fabs(forward.x) < EPSILON && fabs(forward.z) < EPSILON)
        {
            // 前向量指向+Y轴
            if(forward.y > 0)
                up = Vector3(0, 0, -1);
            // 前向量指向-Y轴
            else
                up = Vector3(0, 0, 1);
        }
        // 通常情况上向量为直立的
        else
        {
            up = Vector3(0, 1, 0);
        }
    
        // 计算左向量
        left = up.cross(forward);  // cross product
        left.normalize();
    
        // 重新计算正交化的上向量
        up = forward.cross(left);  // 差乘
        up.normalize();
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // 从位置、目标与向上方向计算变换轴
    ///////////////////////////////////////////////////////////////////////////////
    void lookAtToAxes(const Vector3& pos, const Vector3& target, const Vector3& upDir,
                      Vector3& left, Vector3& up, Vector3& forward)
    {
        // 计算前向量
        forward = target - pos;
        forward.normalize();
    
        // 计算左向量
        left = upDir.cross(forward);  // 差乘
        left.normalize();
    
        // 计算正交化的上向量
        up = forward.cross(left);     // 差乘
        up.normalize();
    }
    

    英文原文:http://www.songho.ca/opengl/gl_lookattoaxes.html 

    学习与分享
  • 相关阅读:
    ArrayBlockingQueue和LinkedBlockingQueue
    hibernate中保存一个对象后再设置此对象的属性为什么不需要调用update方法了
    Hello World!
    org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction;
    jquery的attr在浏览器发生错误,checkbox的属性总是为undefined
    如何解决设置maven时Could not read settings.xml
    iOS与HTML交互问题
    一个苹果证书怎么多次使用——导出p12文件
    Mac Chrome-点击书签页在新的标签打开之方法
    iOS 开发者中的个人账号与组织账号之间区别
  • 原文地址:https://www.cnblogs.com/hefee/p/3819785.html
Copyright © 2011-2022 走看看