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

Nul*_*ion 13 opengl opengl-es

我正在跟踪谷歌的OpenGL es旋转示例,在我的Android应用程序上旋转一个简单的方形(不是多维数据集),例如这段代码:

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
Run Code Online (Sandbox Code Playgroud)

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

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

编辑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;
}
Run Code Online (Sandbox Code Playgroud)

平方的绘制:

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

}
Run Code Online (Sandbox Code Playgroud)

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);
.
.
.
Run Code Online (Sandbox Code Playgroud)

Sha*_*baz 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);    
Run Code Online (Sandbox Code Playgroud)

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

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

gl.glTranslatef(0.0f, 0.0f, -z);
Run Code Online (Sandbox Code Playgroud)

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

所以,就在你写作之前

square.draw(gl);
Run Code Online (Sandbox Code Playgroud)

你应该有轮换.你的代码现在的方式,你移动对象远(写作

gl.glTranslatef(0.0f, 0.0f, z);
Run Code Online (Sandbox Code Playgroud)

之前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);    
Run Code Online (Sandbox Code Playgroud)

现在广场应该旋转到位.

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

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

这需要对数学和3D想象有所了解.因此,如果您在第一天没有做到正确,请不要感到沮丧.

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

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

gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);   //Z
Run Code Online (Sandbox Code Playgroud)

现在,全局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        ]
Run Code Online (Sandbox Code Playgroud)

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

gl.glRotatef(yrot, -sin(zrot), cos(zrot), 0.0f);   //Y-object
Run Code Online (Sandbox Code Playgroud)

你可以尝试这个到目前为止(禁用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        ]
Run Code Online (Sandbox Code Playgroud)

我们称这个向量(u_x,u_y,u_z).然后你的最终轮换(X周围的轮换)将是这样的:

gl.glRotatef(xrot, u_x, u_y, u_z);   //X-object
Run Code Online (Sandbox Code Playgroud)

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

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


附加说明:一种计算方法Rot_around_new_y也可以使用四元数.四元数被定义为4D向量[xs, ys, zs, c],其对应于左右旋转[x, y, z]通过其的角度sins并且其cosc.

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

q_Y = [-sin(zrot)*sin(yrot), cos(zrot)*sin(yrot), 0, cos(yrot)]
Run Code Online (Sandbox Code Playgroud)

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

[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]
Run Code Online (Sandbox Code Playgroud)