Opengl 绕轴旋转物体

Opengl 绕轴旋转物体,opengl,matrix,graphics,rotation,Opengl,Matrix,Graphics,Rotation,我有一个圆形的物体,我想像风扇一样沿着它自己的轴旋转 我可以使用变换矩阵更改任意方向的旋转,即dx、dy、dz 以下是代码: Matrix4f matrix = new Matrix4f(); matrix.setIdentity(); Matrix4f.translate(translation, matrix, matrix); Matrix4f.rotate((float) Math.toRadians(rx), new Vector3f(1,0,0), matrix, matri

我有一个圆形的物体,我想像风扇一样沿着它自己的轴旋转

我可以使用变换矩阵更改任意方向的旋转,即
dx、dy、dz

以下是代码:

 Matrix4f matrix = new Matrix4f();
 matrix.setIdentity();
 Matrix4f.translate(translation, matrix, matrix);
 Matrix4f.rotate((float) Math.toRadians(rx), new Vector3f(1,0,0), matrix, matrix);
 Matrix4f.rotate((float) Math.toRadians(ry), new Vector3f(0,1,0), matrix, matrix);
 Matrix4f.rotate((float) Math.toRadians(rz), new Vector3f(0,0,1), matrix, matrix);
 Matrix4f.scale(new Vector3f(scale,scale,scale), matrix, matrix);
我的顶点代码:

 vec4 worldPosition = transformationMatrix * vec4(position,1.0);
 vec4 positionRelativeToCam = viewMatrix*worldPosition;
 gl_Position = projectionMatrix *positionRelativeToCam;


Main Game Loop:



  Object.increaseRotation(dxf,dyf,dzf);
但是,它不是沿着自己的轴旋转的。我错过了什么? 我想要这样的东西。请帮忙


为此,您应该去掉欧拉角

  • 对象/网格几何体

    您需要了解对象在其局部空间中是如何定向的。例如,假设:

    因此,在这种情况下,主旋转围绕轴
    z
    。如果您的网格定义为旋转轴未与任何轴对齐(
    x,y
    z
    ),或者中心点不是
    (0,0,0)
    ,则会导致问题。补救方法是更改网格几何体或创建一个特殊的常量变换矩阵
    M0
    ,该矩阵将所有顶点从网格LCS(局部坐标系)变换为一个不同的顶点,该顶点与轴对齐,且旋转中心在轴(也是旋转轴)中为零

    在后一种情况下,对对象矩阵
    M
    的任何操作都将如下所示:

    M'=M.M0.operation.Inverse(M0)
    
    或反向或反向(取决于矩阵/顶点乘法和行/列顺序约定)。如果网格已居中且轴已对齐,则只需执行以下操作:

    M'=M.operation
    
    操作是变化增量的变换矩阵(例如旋转矩阵)。
    M
    是来自#2的对象当前变换矩阵,
    M'
    是应用
    操作后的新版本

  • 对象变换矩阵

    对于得到的每个对象,都需要一个变换矩阵。这将保持对象的位置和方向LCS,因此可以将其转换为世界/场景GCS(全局坐标系)或其父对象LCS

  • 围绕对象的局部旋转轴旋转对象

    正如标准OpenGL矩阵变换中提到的,您需要执行以下操作:

    M'=M*rotation_matrix
    
    其中,
    M
    是当前对象变换矩阵,
    M'
    是旋转后的新版本。这就是你与众不同的地方。您使用的是Euler角度
    rx、ry、rz
    ,而不是增量累积旋转。你不能用任何理智和稳健的方式来处理欧拉角!即使许多现代游戏和应用程序仍在努力做到这一点(并失败多年)

  • 那么如何去除欧拉角:

  • 每个对象必须具有持久/全局/静态矩阵
    M

    而不是每个渲染的本地实例,因此只需初始化它一次,而不是在每帧的基础上清除它

  • 在需要的动画更新应用操作上

    因此:

    其中,
    angspeed
    是风扇转速的
    [rad/second]
    [deg/second]
    ,而
    dt
    是以
    [seconds]
    为单位经过的时间。例如,如果在计时器中执行此操作,则
    dt
    是计时器间隔。对于可变时间,您可以测量经过的时间(它取决于平台,我通常使用PerformanceTimes或RDTSC)

    您可以在其顶部堆叠更多操作(例如,您的风扇还可以围绕
    y
    轴前后转动,以覆盖更多区域

    对于对象直接控制(通过键盘、鼠标或操纵杆),只需添加以下内容:

    if (keys.get( 38)) { redraw=true; M*=translate_z(-pos_speed*dt); }
    if (keys.get( 40)) { redraw=true; M*=translate_z(+pos_speed*dt); }
    if (keys.get( 37)) { redraw=true; M*=rotation_around_y(-turn_speed*dt); } 
    if (keys.get( 39)) { redraw=true; M*=rotation_around_y(+turn_speed*dt); }
    
    其中,
    keys
    是我的键映射,为键盘中的每个键保持开/关状态(这样我可以一次使用更多键)。此代码仅使用箭头控制对象。有关主题的更多信息,请参阅相关QA:

  • 保持准确性

    增量更改会导致risc由于浮点错误而失去精度。因此,请在矩阵类中添加一个计数器,用于计算更改的次数(应用增量操作),以及如果某个常量计数命中(例如128次操作),则会使矩阵正常化

    为此,您需要确保矩阵的正交性。因此eaxh轴向量
    X,Y,Z
    必须与其他两个向量垂直,并且其大小必须为单位。我这样做:

    M'=M.M0.operation.Inverse(M0)
    
  • 选择方向不变的主轴。我选择的是
    Z
    轴,因为它通常是我网格中的主轴(查看方向、旋转轴等)。所以只需将此向量单位设为
    Z=Z/| Z
  • 利用叉积计算其他两个轴因此
    X=(+/-)zxy
    Y=(+/-)zx
    ,并对它们进行规格化
    X=X/| X |
    Y=Y/| Y
    之所以存在,是因为我不知道您的坐标系约定,而叉积可以生成与原始方向相反的向量,因此如果方向相反,请更改乘法顺序或对结果求反(这是在非运行时编码时间时完成的!)
  • 下面是C++中的示例,我的正交规范化是如何完成的:

    void repro::orto(int测试)
    {
    双x[3],y[3],z[3];
    if((cnt>=_resu_max_cnt)| | |(test))//这里cnt是操作计数器和测试力标准化,不管它是什么
    {
    使用_rep();//您可以忽略此选项
    _rep=1;_inv=0;//您可以忽略此项
    axix_-get(x);
    axisy_-get(y);
    axisz_-get(z);
    向量_-one(z,z);
    向量_mul(x,y,z);//x垂直于y,z
    向量_-one(x,x);
    向量μmul(y,z)