Control a 3d object using sensors?

Tutorials concerning the OpenGL® ES cross-platform API for full-function 2D and 3D graphics on the Google-Android platform.

Control a 3d object using sensors?

Postby rcpinheiro » Mon May 17, 2010 6:00 pm

Hi!
To learn OpenGL I'm trying to adapt the Graphics->OpenGL->Touch Rotate cube in the ApiDemo to respond to sensors.
Has anyone done this or knows of a good tutorial on how to control a 3D object using Android's sensors?

Here's what I've done so far (it kind of works):

Code: Select all
class TouchSurfaceView extends GLSurfaceView {
     private final float SENSOR_SCALE_FACTOR = 90.0f / 9;

    public TouchSurfaceView(Context context) {
        super(context);
        mRenderer = new CubeRenderer();
        setRenderer(mRenderer);
        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensorManager.registerListener(sensorListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_FASTEST);
    }

    private final SensorEventListener sensorListener = new SensorEventListener() {
      @Override public void onAccuracyChanged(Sensor arg0, int arg1) {}

      @Override
      public void onSensorChanged(SensorEvent event) {
         boolean changed=false;

         float[] mValues = event.values;

         if (Math.abs(event.values[0])>1) {   // don't render on small change
            mRenderer.mAngleX = event.values[0] * SENSOR_SCALE_FACTOR;
            changed=true;
         }
         
         if (Math.abs(event.values[1])>1) {
            mRenderer.mAngleY = event.values[1] * SENSOR_SCALE_FACTOR;
            changed=true;
         }
         
         if (changed) requestRender();

      }
    };
rcpinheiro
Junior Developer
Junior Developer
 
Posts: 13
Joined: Fri Apr 02, 2010 6:45 pm

Top

Re: Control a 3d object using sensors?

Postby seed » Tue May 18, 2010 2:36 pm

What does requestRender() do? The Sensor Listener is in a different thread than the GL rendering loop. Be careful there. If requestRender is just setting a flag or some data for onDrawFrame() to use, then you should be ok. If it is actually trying to do some gl calls then look out. Generally, you just want to save off the data you get from the sensor and use it in onDrawFrame(). At least that is what I do.

Not sure if it makes much difference, but I have my Activity implementing the SensorListener rather than the GlSurfaceView doing it.

Code: Select all
   

public class LavaBall extends Activity implements SensorListener{

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mView = new OpenGLRenderer(this);
        setContentView(mView);   
    }
   
    @Override
    protected void onResume()
    {
        super.onResume();
        mSensorManager.registerListener(
            this,
            SensorManager.SENSOR_ACCELEROMETER,
            SensorManager.SENSOR_DELAY_FASTEST);
        mView.onResume();
    }

    static private float   mAccelValues[] = new float[3];
    static private float   mSmoothAccelValues[] = new float[3];

    public void onSensorChanged(int sensor, float[] values) {
        synchronized (this) {
            if (sensor == SensorManager.SENSOR_ACCELEROMETER) {
                for (int i=0 ; i<3 ; i++) {
                    mAccelValues[i] = values[i];
                    mSmoothAccelValues[i] = mSmoothAccelValues[i] +
                        (mAccelValues[i] - mSmoothAccelValues[i])/4;
                }
            }
        }
    }


Note, I am using static data. Then I have some static methods to read the saved off sensor data. Note I am keeping the raw accelerometer values plus ones that I smooth slightly.

Code: Select all
    static public void getSense(Vector3 val)
    {
       val.x=mAccelValues[0];
       val.y=mAccelValues[1];
       val.z=mAccelValues[2];
    };

    static public void getSmoothSense(Vector3 val)
    {
       val.x=mSmoothAccelValues[0];
       val.y=mSmoothAccelValues[1];
       val.z=mSmoothAccelValues[2];
    };


Then I use it in moving stuff in my game in the onDrawFrame call.

Code: Select all
    Vector3 gravity = new Vector3();
    public void move()
    {
        LavaBall.getSense(gravity);

        // Set my acceleration according to gravity.
        acceleration.x=gravity.x;
        acceleration.y=gravity.y;
        acceleration.z=gravity.z;
        Vector3.normalize(acceleration,acceleration);

        // Size it for my world
        Vector3.scale(acceleration,acceleration, 0.002f);
   
        // Update the velocity with the acceleration
        Vector3.add(velocity,velocity,acceleration);
    }


The accelerometer values are just an x,y,z vector relative to your phone orientation. If you think of them as a vector representing gravity, then it is easy to visualize how they should affect stuff in your application.

Hope this helps.
Visit Exit 4 Gaming - http://www.exit4games.com/
Home of LavaBall - http://exit4games.com/?page_id=3
Home of Rebound - http://exit4games.com/?page_id=138
Home of Tap Crazy - http://exit4games.com/?page_id=219
Download "Caveman Pool" From the Market Today!
seed
Senior Developer
Senior Developer
 
Posts: 103
Joined: Mon Mar 15, 2010 3:22 pm

Re: Control a 3d object using sensors?

Postby rcpinheiro » Tue May 18, 2010 10:25 pm

Thanks a lot, seed. That really helped.

My experience with the sensors has been underwhelming. The results aren't so good (heck, my HTC Magic says G is 10.1m/s^2, maybe I live in a high gravity zone!)
Worse, using a phone from other manufacturer gives a different set of results.

The "smoothing" of the results you use makes a lot of sense, sometimes the sensors generate weird results and take a long time to settle.

Good luck with your game!
rcpinheiro
Junior Developer
Junior Developer
 
Posts: 13
Joined: Fri Apr 02, 2010 6:45 pm

Re: Control a 3d object using sensors?

Postby Ramana » Wed May 19, 2010 7:12 am

Hi...iam trying to develop an augment reality app on Android phone.I have camera preview on a surface view.On that i have a 3d grid on GlSurfaceView which i would control using sensors.Now i would like to draw some png images as Markers on the 3d grid.How do i do that?For 3d grid i have defined vertices and connected using indices.I have used gl.glDrawElements(GL10.GL_LINES, indices.length,
GL10.GL_UNSIGNED_SHORT, indexBuffer);
for drawing.
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(0,0,-4);
gl.glScalef(2.0f, 1.0f, 1.0f);
gl.glPushMatrix();
gl.glRotatef(-45 , 1, 0, 0);
sq.draw(gl);
gl.glPopMatrix();
}
Ramana
Junior Developer
Junior Developer
 
Posts: 17
Joined: Wed May 19, 2010 6:57 am

Top

Return to Android 2D/3D Graphics - OpenGL Tutorials

Who is online

Users browsing this forum: No registered users and 4 guests