【问题标题】:Rotating an Object Around an Axis围绕轴旋转对象
【发布时间】:2017-02-10 09:35:17
【问题描述】:

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

我可以使用我的变换矩阵改变任何方向的旋转,即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);

但是,它并没有沿着自己的轴旋转。我在这里想念什么? 我想要这样的东西。请帮忙

【问题讨论】:

  • 参见Understanding 4x4 homogenous transform matrices bullet #5 并在那里寻找局部和全局旋转之间的差异。
  • @Spektre 请在答案中解释需要做哪些改变我也面临类似的问题
  • 您的问题中的相关代码太少,无法查看问题可能出在哪里。数学的应用是正确的。所以我的猜测是,转换矩阵没有正确加载到着色器的制服中。
  • @datenwolf 我的对象像硬币一样翻转,即在一帧中Head 一侧面向相机,而在第二帧中Tail 一侧面向相机,当我仅更改y 旋转时, 对于x 旋转,它围绕轨道旋转,对于z 旋转,它在旋转,但 y 位置也在变化

标签: opengl matrix graphics rotation


【解决方案1】:

为此,您应该去掉欧拉角

  1. 对象/网格几何体

    您需要了解您的对象在其本地空间中是如何定向的。例如让我们假设:

    所以在这种情况下,主要旋转是围绕轴z。如果您的网格被定义为旋转轴未与任何轴对齐(@9​​87654326@ 或z)或中心点不是(0,0,0),则会导致您出现问题。补救方法是更改​​网格几何形状或创建一个特殊的常量变换矩阵M0,它将所有顶点从网格 LCS(局部坐标系)转换为轴对齐和旋转中心的不同顶点在轴上为零,这也是旋转轴。

    在后一种情况下,对对象矩阵M 的任何操作都将像这样完成:

    M'=M.M0.operation.Inverse(M0)
    

    或反向或反向(取决于您的矩阵/顶点乘法和行/列顺序约定)。如果你的网格已经居中并且轴对齐,那么就这样做吧:

    M'=M.operation
    

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

  2. 对象变换矩阵

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

  3. 围绕其局部旋转轴旋转对象

    正如Understanding 4x4 homogenous transform matrices 中提到的标准 OpenGL 矩阵转换,您需要这样做:

    M'=M*rotation_matrix
    

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

那么如何摆脱欧拉角:

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

    而不是每次渲染的本地实例,因此您需要只初始化一次,而不是每帧清除它。

  2. 关于动画更新应用你需要的操作

    所以:

    M*=rotation_around_z(angspeed*dt);
    

    angspeed 是风扇速度的[rad/second][deg/second]dt[seconds] 中经过的时间。例如,如果您在计时器中执行此操作,则 dt 是计时器间隔。对于可变时间,您可以测量经过的时间(取决于平台,我通常使用 PerformanceTimers 或 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:

    Computer Graphics: Moving in the world

  3. 保持准确性

    随着增量更改,存在由于浮点错误而导致精度下降的风险。因此,向您的矩阵类添加一个计数器,该计数器计算它被更改的次数(应用了增量操作)以及是否有一些常量计数命中(例如 128 次操作)标准化您的矩阵。

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

    1. 选择主轴,方向不变。我选择Z 轴,因为它通常是我的网格中的主轴(查看方向、旋转轴等)。所以只需制作这个矢量单元Z = Z/|Z|
    2. 利用叉积来计算其他两个轴,所以X = (+/-) Z x YY = (+/-) Z x X 也将它们归一化X = X/|X|Y = Y/|Y|(+/-) 在那里,因为我不知道您的坐标系约定,并且叉积可以产生与原始方向相反的向量,因此如果方向相反,请更改乘法顺序或否定结果(这是在编码时间不在的情况下完成的运行时!)。

    C++ 中的示例是如何完成正交归一化的:

    void reper::orto(int test)
            {
            double   x[3],y[3],z[3];
            if ((cnt>=_reper_max_cnt)||(test)) // here cnt is the operations counter and test force normalization regardless of it
                    {
                    use_rep();              // you can ignore this 
                    _rep=1; _inv=0;         // you can ignore this
                    axisx_get(x);
                    axisy_get(y);
                    axisz_get(z);
                    vector_one(z,z);
                    vector_mul(x,y,z);      // x is perpendicular to y,z
                    vector_one(x,x);
                    vector_mul(y,z,x);      // y is perpendicular to z,x
                    vector_one(y,y);
                    axisx_set(x);
                    axisy_set(y);
                    axisz_set(z);
                    cnt=0;
                    }
            }
    

    axis?_get/set(a) 只需获取/设置a 作为从/到矩阵的轴。 vector_one(a,b) 返回 a = b/|b|vector_mul(a,b,c) 返回 a = b x c

【讨论】:

    猜你喜欢
    • 2015-01-06
    • 2015-07-14
    • 1970-01-01
    • 2015-07-23
    • 2014-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多