AR3D - not R2D2 - augmented reality in 3D.

You are here

Contact

Israel Office

+972-52-838-7222

+972-52-430-5252

Europe office

+33-695-805-004

26.08.2010
AR3D - not R2D2 - augmented reality in 3D.
submitted by: royi

Hello all,
This blog feed is dedicated to augment reality (or "AR").

I was asked to create an Android application that will display a virtual "marker" over "reality" upon the discovery of a "pattern", in short i was asked to create a pattern oriented augmented reality mobile application (not that short, is it?).

Since i'm willing to bet that half of you reread the last line 2 or 3 times and are still wondering what am i blabbing about, this is the time for some glossary:
A mobile pattern oriented AR app workflow is as follows:
1. Reality - what is currently captured in the camera lens and is displayed on the device's screen.
2. Marker - a virtual entity that is projected on to "reality".
3. Pattern - the trigger for the marker to be displayed.

O.k. - after some basics lets start addressing the code.
We start off with an open-source project called "AndAR" which has done an incredible job at making a pattern oriented AR client for android, so what you need to do to obtain the code is to open the terminal and type:
svn checkout http://andar.googlecode.com/svn/trunk/ andar-read-only
In this feed i am referring to the AndAR project that is 1 of the 3 sample projects you get via the SVN,
for further documentation on the project and it's open source assets go to the AndAR project page at:
http://code.google.com/p/andar/
So, what are we getting?
- Pattern recognition.
- Basic pattern customization.
- A single "hard-wired" cube marker in fluorescent-green.
It's a little basic and crude but the implementation is light, easy to read and quite brilliant.

Now for some real programming, in order to present a customized image based marker you need to find the SimpleBox.java file in AndAR/src/edu/dhbw/andar/pub, the draw function initially looks like this:

public final void draw(GL10 gl)
{
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, box);
gl.glNormalPointer(GL10.GL_FLOAT,0, normals);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
}

as you can see, it's pretty basic and straight forward, the function works in phases:
1. It enables vertices and normal arrays in the client.
2. It sets a pointer for each of these arrays (which are declared in the SimpleBox constructor).
3. It draws the arrays by vertex and since it's 3 dimensional every vertex is declared as 3 float values for the x,y and z axis so a quick calculation will tell you that a cube will need 92(!) float values.
4. It disables vertices and normal arrays in the client.

and after the modification it looks like this: (additions are marked by //)

public final void draw(GL10 gl)
{
/
/Bitmap bitmap = CustomActivity.b; //1- an explanation is appended
//gl.glEnable(GL10.GL_CULL_FACE); // Enable face culling.
/
/gl.glCullFace(GL10.GL_BACK); // What faces to remove with the face culling.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
//gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
/
/gl.glEnable(GL10.GL_TEXTURE_2D);
//loadTextureFromBitmap(gl, bitmap); //2 - function is appended
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, box);
/
/gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, tb); //3 - values are appended
gl.glNormalPointer(GL10.GL_FLOAT,0, normals);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
//gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
/
/gl.glDisable(GL10.GL_TEXTURE_2D);
}

** 1 - In CustomActivity.java i added:

public static Bitmap b;
b = BitmapFactory.decodeResource(this.getResources(), R.drawable.bgtex); //where bgtex is a PNG file //located in res/drawable

** 2 - In SimpleBox i added this function:

public int loadTextureFromBitmap(GL10 gl, Bitmap bitmap)
{
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);
ByteBuffer imageBuffer = ByteBuffer.allocateDirect(bitmap.getHeight() * bitmap.getWidth() * 4);
imageBuffer.order(ByteOrder.nativeOrder());
byte buffer[] = new byte[4];
for(int i = 0; i < bitmap.getHeight(); i++)
{
for(int j = 0; j < bitmap.getWidth(); j++)
{
int color = bitmap.getPixel(j, i);
buffer[0] = (byte)Color.red(color);
buffer[1] = (byte)Color.green(color);
buffer[2] = (byte)Color.blue(color);
buffer[3] = (byte)Color.alpha(color);
imageBuffer.put(buffer);
}
}
imageBuffer.position(0);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(), 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, imageBuffer);
return textures[0];
}

**3 - in the SimpleBox constructor i added:

float[] tc = new float[]
{
1.0f, 1.0f,
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,

1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, }; tb = makeFloatBuffer(tc);

I'd like to end this feed with an acknowledgment, if it wasn't for the work of open source projects as "AndAR"
(http://code.google.com/p/andar/) it is very plausible that this blog feed wouldn't be possible, so, I thank you dearly.
That's it, you can see the result in the appended screen shot.

Add new comment

blogs