绕轴旋转对象 [英] Rotating an Object Around an Axis

查看:97
本文介绍了绕轴旋转对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个圆形的对象,想要像扇子一样沿其自身的轴旋转.

I have a circular shape object, which I want to rotate like a fan along it's own axis.

我可以使用变换矩阵在任何方向(即dx, dy, dz)上更改旋转.

I can change the rotation in any direction i.e. dx, dy, dz using my transformation matrix.

以下是代码:

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

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

But, it's not rotating along it's own axis. What am I missing here? I want something like this. Please Help

推荐答案

您应该为此摆脱欧拉角.

  1. 对象/网格几何

您需要了解对象在其本地空间中的朝向.例如,假设:

You need to be aware of how your object is oriented in its local space. For example let assume this:

因此,在这种情况下,主旋转围绕轴z.如果定义了网格,则旋转轴未与任何轴(x,yz)对齐,或者中心点未(0,0,0),将给您带来麻烦.补救措施是更改网格的几何形状或创建特殊的常数转换矩阵M0,该矩阵将所有顶点从网格 LCS (局部坐标系)转换为轴对齐且旋转中心的另一个顶点在轴上也为零,这也是旋转轴.

So in this case the main rotation is around axis 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. 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.

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

In the latter case any operation on object matrix M would be done like this:

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

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

The operation is transform matrix of the change increment (for example rotation matrix). The M is the object current transform matrix from #2 and M' is its new version after applying operation.

对象变换矩阵

您需要为每个获得的对象使用单个Transform矩阵.这将保留对象 LCS 的位置和方向,因此可以将其转换为世界/场景 GCS (全局坐标系)或其父对象 LCS

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

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

对于标准OpenGL矩阵优化中提到的理解4x4均匀变换矩阵中,您需要执行以下操作:

As in the Understanding 4x4 homogenous transform matrices is mentioned for standard OpenGL matrix convetions you need to do this:

M'=M*rotation_matrix

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

Where M is current object transform matrix and M' is the new version of it after rotation. This is the thing you got different. You are using Euler angles rx,ry,rz instead of accumulating the rotations incrementally. 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).

那么要摆脱欧拉角怎么办:

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

  1. You must have persistent/global/static matrix M per object

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

instead of local instance per render so you need to init it just once instead of clearing it on per frame basis.

在动画更新中应用所需的操作

如此:

M*=rotation_around_z(angspeed*dt);

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

Where angspeed is in [rad/second] or [deg/second] of your fan speed and dt is time elapsed in [seconds]. For example if you do this in timer then dt is the timer interval. For variable times you can measure the time elapsed (it is platform dependent I usually use PerformanceTimers or RDTSC).

您可以在自身之上进行更多操作(例如,风扇也可以围绕y轴来回旋转以覆盖更多区域.

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.

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

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

keys是键盘上每个键的开/关状态(因此我可以一次使用更多键).这段代码只是用箭头控制对象.有关该主题的更多信息,请参见相关的质量检查:

Where keys is my key map holding on/off state for every key in the keyboard (so I can use more keys at once). This code just control object with arrows. For more info on the subject see related QA:

计算机图形学:走向世界

保持准确性

随着增量更改,由于浮点错误而导致精度损失的风险.因此,将一个计数器添加到矩阵类中,该计数器将计数已更改的次数(应用增量操作),以及是否命中了一些恒定计数(例如128个操作),以对矩​​阵进行归一化.

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.

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

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. I do it like this:

  1. 选择主轴,其方向不变.我选择Z轴,因为这通常是网格中的主轴(查看方向,旋转轴等).所以只要将此向量单位Z = Z/|Z|
  2. 利用叉积来计算其他两个轴,因此X = (+/-) Z x YY = (+/-) Z x X以及也将它们标准化X = X/|X|Y = Y/|Y|. (+/-)之所以存在,是因为我不知道您的坐标系惯例,并且叉积会产生与原始方向相反的矢量,因此,如果方向相反,则可以更改乘法顺序或取反结果(这是在编码时间不等于0的情况下完成的)运行时!).
  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). so just make this vector unit 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| and 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!).

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

Here example in C++ how my orthonormal normalization is done:

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

Where axis?_get/set(a) just get/set a as axis from/to your matrix. The vector_one(a,b) returns a = b/|b| and vector_mul(a,b,c) return a = b x c

这篇关于绕轴旋转对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆