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

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

问题描述

我正在跟踪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.

让我们看一下您的代码:

So let's look at your code:

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