OpenGL旋转问题

时间:2010-10-24 11:08:49

标签: java android opengl-es

我正在通过阅读教程并应用我已经知道的知识来学习Java和OpenGL ES for Android。在旋转物体时,我现在遇到了一堵砖墙。

通过触摸屏幕旋转立方体是没有问题的。但是如果我将立方体向上或向下旋转180度,那么当我现在尝试向左或向右旋转立方体时,它会被反转。我知道为什么会这样,但我找不到解决办法。

如果有人想测试它,代码如下:

文件“Rotating.java”:

package com.test.opengl;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

public class Rotating extends Activity {

    private GLControlView glControlView;

    @Override
    public void onCreate( Bundle savedInstanceState ) {
        super.onCreate( savedInstanceState );

        this.requestWindowFeature( Window.FEATURE_NO_TITLE );
        getWindow().setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN );

        glControlView = new GLControlView( this );
        setContentView( glControlView );

    }

}

文件“GLControlView.java”:

package com.test.opengl;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.opengl.GLSurfaceView.Renderer;
import android.view.MotionEvent;

public class GLControlView extends GLSurfaceView implements Renderer {

    private Context context;

    private float xPrevious, yPrevious;
    private float xRotation = 0.0f, yRotation = 0.0f;

    private SimpleCubeObject cubeObject;

    public GLControlView( Context context ) {
        super( context );

        this.context = context;

        this.setRenderer( this );

        this.requestFocus();
        this.setFocusableInTouchMode( true );

        cubeObject = new SimpleCubeObject();

    }

    public void onSurfaceCreated( GL10 gl, EGLConfig config ) {

        gl.glClearColor( 0.0f, 0.0f, 0.0f, 0.5f );
        gl.glShadeModel( GL10.GL_SMOOTH );
        gl.glClearDepthf( 1.0f );
        gl.glEnable( GL10.GL_DEPTH_TEST );
        gl.glDepthFunc( GL10.GL_LEQUAL );
        gl.glHint( GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST );

    }

    public void onDrawFrame( GL10 gl ) {

        gl.glClear( GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT );
        gl.glLoadIdentity();
        gl.glTranslatef( 0.0f, 0.0f, -10.0f );

        gl.glPushMatrix();

        gl.glRotatef( xRotation, 1.0f, 0.0f, 0.0f );
        gl.glRotatef( yRotation, 0.0f, 1.0f, 0.0f );

        gl.glPushMatrix();
        cubeObject.draw( gl );
        gl.glPopMatrix();

        gl.glPopMatrix();

    }

    public void onSurfaceChanged( GL10 gl, int width, int height ) {

        gl.glViewport( 0, 0, width, height );
        gl.glMatrixMode( GL10.GL_PROJECTION );
        gl.glLoadIdentity();
        GLU.gluPerspective( gl, 45.0f, ( ( float )width / ( float )height ), 0.1f, 100.0f );
        gl.glMatrixMode( GL10.GL_MODELVIEW );
        gl.glLoadIdentity();

    }

    @Override
    public boolean onTouchEvent( MotionEvent event ) {

        float xEvent = event.getX();
        float yEvent = event.getY();

        switch( event.getAction() ) {

            case MotionEvent.ACTION_DOWN: {

                xPrevious = xEvent;
                yPrevious = yEvent;

                return true;

            }

            case MotionEvent.ACTION_MOVE: {

                float xDelta = xEvent - xPrevious;
                float yDelta = yEvent - yPrevious;

                xRotation += ( yDelta * 0.5f );
                yRotation += ( xDelta * 0.5f );

                xPrevious = xEvent;
                yPrevious = yEvent;

                return true;

            }

            default: return super.onTouchEvent( event );

        }

    }

}

文件“SimpleCubeObject.java”:

package com.test.opengl;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

public class SimpleCubeObject {

    private int[] textures = new int[ 1 ];

    private float[] colors = {

            0.0f, 0.0f, 0.0f, 1.0f,
            1.0f, 0.0f, 0.0f, 1.0f,
            0.0f, 1.0f, 0.0f, 1.0f,
            0.0f, 0.0f, 1.0f, 1.0f,
            1.0f, 0.0f, 1.0f, 1.0f,
            0.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 0.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f

    };

    private short[] indices = {

            0, 1, 2, 0, 2, 3,
            1, 5, 6, 1, 6, 2,
            2, 6, 7, 2, 7, 3,
            3, 7, 4, 3, 4, 0,
            0, 4, 5, 0, 5, 1,
            7, 6, 5, 7, 5, 4

    };

    private float[] vertices = {

            -1.0f,  1.0f, -1.0f,
            -1.0f,  1.0f,  1.0f,
             1.0f,  1.0f,  1.0f,
             1.0f,  1.0f, -1.0f,
            -1.0f, -1.0f, -1.0f,
            -1.0f, -1.0f,  1.0f,
             1.0f, -1.0f,  1.0f,
             1.0f, -1.0f, -1.0f

    };

    private FloatBuffer colorBuffer;
    private ShortBuffer indexBuffer;
    private FloatBuffer vertexBuffer;

    public SimpleCubeObject() {

        ByteBuffer cbb = ByteBuffer.allocateDirect( colors.length * 4 );
        cbb.order( ByteOrder.nativeOrder() );
        colorBuffer = cbb.asFloatBuffer();
        colorBuffer.put( colors );
        colorBuffer.position( 0 );

        ByteBuffer ibb = ByteBuffer.allocateDirect( indices.length * 2 );
        ibb.order( ByteOrder.nativeOrder() );
        indexBuffer = ibb.asShortBuffer();
        indexBuffer.put( indices );
        indexBuffer.position( 0 );

        ByteBuffer vbb = ByteBuffer.allocateDirect( vertices.length * 4 );
        vbb.order( ByteOrder.nativeOrder() );
        vertexBuffer = vbb.asFloatBuffer();
        vertexBuffer.put( vertices );
        vertexBuffer.position( 0 );

    }

    public void draw( GL10 gl ) {

        gl.glFrontFace( GL10.GL_CCW );
        gl.glEnable( GL10.GL_CULL_FACE );
        gl.glCullFace( GL10.GL_BACK );

        gl.glBindTexture( GL10.GL_TEXTURE_2D, textures[ 0 ] );

        gl.glEnableClientState( GL10.GL_COLOR_ARRAY );
        gl.glEnableClientState( GL10.GL_TEXTURE_COORD_ARRAY );

        gl.glColorPointer( 4, GL10.GL_FLOAT, 0, colorBuffer );
        gl.glVertexPointer( 3, GL10.GL_FLOAT, 0, vertexBuffer );

        gl.glDrawElements( GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer );

        gl.glDisableClientState( GL10.GL_VERTEX_ARRAY );
        gl.glDisableClientState( GL10.GL_COLOR_ARRAY );

        gl.glDisable( GL10.GL_CULL_FACE );

    }

}

我当然希望有人可以帮助我。我一如既往地相信解决方案简单易行 - 只是我现在无法看到它。

3 个答案:

答案 0 :(得分:1)

当旋转的每个后续部分改变参考系时,该问题是旋转的欧拉角表示(即将旋转存储为来自参考轴的旋转)所固有的。 您可以尝试使用一些不同的对象旋转表示,如四元数或 - 根据Ishtar的建议 - 旋转矩阵或轴/角度。

如果您想尝试使用以下是四元数的教程: http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation

还有一些不同的建议: http://gpwiki.org/forums/viewtopic.php?t=8611&sid=7d8cb26617084c80c670634d3d7e9f36

http://www.gamedev.net/community/forums/topic.asp?topic_id=491391

答案 1 :(得分:0)

我认为这是你正在进行轮换的顺序。你是否尝试过这种方式:

    gl.glRotatef( yRotation, 0.0f, 1.0f, 0.0f );
    gl.glRotatef( xRotation, 1.0f, 0.0f, 0.0f );

答案 2 :(得分:0)

这并不简单。

xRotation += ( yDelta * 0.5f );
yRotation += ( xDelta * 0.5f );

这不起作用。您的x轴或y轴将不正确,这些是俯仰和滚动轴(?)。不是x轴和y轴。

我认为你需要记住旋转矩阵本身,而不是一些x和y旋转。你最好只有一个旋转的轴。轴当然取决于MotionEvent的方向。并且总旋转距离上的旋转量。

float xDelta = xEvent - xActionDown;//from starting point
float yDelta = yEvent - yActionDown;
float distance = sqrt(xDelta*xDelta+yDelta*yDelta);
float xaxis = xDelta/distance;//normalized: 0.0 <-> 1.0
float yaxis = yDelta/distance;

gl.glRotatef( distance, yaxis, xaxis, 0.0f );//x and y swapped!

我100%确定上述内容不正确。你必须添加一些支票,一个减号等。但我希望你得到基本的想法?