3D数学中的旋转变换详解及实例
1. 2D空间中的旋转变换
在二维空间中,旋转发生在单一平面上,通常围绕z轴(垂直于xy平面)进行。这是最简单的旋转形式,但理解它对于掌握3D旋转至关重要。
1.1 基本概念与数学表示
2D旋转可以通过一个角度θ完全描述,表示围绕原点的逆时针旋转(顺时针旋转对应负角度)。
1.1.1 旋转方程
对于点P(x, y),经过角度θ的旋转后得到P'(x', y'),计算公式为:
x' = x·cos(θ) - y·sin(θ)
y' = x·sin(θ) + y·cos(θ)
1.1.2 旋转矩阵
2D旋转可以表示为2×2旋转矩阵:
cpp
// 2D旋转矩阵
Matrix2x2 createRotationMatrix2D(float angleRadians) {
float cosTheta = cos(angleRadians);
float sinTheta = sin(angleRadians);
Matrix2x2 rotationMatrix;
rotationMatrix(0, 0) = cosTheta;
rotationMatrix(0, 1) = -sinTheta;
rotationMatrix(1, 0) = sinTheta;
rotationMatrix(1, 1) = cosTheta;
return rotationMatrix;
}
1.1.3 复数表示
2D旋转也可以使用复数表示,这为理解四元数提供了基础:
cpp
// 使用复数表示2D旋转
struct Complex {
float real;
float imag;
Complex(float r, float i) : real(r), imag(i) {}
// 复数乘法实现旋转
Complex operator*(const Complex& other) const {
return Complex(
real * other.real - imag * other.imag,
real * other.imag + imag * other.real
);
}
};
// 创建表示旋转的复数
Complex createRotationComplex(float angleRadians) {
return Complex(cos(angleRadians), sin(angleRadians));
}
// 使用复数旋转一个点
Vector2 rotatePointUsingComplex(const Vector2& point, float angleRadians) {
Complex rotationComplex = createRotationComplex(angleRadians);
Complex pointComplex(point.x, point.y);
Complex resultComplex = rotationComplex * pointComplex;
return Vector2(resultComplex.real, resultComplex.imag);
}
1.2 特殊角度旋转的优化
对于常用角度(如90°、180°、270°),可以避免使用三角函数,提高计算效率:
cpp
// 优化的90度旋转
Vector2 rotate90Degrees(const Vector2& point) {
return Vector2(-point.y, point.x);
}
// 优化的180度旋转
Vector2 rotate180Degrees(const Vector2& point) {
return Vector2(-point.x, -point.y);
}
// 优化的270度(-90度)旋转
Vector2 rotate270Degrees(const Vector2& point) {
return Vector2(point.y, -point.x);
}
1.3 围绕任意点旋转
当需要围绕非原点的点进行旋转时,需要先将坐标系平移,使旋转中心成为原点,旋转后再平移回去:
cpp
// 围绕任意点旋转
Vector2 rotateAroundPoint(const Vector2& point, const Vector2& center, float angleRadians) {
// 1. 平移到以旋转中心为原点的坐标系
Vector2 translated = Vector2(point.x - center.x, point.y - center.y);
// 2. 围绕原点旋转
float cosTheta = cos(angleRadians);
float sinTheta = sin(angleRadians);
Vector2 rotated = Vector2(
translated.x * cosTheta - translated.y * sinTheta,
translated.x * sinTheta + translated.y * cosTheta
);
// 3. 平移回原来的坐标系
return Vector2(rotated.x + center.x, rotated.y + center.y);
}
1.4 累积旋转与插值
在动画和物理模拟中,经常需要处理累积旋转和旋转插值:
cpp
// 累积旋转:使用矩阵乘法
Matrix2x2 accumulateRotations(const Matrix2x2& rotation1, const Matrix2x2& rotation2) {
return rotation2 * rotation1; // 注意顺序:先执行rotation1,再执行rotation2
}
// 角度线性插值
float lerpAngle(float startAngle, float endAngle, float t) {
// 确保角度在同一范围内(如[-π, π))
float diff = fmod(endAngle - startAngle + M_PI, 2 * M_PI) - M_PI;
if (diff < -M_PI) diff += 2 * M_PI;
return startAngle + diff * t;
}
// 平滑角度插值(使用正弦函数)
float smoothLerpAngle(float startAngle, float endAngle, float t) {
float angle = lerpAngle(startAngle, endAngle, t);
// 平滑因子:加速然后减速
float smooth = 0.5f - 0.5f * cos(t * M_PI);
return lerpAngle(startAngle, endAngle, smooth);
}
1.5 2D旋转的应用实例
1.5.1 旋转精灵或图像
cpp
class Sprite {
private:
Vector2 position;
Vector2 origin;
float rotation; // 角度,以弧度表示
Vector2 scale;
public:
Sprite() : position(0, 0), origin(0, 0), rotation(0), scale(1, 1) {}
void setPosition(const Vector2& pos) { position = pos; }
void setOrigin(const Vector2& orig) { origin = orig; }
void setRotation(float rot) { rotation = rot; }
void setScale(const Vector2& sc) { scale = sc; }
// 获取变换矩阵(按照缩放→旋转→平移的顺序)
Matrix3x3 getTransformMatrix() const {
// 在2D图形库中,通常使用3x3矩阵表示带平移的仿射变换
float cosTheta = cos(rotation);
float sinTheta = sin(rotation);
Matrix3x3 transform;
// 应用缩放
transform(0, 0) = scale.x;
transform(1, 1) = scale.y;
// 应用旋转
Matrix3x3 rotationMatrix;
rotationMatrix(0, 0) = cosTheta;
rotationMatrix(0, 1) = -sinTheta;
rotationMatrix(1, 0) = sinTheta;
rotationMatrix(1, 1) = cosTheta;
transform = rotationMatrix * transform;
// 应用原点平移
Matrix3x3 originTranslation;
originTranslation(0, 2) = -origin.x;
originTranslation(1, 2) = -origin.y;
transform = transform * originTranslation;
// 应用位置平移
transform(0, 2) += position.x;
transform(1, 2) += position.y;
return transform;
}
// 应用变换到顶点
std::vector<Vector2> getTransformedVertices(const std::vector<Vector2>& originalVertices) const {
Matrix3x3 transform = getTransformMatrix();
std::vector<Vector2> transformedVertices;
for (const auto& vertex : originalVertices) {
Vector3 homogeneous(vertex.x, vertex.y, 1.0f);
Vector3 transformed = transform * homogeneous;
transformedVertices.push_back(Vector2(transformed.x, transformed.y));
}
return transformedVertices;
}
};
1.5.2 2D物理中的旋转
cpp
class RigidBody2D {
private:
Vector2 position;
float rotation; // 角度,以弧度表示
Vector2 linearVelocity;
float angularVelocity; // 角速度,以弧度/秒表示
float mass;
float momentOfInertia;
public:
RigidBody2D(float mass)
: position(0, 0), rotation(0), linearVelocity(0, 0), angularVelocity(0),
mass(mass), momentOfInertia(mass) {} // 简化:使用质量作为惯性矩
void update(float deltaTime) {
// 更新位置
position.x += linearVelocity.x * deltaTime;
position.y += linearVelocity.y * deltaTime;
// 更新旋转
rotation += angularVelocity * deltaTime;
// 规范化旋转角度到[0, 2π)
rotation = fmod(rotation, 2 * M_PI);
if (rotation < 0) rotation += 2 * M_PI;
}
void applyForce(const Vector2& force, const Vector2& applicationPoint) {
// 力导致的线性加速度
Vector2 linearAcceleration = force * (1.0f / mass);
linearVelocity.x += linearAcceleration.x;
linearVelocity.y += linearAcceleration.y;
// 力矩 = r × F(在2D中,r×F = r_x*F_y - r_y*F_x)
Vector2 r = applicationPoint - position;
float torque = r.x * force.y - r.y * force.x;
// 角加速度 = 力矩 / 惯性矩
float angularAcceleration = torque / momentOfInertia;
angularVelocity += angularAcceleration;
}
// 获取物体上某点在世界坐标系中的位置
Vector2 getWorldPoint(const Vector2& localPoint) const {
// 旋转点
float cosTheta = cos(rotation);
float sinTheta = sin(rotation);
Vector2 rotatedPoint(
localPoint.x * cosTheta - localPoint.y * sinTheta,
localPoint.x * sinTheta + localPoint.y * cosTheta
);
// 平移到正确位置
return position + rotatedPoint;
}
};
2. 3D空间中的旋转变换
3D空间中的旋转比2D要复杂得多,因为我们现在有三个正交轴,围绕不同轴的旋转不满足交换律。
2.1 基本旋转矩阵
在3D空间中,基本旋转是围绕坐标轴(x轴、y轴或z轴)的旋转。
2.1.1 围绕X轴旋转
cpp
// 创建绕X轴旋转的矩阵
Matrix4x4 createRotationXMatr