简体   繁体   English

绕轴旋转对象

[英]Rotating an Object Around an Axis

I have a circular shape object, which I want to rotate like a fan along it's own axis. 我有一个圆形的对象,我想像风扇一样沿其自身的轴旋转。

I can change the rotation in any direction ie dx, dy, dz using my transformation matrix. 我可以使用变换矩阵沿任何方向(即dx, dy, dz更改旋转。

The following it's the code: 以下是代码:

 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);

My vertex code: 我的顶点代码:

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


Main Game Loop:



  Object.increaseRotation(dxf,dyf,dzf);

But, it's not rotating along it's own axis. 但是,它并没有沿着自己的轴旋转。 What am I missing here? 我在这里想念什么? I want something like this. 我想要这样的东西。 Please Help 请帮忙

在此处输入图片说明

You should Get rid of Euler angles for this. 您应该为此摆脱欧拉角

  1. Object/mesh geometry 对象/网格几何

    You need to be aware of how your object is oriented in its local space. 您需要了解对象在其本地空间中的朝向。 For example let assume this: 例如,假设:

    几何

    So in this case the main rotation is around axis z . 因此,在这种情况下,主旋转围绕z轴。 If your mesh is defined so the rotation axis is not aligned to any of the axises ( x,y or z ) or the center point is not (0,0,0) than that will cause you problems. 如果定义了网格,则旋转轴未与任何轴( x,yz )对齐,或者中心点不在(0,0,0)之外,这会给您带来麻烦。 The remedy is either change your mesh geometry or create a special constant transform matrix M0 that will transform all vertexes from mesh LCS (local coordinate system) to a different one that is axis aligned and center of rotation has zero in the axis which is also the axis of rotation. 补救措施是更改网格的几何形状或创建特殊的常数转换矩阵M0 ,该矩阵将所有顶点从网格LCS (局部坐标系)转换为与轴对齐且旋转中心在轴上为零的另一个顶点,即旋转轴。

    In the latter case any operation on object matrix M would be done like this: 在后一种情况下,将对对象矩阵M进行任何操作,如下所示:

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

    or in reverse or in inverse (depends on your matrix/vertex multiplication and row/column order conventions). 或反向或反向(取决于矩阵/顶点乘法和行/列顺序约定)。 If you got your mesh already centered and axis aligned then do just this instead: 如果您的网格已经居中并且轴对齐,则请执行以下操作:

     M'=M.operation 

    The operation is transform matrix of the change increment (for example rotation matrix). operation是变化增量的变换矩阵(例如旋转矩阵)。 The M is the object current transform matrix from #2 and M' is its new version after applying operation . M是来自#2的对象当前变换矩阵, M'是应用operation后的新版本。

  2. Object transform matrix 对象变换矩阵

    You need single Transform matrix for each object you got. 您需要为每个获得的对象使用单个变换矩阵。 This will hold the position and orientation of your object LCS so it can be converted to world/scene GCS (global coordinate system) or its parent object LCS 这将保留对象LCS的位置和方向,因此可以将其转换为世界/场景GCS (全局坐标系)或其父对象LCS

  3. rotating your object around its local axis of rotation 围绕对象的局部旋转轴旋转对象

    As in the Understanding 4x4 homogenous transform matrices is mentioned for standard OpenGL matrix convetions you need to do this: 正如在“ 了解4x4均匀变换矩阵”中提到的那样,您需要执行以下操作:

     M'=M*rotation_matrix 

    Where M is current object transform matrix and M' is the new version of it after rotation. 其中M是当前对象变换矩阵,而M'是旋转后的新版本。 This is the thing you got different. 这就是你与众不同的地方。 You are using Euler angles rx,ry,rz instead of accumulating the rotations incrementally. 您使用的是欧拉角rx,ry,rz而不是累加旋转。 You can not do this with Euler angles in any sane and robust way! 您不能以任何理智而稳健的方式使用欧拉角来做到这一点! Even if many modern games and apps are still trying hard to do it (and failing for years). 即使许多现代游戏和应用程序仍在努力做到这一点(并且失败了多年)。

So what to do to get rid of Euler angles: 因此,如何摆脱欧拉角:

  1. You must have persistent/global/static matrix M per object 每个对象必须具有永久/全局/静态矩阵M

    instead of local instance per render so you need to init it just once instead of clearing it on per frame basis. 而不是每个渲染的本地实例,因此您只需要初始化一次即可,而不是逐帧清除它。

  2. On animation update apply operation you need 在动画更新上,您需要执行操作

    so: 所以:

     M*=rotation_around_z(angspeed*dt); 

    Where angspeed is in [rad/second] or [deg/second] of your fan speed and dt is time elapsed in [seconds] . angspeed以您的风扇速度[rad/second][deg/second]为单位,而dt是经过的时间,以[seconds] For example if you do this in timer then dt is the timer interval. 例如,如果您在计时器中执行此操作,则dt是计时器间隔。 For variable times you can measure the time elapsed (it is platform dependent I usually use PerformanceTimers or RDTSC). 对于可变时间,您可以测量经过的时间(它取决于平台,我通常使用PerformanceTimers或RDTSC)。

    You can stack more operations on top of itself (for example your fan can also turning back and forward around y axis to cover more area. 您可以在自身之上进行更多操作(例如,风扇也可以围绕y轴来回旋转以覆盖更多区域。

    For object direct control (by keyboard,mouse or joystick) just add things like: 对于对象直接控制(通过键盘,鼠标或操纵杆),只需添加以下内容:

     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); } 

    Where keys is my key map holding on/off state for every key in the keyboard (so I can use more keys at once). 其中keys是我的键映射,用于保持键盘中每个键的开/关状态(因此我可以一次使用更多键)。 This code just control object with arrows. 这段代码只是用箭头控制对象。 For more info on the subject see related QA: 有关该主题的更多信息,请参见相关的质量检查:

    Computer Graphics: Moving in the world 计算机图形学:移动世界

  3. Preserve accuracy 保持准确性

    With incremental changes there is a risc of loosing precision due to floating point errors. 随着增量的变化,由于浮点误差而导致精度降低的风险。 So add a counter to your matrix class which counts how many times it has been changed (incremental operation applied) and if some constant count hit (for example 128 operations) Normalize your matrix. 因此,向您的矩阵类添加一个计数器,该计数器将计数已更改的次数(应用增量操作),以及是否命中了恒定计数(例如128个操作),以对矩​​阵进行归一化。

    To do that you need to ensure orthogonormality of your matrix. 为此,您需要确保矩阵的正交性。 So eaxh axis vector X,Y,Z must be perpendicular to the other two and its size has to be unit. 因此eaxh轴向量X,Y,Z必须垂直于其他两个轴X,Y,Z并且其大小必须为单位。 I do it like this: 我这样做是这样的:

    1. Choose main axis which will have unchanged direction. 选择方向不变的主轴 I am choosing Z axis as that is usually my main axis in my meshes (viewing direction, rotation axis etc). 我选择Z轴,因为这通常是网格中的主轴(查看方向,旋转轴等)。 so just make this vector unit Z = Z/|Z| 所以只要使这个向量单位Z = Z/|Z|
    2. exploit cross product to compute the other two axises so X = (+/-) Z x Y and Y = (+/-) Z x X and also normalize them too X = X/|X| 利用叉积来计算其他两个 X = (+/-) Z x Y因此X = (+/-) Z x YY = (+/-) Z x X并对其进行归一化X = X/|X| and Y = Y/|Y| Y = Y/|Y| . The (+/-) is there because I do not know your coordinate system conventions and the cross product can produce opposite vector to your original direction so if the direction is opposite change the multiplication order or negate the result (this is done while coding time not in runtime!). 之所以存在(+/-)是因为我不知道您的坐标系惯例,并且叉积会产生与原始方向相反的矢量,因此,如果方向相反,则可以更改乘法顺序或取反结果(这是在编码时完成的)不在运行时!)。

    Here example in C++ how my orthonormal normalization is done: 以下是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; } } 

    Where axis?_get/set(a) just get/set a as axis from/to your matrix. axis?_get/set(a)刚刚获得/设置a自/至您的矩阵轴。 The vector_one(a,b) returns a = b/|b| vector_one(a,b)返回a = b/|b| and vector_mul(a,b,c) return a = bxc vector_mul(a,b,c)返回a = bxc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM