011-3D数学中的旋转变换详解及实例

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小宝哥Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值