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

vecaoik1  于 2022-11-04  发布在  其他
关注(0)|答案(5)|浏览(363)

我遵循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

如果你只绕一个轴旋转,它就能正常工作。
但是如果你绕一个轴旋转,然后再绕另一个轴旋转,那么旋转就不公平了。我的意思是,旋转是绕着基准(全局)坐标系的轴进行的,而不是绕着正方形自身的坐标系。
使用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);
.
.
.
ljsrvy3e

ljsrvy3e1#

首先你应该知道的是,在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)向量旋转之后。
所以现在物体坐标中的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]旋转一个Angular ,该Angular 的sins,并且其cosc
这个[x, y, z]是我们的“新Y”,即[-sin(zrot), cos(zrot), 0]。Angular 是yrot。因此,绕Y旋转的四元数给出为:

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

最后,如果您有四元数[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]
0qx6xfy6

0qx6xfy62#

我对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);
pnwntuvh

pnwntuvh3#

我认为你需要四元数来做你想做的事情。使用绕坐标轴的旋转在某些时候是可行的,但最终会受到“万向节锁定”的困扰。当你想要的旋转经过坐标轴附近时,会发生这种情况,并在绕轴所需的旋转接近180度时产生不必要的回转。
四元数是一个数学对象,它表示围绕定义为3D矢量的任意轴的旋转。要在openGL中使用它,您可以从四元数生成一个矩阵,并将其乘以模型视图矩阵。这将转换您的世界坐标,以便旋转正方形。
您可以在这里获得更多信息http://content.gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation
我有一个四元数C++类,我可以发送给你,如果它有助于。

dz6r00yl

dz6r00yl4#

尝试添加

glMatrixMode(GL_MODELVIEW);
glPushMatrix();

在要旋转的单个立方体的渲染代码之前,然后

glPopMatrix();

它会给予你一个额外的视图矩阵来使用,而不会影响你的主模型视图矩阵。
本质上,这是创建一个新的模型视图摄影机,渲染,然后销毁它。

sdnqo3pr

sdnqo3pr5#

我用的是opentk,不过还是一样的。首先移动对象的一半尺寸,然后旋转并移回来:

model = Matrix4.CreateTranslation(new Vector3(-width/2, -height / 2, -depth / 2)) * 

Matrix4.CreateRotationX(rotationX) * 

Matrix4.CreateRotationY(rotationY) * 

Matrix4.CreateRotationZ(rotationZ) *

Matrix4.CreateTranslation(new Vector3(width / 2, height / 2, depth / 2));

相关问题