Blender 通过脚本实现绕轴(单位向量)旋转

542 阅读2分钟

常见旋转矩阵 R 的指定方法

R 在三维中的一般定义是

image.png

其中 (x', x) 表示 x'x 轴的夹角,(x', y)x'y 轴的夹角,以此类推。

3-D 退化为 2-D

z 轴旋转意味着 cos(z', z)=1 因为 z'z 的夹角保持为 。同时,cos(x', z)=cos(y', z)=cos(z', x)=cos(z', y)=0,因为这些轴之间的夹角保持 90°

xy' 之间的角度为 (90∘+θ), 而 cos(y', x) = cos(90∘+θ)=−sinθ

同样,x'y 之间的角为 (90°−θ),而 cos(x', y)=cos(90°−θ)=sinθ

所有这些导致 R 退化为

image.png

这揭示了三维旋转矩阵中的二维旋转矩阵。

通过绕轴旋转指定旋转矩阵 R

除了我们常见的指定旋转矩阵的方法,还有另一种指定旋转矩阵的方法,即是通过旋转轴向量 p 和一个绕 p 轴的旋转角 α

在这种情况下,旋转矩阵被写成

image.png

其中

image.png

代入上式,把矩阵完整写出来

image.png

用这种方法很容易将坐标旋转可视化。例如,2-D 的情况可以通过注意旋转是关于 z 轴的来再现,因此向量是 p=(0,0,1) 。这将导致 R 简化为

image.png

效果图与完整代码

Rot.gif

Rot.gif

import numpy as np
import bpy

# 获取单位向量
def get_unit_vector(vec):
    # if not isinstance(vec,np.array):
    vec = np.array(vec)
    vec_norm = np.linalg.norm(vec)
    return vec/vec_norm

# 围绕某单位向量旋转特定角度的旋转矩阵
def rotatematrix(vec,theta):
    p1 = vec[0]
    p2 = vec[1]
    p3 = vec[2]
    theta = np.radians(theta)
    tem_1 = 1-np.cos(theta)
    tem_2 = np.sin(theta)
    tem_3 = np.cos(theta)
    matrix = np.array([
    [tem_3+p1*p1*(tem_1),(tem_1)*p1*p2-p3*tem_2,p1*p3*tem_1+p2*tem_2],
    [p1*p2*tem_1+p3*tem_2,tem_3+tem_1*p2*p2,tem_1*p2*p3-p1*tem_2],
    [tem_1*p1*p3-p2*tem_2,tem_1*p2*p3+p1*tem_2,tem_3+tem_1*p3*p3]
    ])
    return matrix

ob = bpy.context.active_object
rotate_vec = np.array([5,6,2])
vec = get_unit_vector(rotate_vec)
p = np.array(ob.location)

# ob.location = p 围绕某特定向量旋转
num = 0

def test_roate(scene):
    global num
    per_frame = 360/250
    theta = per_frame * scene.frame_current
    r_m = rotatematrix(vec,theta)
    
    # 旋转角度后的坐标 
    newp = np.dot(p,r_m) 
    ob.location = newp
    num += 1
    
    # 画出其运动轨迹
    if scene.frame_current % 10 ==0 and num <251:
        bpy.ops.mesh.primitive_ico_sphere_add(radius=1, location=newp, scale=(0.2, 0.2, 0.2))
        
def main():
    bpy.app.handlers.frame_change_pre.clear()
    bpy.app.handlers.frame_change_pre.append(test_roate)
    
main()