2016-10-02 197 views
0

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

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

但是,它不是沿着它自己的轴旋转。我在这里错过了什么? 我想要这样的东西。请帮助

enter image description here

+1

见[4×4认识同质变换矩阵(http://stackoverflow.com/a/28084380/2521214)子弹**#5 **,并寻找本地之间差并在那里进行全球轮换。 – Spektre

+1

@Spektre会在回答中解释需要做些什么改变我也面临类似问题 –

+0

问题中的代码太少,而不是问题的出现位置。数学的应用是正确的。所以我的猜测是,转换矩阵无法正确加载到着色器的制服中。 – datenwolf

回答

1

你应该摆脱欧拉角这一点。

  1. 对象/网格几何

    你需要知道你的对象是如何在其本地空间为主。例如,让这个假设:

    geometry

    因此,在这种情况下,主转动轴周围z。如果您的网格已定义为旋转轴未与任何轴对齐(x,yz),或者中心点不是(0,0,0),则会导致出现问题。补救措施是更改网格几何图形或创建一个特殊的常数变换矩阵M0,该变换矩阵将将网格物体LCS(局部坐标系)中的所有顶点变换为轴对齐的另一个顶点,并且轴的旋转中心为零也是旋转轴。

    在后者的情况上对象矩阵M任何操作将这样来完成:

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

    或反向或逆(取决于你的矩阵/顶点乘法和行/列顺序惯例)。如果你有你的网已经集中,然后轴对准刚刚做这个:

    M'=M.operation 
    

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

  2. 对象变换矩阵

    你需要一个变换矩阵每个对象你知道的。这将持有你的对象的位置和方向LCS,因此它可以被转换成世界/场景GCS(全球坐标系)或其父对象LCS

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

    正如Understanding 4x4 homogenous transform matrices为标准的OpenGL矩阵convetions提到你需要这样做:

    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是我的钥匙图保持开/关状态,在键盘(这样我就可以同时使用多个键)此代码只是控制与箭头对象中的每个键有关的详细信息。该主题参见相关质量保证:

    Computer Graphics: Moving in the world

  3. 保留准确性

    随着增量变化有失去精度的RISC由于浮点错误。因此,在您的矩阵类中添加一个计数器,计数它已被更改的次数(应用增量操作),以及是否有一些常量计数(例如128次操作)对矩阵进行归一化。

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

    1. 选择主轴这将有方向不变。我选择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