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

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

问题描述

我正在按照 google 的 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 旋转这把事情搞砸了.删除那条线会让你更接近你需要的东西.因此,您的代码将如下所示:

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天全站免登陆