2010-10-24 6 views
1

J'apprends Java et OpenGL ES pour Android en lisant des tutoriels et en appliquant ce que je sais déjà. Et j'ai maintenant frappé un mur de briques quand il s'agit de faire tourner un objet.Problème de rotation OpenGL

La rotation d'un cube en touchant l'écran ne pose aucun problème. Mais si je fais pivoter le cube de 180 degrés vers le haut ou le bas, alors quand j'essaie maintenant de faire tourner le cube vers la gauche ou vers la droite, il est inversé. Je sais pourquoi cela se passe mais je ne trouve pas de solution.

Le code est ci-dessous si certains veulent le tester:

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

    } 

} 

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

     } 

    } 

} 

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

    } 

} 

J'espère que quelqu'un peut m'aider avec ça. Je crois, comme toujours, que la solution est simple et facile - c'est juste moi qui ne peux pas le voir maintenant.

Répondre

1

Ce problème est inhérent à la représentation des angles d'Euler de la rotation (c'est-à-dire la rotation des rotations à partir des axes de référence) car chaque partie de rotation suivante modifie le cadre de référence. Vous pourriez essayer d'utiliser une représentation différente de la rotation de l'objet, comme des quaternions ou - selon la suggestion d'Ishtar - une matrice de rotation ou un axe/angle.

Voici un tutoriel sur escouades si vous voulez les essayer: http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation

Et aussi quelques suggestions différentes: http://gpwiki.org/forums/viewtopic.php?t=8611&sid=7d8cb26617084c80c670634d3d7e9f36

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

+0

Merci! Cela semble être une mission impossible à assumer, mais les quaternions sont ce dont j'ai besoin. – Espen

0

je pense qu'il est l'ordre que vous faites des rotations Avez-vous essayé de cette façon.

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

je l'ai fait. Cela déplace simplement le problème sur l'autre axe. – Espen

0

Ce n'est pas simple.

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

Cela ne va pas fonctionner. Soit votre axe x ou y ne sera pas correct, ce sont l'axe de tangage et de roulis (?). Pas les axes x et y.

Je pense que vous devrez vous souvenir de la matrice de rotation elle-même, pas de quelques rotations x et y. Tu ferais mieux d'avoir un seul axe sur lequel tu tournes. L'axe dépend bien sûr de la direction du MotionEvent. Et la quantité de rotation sur la distance totale traînée.

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! 

Je suis sûr à 100% que ce qui précède est incorrect. Vous devrez ajouter des chèques, un négatif, etc. Mais j'espère que vous aurez l'idée de base?