是否可以围绕自己的轴而不是围绕基准坐标轴旋转对象?

时间:2011-10-11 10:50:50

标签: opengl opengl-es

我正在关注Android上的OpenGL es旋转示例,以便在我的Android App上旋转一个简单的方块(不是多维数据集),例如此代码:

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

如果只围绕一个轴旋转,它可以正常工作。

但是如果围绕一个轴旋转,之后,围绕另一个轴旋转,则旋转不公平。我的意思是旋转是围绕基础(全局)坐标系的轴而不是方形自己的坐标系完成的。

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

}

VERTEX BUFFER VALUES:

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

4 个答案:

答案 0 :(得分:24)

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

让我们来看看你的代码:

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)并最终缩放。

你有正确的缩放比例。你把它放在第一位,所以最后应用它。你也有了

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

在正确的位置,因为您首先想要旋转对象然后移动它。请注意,旋转对象时,它始终围绕基本坐标旋转,即(0,0,0)。如果要围绕自己的轴旋转对象,则对象本身应该在(0,0,0)中。

所以,就在你写

之前
square.draw(gl);
你应该有轮换。你的代码现在的方式,你移动对象远(通过写

gl.glTranslatef(0.0f, 0.0f, z);
square.draw(gl);之前

然后旋转会让事情变得混乱。删除该行可以让您更接近您的需求。所以,你的代码看起来像这样:

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

现在广场应该旋转到位。

注意:运行此操作后,您将看到方块的旋转相当笨拙。例如,如果绕z旋转90度,则围绕x旋转看起来像是因为前一次旋转而绕y旋转。现在,这对你来说可能没问题,但是如果你想让它看起来真的很好,你应该这样做:

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

这需要对数学和3d想象力有所了解。因此,如果你在第一天没有做好,不要感到沮丧。

编辑:这是如何沿旋转的对象坐标旋转的想法;

首先,假设您围绕z进行旋转。因此你有

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

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

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

因此,你在y周围的旋转应该是这样的:

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

到目前为止你可以尝试这个(禁用x周围的旋转)并看到它看起来像你想要它的方式(我做了,它工作)。

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

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

                   [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周围的轮换)将是这样的:

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

原来如此!如何找到矩阵Rot_around_new_y?有关围绕任意轴的旋转,请参阅here。转到6.2节,第一个矩阵,得到3 * 3子矩阵旋转(忽略与翻译有关的最右边的列)并将(-sin(zrot), cos(zrot), 0)作为(u, v, w)轴并theta } yrot

我不会在这里做数学,因为它需要付出很多努力,最终我会在那里的某个地方犯错误。但是,如果你非常小心并准备好多次检查它们,你可以把它写下来并进行矩阵乘法。


附加说明:计算Rot_around_new_y的一种方法也可能是使用Quaternions。四元数定义为4d向量[xs, ys, zs, c],对应于[x, y, z]周围的sins且其cos为{{1}的角度}}

c是我们的“新Y”,即[x, y, z]。角度为[-sin(zrot), cos(zrot), 0]。因此围绕Y旋转的四元数为:

yrot

最后,如果您有四元数q_Y = [-sin(zrot)*sin(yrot), cos(zrot)*sin(yrot), 0, cos(yrot)] ,则相应的旋转矩阵is given as

[a, b, c, d]

答案 1 :(得分:3)

我对openGL几乎一无所知,但我想转换为0,旋转然后翻译应该有效......

gl.glTranslatef(-x, -y, -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(x, y, z);

答案 2 :(得分:3)

我认为你需要四元数才能做你想做的事。使用关于坐标轴的旋转在某些时候起作用,但最终会受到“万向节锁定”的影响。当您想要的旋转靠近坐标轴时会发生这种情况,并且当轴周围所需的旋转接近180度时会产生不必要的回转。

四元数是一个数学对象,表示围绕定义为3D矢量的任意轴的旋转。要在openGL中使用它,您可以从四元数生成矩阵并将其乘以模型视图矩阵。这将转换您的世界坐标,以便旋转方形。

您可以在此处获取更多信息http://content.gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation

我有一个Quaternion C ++类,如果有帮助我可以发给你。

答案 3 :(得分:0)

尝试添加

glMatrixMode(GL_MODELVIEW);
glPushMatrix();

在旋转的单个多维数据集的渲染代码之前,然后

glPopMatrix();
渲染完成后

。它将为您提供额外的视图矩阵,而不会影响您的主要模型视图矩阵。

基本上它的作用是创建一个新的模型视图相机,渲染,然后销毁它。