OpenGL观察轴
旋转矩阵可以通过观察向量构造,观察向量可以是3D空间的两个或三个点。如果一个处于P1点的对象面向P2点,则观察向量就是P2-P1,如下图:
首先,前轴向量通过归一化的观察向量简单计算而来。
其次,左轴通过指定向上方向向量与前轴的差乘计算而来。向上方向向量用于确定对象的roll角度。并且她不必与前轴垂直。如果我们不考虑对象的roll旋转,我们可以使用(0,1,0)。这就是说对象始终向上站立着。
实际上,与前轴与左轴都正交的上轴向量可以动过另外前轴与左轴向量的差乘计算出来。为了拥有单位长度的向量,左轴与上轴在差乘之后需要归一化。
下面是从观察向量计算左轴、上轴与前轴的C++代码。第一段代码块是Vector3结构体变量的最简便实现。第二代码块从两点(位置与目标向量)计算3个轴。最后一个代码块从3点(位置、目标向量与向上向量)计算3轴。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | // 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); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | /////////////////////////////////////////////////////////////////////////////// // 从对象的位置与目标点计算变换轴 /////////////////////////////////////////////////////////////////////////////// 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(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /////////////////////////////////////////////////////////////////////////////// // 从位置、目标与向上方向计算变换轴 /////////////////////////////////////////////////////////////////////////////// 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(); } |
学习与分享
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)