是否可以围绕自己的轴而不是围绕基本坐标的轴旋转对象? [英] Is it possible to rotate an object around its own axis and not around the base coordinate's axis?

查看:22
本文介绍了是否可以围绕自己的轴而不是围绕基本坐标的轴旋转对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在按照谷歌的 OpenGL es 旋转示例在我的 Android 应用程序上旋转一个简单的正方形(不是立方体),例如以下代码:

I am following the OpenGL es rotation examples from google to rotate a simple square (not a cube) on my Android App, for example this code:

gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);   //X
gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);   //Y
gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);   //Z

如果你只绕一个轴旋转它就可以正常工作.

It works fine if you only rotate around one axis.

但是如果你绕一个轴旋转,然后再绕另一个轴旋转,旋转是不公平的.我的意思是旋转是围绕基本(全局)坐标系的轴完成的,而不是正方形自己的坐标系.

But if you rotate around one axis, and after that, you rotate around another axis, the rotation is not fair. I mean that the rotation is done around the axes of base (global) coordinate system and not the square's own coordinate system.

使用 Shahbaz

public void onDrawFrame(GL10 gl) {
    //Limpiamos pantalla y Depth Buffer
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);    
    gl.glLoadIdentity();
    //Dibujado
    gl.glTranslatef(0.0f, 0.0f, z);         //Move z units into the screen
    gl.glScalef(0.8f, 0.8f, 0.8f);          //Escalamos para que quepa en la pantalla
    //Rotamos sobre los ejes.
    gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);   //X
    gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);   //Y
    gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);   //Z
    //Dibujamos el cuadrado
    square.draw(gl);    
    //Factores de rotación.
    xrot += xspeed;
    yrot += yspeed;
}

绘制正方形:

    public void draw(GL10 gl) {
    gl.glFrontFace(GL10.GL_CCW);
    //gl.glEnable(GL10.GL_BLEND);
    //Bind our only previously generated texture in this case
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
    //Point to our vertex buffer
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
    //Enable vertex buffer
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    //Draw the vertices as triangle strip
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
    //Disable the client state before leaving
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    //gl.glDisable(GL10.GL_BLEND);

}

顶点缓冲区值:

private FloatBuffer vertexBuffer;

private float vertices[] = 
{ 
    -1.0f, -1.0f, 0.0f,     //Bottom Left
    1.0f, -1.0f, 0.0f,      //Bottom Right
    -1.0f, 1.0f, 0.0f,      //Top Left
    1.0f, 1.0f, 0.0f        //Top Right
};
.
.
.
public Square(int resourceId) {
        ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
        byteBuf.order(ByteOrder.nativeOrder());
        vertexBuffer = byteBuf.asFloatBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);
.
.
.

推荐答案

首先你应该知道的是,在 OpenGL 中,变换矩阵是从右乘的.这是什么意思?这意味着您编写的最后一个转换首先应用于对象.

First thing you should know is that in OpenGL, transformation matrices are multiplied from right. What does it mean? It means that the last transformation you write gets applied to the object first.

让我们看看你的代码:

gl.glScalef(0.8f, 0.8f, 0.8f);
gl.glTranslatef(0.0f, 0.0f, -z);
gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);   //X
gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);   //Y
gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);   //Z
gl.glTranslatef(0.0f, 0.0f, z);

square.draw(gl);    

这意味着,首先,对象被移动到(0.0f, 0.0f, z).然后围绕 Z 旋转,然后围绕 Y 旋转,然后围绕 X 旋转,然后移动 (0.0f, 0.0f, -z) 并最终缩放.

This means that, first, the object is moved to (0.0f, 0.0f, z). Then it is rotated around Z, then around Y, then around X, then moved by (0.0f, 0.0f, -z) and finally scaled.

您的缩放比例正确.你把它放在第一位,所以它最后被应用.你也得到了

You got the scaling right. You put it first, so it gets applied last. You also got

gl.glTranslatef(0.0f, 0.0f, -z);

在正确的位置,因为您首先要旋转对象然后移动它.请注意,当您旋转一个对象时,它总是围绕基本坐标旋转,即 (0, 0, 0).如果要围绕自己的轴旋转对象,则对象本身应位于 (0, 0, 0) 中.

in the right place, because you first want to rotate the object then move it. Note that, when you rotate an object, it ALWAYS rotates around the base coordinate, that is (0, 0, 0). If you want to rotate the object around its own axes, the object itself should be in (0, 0, 0).

所以,在你写之前

square.draw(gl);

你应该有轮换.您的代码现在的方式是将对象移远(通过编写

you should have the rotations. The way your code is right now, you move the object far (by writing

gl.glTranslatef(0.0f, 0.0f, z);

before square.draw(gl);) 和 THEN rotate 把事情搞砸了.删除那条线会让你更接近你需要的东西.因此,您的代码将如下所示:

before square.draw(gl);) and THEN rotate which messes things up. Removing that line gets you much closer to what you need. So, your code will look like this:

gl.glScalef(0.8f, 0.8f, 0.8f);
gl.glTranslatef(0.0f, 0.0f, -z);
gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);   //X
gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);   //Y
gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);   //Z

square.draw(gl);    

现在正方形应该就地旋转了.

Now the square should rotate in place.

注意:运行后,你会发现正方形的旋转会比较尴尬.例如,如果您绕 z 旋转 90 度,那么由于先前的旋转,绕 x 旋转看起来就像绕 y 旋转.目前,这对你来说可能没问题,但如果你想让它看起来真的很好,你应该这样做:

Note: After you run this, you will see that the rotation of the square would be rather awkward. For example, if you rotate around z by 90 degrees, then rotating around x would look like rotating around y because of the previous rotation. For now, this may be ok for you, but if you want to it to look really good, you should do it like this:

想象一下,您不是在旋转物体,而是围绕物体旋转相机,观察物体.通过更改 xrotyrotzrot,您可以在围绕对象的球体上移动相机.然后,一旦找出相机的位置,您可以进行数学运算并获得正确的参数来调用 glRotatefglTranslatef 或者使用 gluLookAt.

Imagine, you are not rotating the object, but rotating a camera around the object, looking at the object. By changing xrot, yrot and zrot, you are moving the camera on a sphere around the object. Then, once finding out the location of the camera, you could either do the math and get the correct parameters to call glRotatef and glTranslatef or, use gluLookAt.

这需要对数学和 3D 想象力有一定的了解.因此,如果您在第一天没有做对,请不要沮丧.

This requires some understanding of math and 3d imagination. So if you don't get it right the first day, don't get frustrated.

这是如何沿旋转对象坐标旋转的思路;

This is the idea of how to rotate along rotated object coordinates;

首先,假设您围绕 z 进行旋转.所以你有

First, let's say you do the rotation around z. Therefore you have

gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);   //Z

现在,全局 Y 单位向量显然是 (0, 1, 0),但是对象已经旋转,因此 它的 Y 单位向量也已经旋转.该向量由下式给出:

Now, the global Y unit vector is obviously (0, 1, 0), but the object has rotated and thus its Y unit vector has also rotated. This vector is given by:

[cos(zrot) -sin(zrot) 0]   [0]   [-sin(zrot)]
[sin(zrot)  cos(zrot) 0] x [1] = [ cos(zrot)]
[0          0         1]   [0]   [ 0        ]

因此,围绕 y 的旋转应该是这样的:

Therefore, your rotation around y, should be like this:

gl.glRotatef(yrot, -sin(zrot), cos(zrot), 0.0f);   //Y-object

到目前为止,您可以尝试此方法(禁用围绕 x 旋转)并查看它是否符合您想要的方式(我做到了,并且成功了).

You can try this so far (disable rotation around x) and see that it looks like the way you want it (I did it, and it worked).

现在对于 x,它变得非常复杂.为什么?因为,X单位向量不仅首先围绕z向量旋转,而是在围绕(-sin(zrot), cos(zrot), 0)向量旋转之后.

Now for x, it gets very complicated. Why? Because, the X unit vector is not only first rotated around the z vector, but after it is rotated around the (-sin(zrot), cos(zrot), 0) vector.

所以现在对象坐标中的 X 单位向量是

So now the X unit vector in the object's cooridnate is

                   [cos(zrot) -sin(zrot) 0]   [1]                      [cos(zrot)]
Rot_around_new_y * [sin(zrot)  cos(zrot) 0] x [0] = Rot_around_new_y * [sin(zrot)]
                   [0          0         1]   [0]                      [0        ]

我们称这个向量为 (u_x, u_y, u_z).那么你的最终旋转(围绕 X 的旋转)将是这样的:

Let's call this vector (u_x, u_y, u_z). Then your final rotation (the one around X), would be like this:

gl.glRotatef(xrot, u_x, u_y, u_z);   //X-object

所以!如何找到矩阵Rot_around_new_y?请参阅此处了解围绕任意轴的旋转.转到第 6.2 节,第一个矩阵,得到 3*3 子矩阵旋转(即忽略与平移相关的最右边的列)并放入 (-sin(zrot), cos(zrot), 0) 作为 (u, v, w) 轴,theta 作为 yrot.

So! How to find the matrix Rot_around_new_y? See here about rotation around arbitrary axis. Go to section 6.2, the first matrix, get the 3*3 sub matrix rotation (that is ignore the rightmost column which is related to translation) and put (-sin(zrot), cos(zrot), 0) as the (u, v, w) axis and theta as yrot.

我不会在这里做数学,因为它需要付出很多努力,最终我还是会在附近的某个地方犯错.但是,如果您非常小心并准备好仔细检查它们几次,则可以将其写下来并进行矩阵乘法.

I won't do the math here because it requires a lot of effort and eventually I'm going to make a mistake somewhere around there anyway. However, if you are very careful and ready to double check them a couple of times, you could write it down and do the matrix multiplications.

附加说明:计算 Rot_around_new_y 的一种方法也可以使用 四元数.四元数定义为一个 4d 向量 [xs, ys, zs, c],它对应于围绕 [x, y, z] 旋转一个角度,其 >sins,其 cosc.

Additional note: one way to calculate Rot_around_new_y could also be using Quaternions. A quaternion is defined as a 4d vector [xs, ys, zs, c], which corresponds to rotation around [x, y, z] by an angle whose sin is s and whose cos is c.

这个[x, y, z]是我们的新Y",即[-sin(zrot), cos(zrot), 0].角度是 yrot.因此,围绕 Y 旋转的四元数为:

This [x, y, z] is our "new Y", i.e. [-sin(zrot), cos(zrot), 0]. The angle is yrot. The quaternion for rotation around Y is thus given as:

q_Y = [-sin(zrot)*sin(yrot), cos(zrot)*sin(yrot), 0, cos(yrot)]

最后,如果你有一个四元数[a, b, c, d],对应的旋转矩阵给出为:

Finally, if you have a quaternion [a, b, c, d], the corresponding rotation matrix is given as:

[1 - 2b^2 - 2c^2        2ab + 2cd           2ac - 2bd   ]
[   2ab - 2cd        1 - 2a^2 - 2c^2        2bc - 2ad   ]
[   2ac - 2bd           2bc + 2ad        1 - 2a^2 - 2b^2]

这篇关于是否可以围绕自己的轴而不是围绕基本坐标的轴旋转对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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