Hi all,

I'm very new to Android and to QCAR, so please bare with me.

I'm trying to display 2D image on the tracked image. I can get the screenPoint and display image on the screen by using `QCAR::Vec2F screenPoint = QCAR::Tool::projectPoint(cameraCalibration, trackable->getPose(), QCAR::Vec3F(0, 0, 0));`

I need also to scale & rotate the 2D image, so I think getPose function on trackable object can be the solution. Can someone explain the values in 3*4 matrix that getPose function returns? Are they x, y, z, u, v etc?

Oz

The pose is a 3D orientation matrix, analogous to the modelview matrix in OpenGL. It is used alongside the projection matrix to bring 3D world coordinates to screen coordinates. For a full look at the set of transformations involved, see the OpenGL FAQ (section 9.011): http://www.opengl.org/resources/faq/technical/transformations.htm

The pose is a 3D transformation, which means you won't easily get a set of 2D transformations out of it for manipulating 2D images on the screen (you're missing a dimension to rotate in). Instead, I would suggest rendering your image on a 3D plane using OpenGL. It's pretty easy, here are the steps:

1) Start with the ImageTargets sample project. Open ImageTargets.cpp, located in the jni folder.

2) Add the following just after the includes at the top:

```#include <QCAR/ImageTarget.h>

static const float planeVertices[] =
{
-0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.5, 0.5, 0.0, -0.5, 0.5, 0.0,
};

static const float planeTexcoords[] =
{
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0
};

static const float planeNormals[] =
{
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0
};

static const unsigned short planeIndices[] =
{
0, 1, 2, 0, 2, 3
};
```

3) Now replace the OpenGL ES 2.0 rendering code in the renderFrame method with the following:

```// assuming this is an image target
QCAR::Vec2F targetSize = ((QCAR::ImageTarget *) trackable)->getSize();

QCAR::Matrix44F modelViewProjection;

SampleUtils::translatePoseMatrix(0.0f, 0.0f, kObjectScale,
&modelViewMatrix.data[0]);
SampleUtils::scalePoseMatrix(targetSize.data[0], targetSize.data[1], 1.0f,
&modelViewMatrix.data[0]);
SampleUtils::multiplyMatrix(&projectionMatrix.data[0],
&modelViewMatrix.data[0] ,
&modelViewProjection.data[0]);

glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &planeVertices[0]);
glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &planeNormals[0]);
glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &planeTexcoords[0]);

glEnableVertexAttribArray(vertexHandle);
glEnableVertexAttribArray(normalHandle);
glEnableVertexAttribArray(textureCoordHandle);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, thisTexture->mTextureID);
glUniformMatrix4fv(mvpMatrixHandle, 1, GL_FALSE,
(GLfloat*)&modelViewProjection.data[0] );
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT,
(const GLvoid*) &planeIndices[0]);
```

4) Build the native code using ndk-build, then refresh the Eclipse project and run the app. You should see the teapot texture stretched over the image target.

5) You can swap the texture by adding your image to the project's assets folder (png or jpg format). Then open ImageTargets.java and replace the teapot texture filenames with your own.

Let me know if you have any questions!

- Kim

I'm still trying to figure out how to get the center of each trackable for comparison purposes and to draw lines between each. I want to apply a tour algorithm to it.

Edit:
http://ar.qualcomm.at/node/2000311

I keep finding answers from her threads, it just takes research in OpenGL to understand exactly what it is I want, so that I know what to search for. Hopefully a lot of her answers and work get put into the documentation as some point.

Hi Kim,

Your answer is very helpful for me, newbie to openGL. I still have a question, if i dont like to use texture, i want to draw with the defined color, how can i do that ?

I try to comment the line :
`glBindTexture(GL_TEXTURE_2D, thisTexture->mTextureID);`
`glColor3f(1.0,1.0,1.0); `

But i seem not work, it raise an error

```C:/Development/Android/qcar-sdk-1-0-0/samples/ImageTargets/jni/ImageTargets.cpp:
485: error: 'glColor3f' was not declared in this scope```

glColor3f is only available in OpenGL ES 1.x. You can switch the application to compile against the 1.1 libraries by setting the USE_OPENGL_ES_1_1 flag in Android.mk to true. The ImageTargets sample includes rendering code for both the 1.1 and 2.0 versions of OpenGL.

- Kim

It still raise an same error after i set USE_OPENGL_ES_1_1 := true and move glColor3f into the code use for drawing in opengl 1.1

Here is the code, can you take a look :

```#ifdef USE_OPENGL_ES_1_1
glMatrixMode(GL_PROJECTION);

glMatrixMode(GL_MODELVIEW);

// Draw object:

glColor3f(1.0f,1.0f,1.0f);
QCAR::Vec2F targetSize = ((QCAR::ImageTarget *) trackable)->getSize();

glTranslatef(0.f, 0.f, kObjectScale);
glScalef(targetSize.data[0], targetSize.data[1], 1.0f);

glTexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*) &planeTexcoords[0]);
glVertexPointer(3, GL_FLOAT, 0, (const GLvoid*) &planeVertices[0]);
glNormalPointer(GL_FLOAT, 0,  (const GLvoid*) &planeNormals[0]);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT,  (const GLvoid*) &planeIndices[0]);

#else```

Thanks

Ah, sorry, it looks like only glColor4f is supported in OpenGL ES:

http://www.khronos.org/opengles/sdk/1.1/docs/man/glColor.xml

- Kim

hi kim,

I want to show 3d object model size such that it will cover entire target marker, for that i need widht and height of marker, I found this code snippet for getting size

QCAR::Vec2F targetSize = ((QCAR::ImageTarget *) trackable)->getSize()

but it is not compiling , it is showing error that:

error: 'ImageTarget' is not a member of 'QCAR'

```#include <QCAR/ImageTarget.h>
```

- Kim

If you look through the renderFrame method you should find a chunk of code that looks like this:

```QCAR::Matrix44F modelViewProjection;

SampleUtils::translatePoseMatrix(0.0f, 0.0f, kObjectScale,
&modelViewMatrix.data[0]);
SampleUtils::scalePoseMatrix(kObjectScale, kObjectScale, kObjectScale,
&modelViewMatrix.data[0]);
SampleUtils::multiplyMatrix(&projectionMatrix.data[0],
&modelViewMatrix.data[0] ,
&modelViewProjection.data[0]);

glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &teapotVertices[0]);
glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &teapotNormals[0]);
glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &teapotTexCoords[0]);

glEnableVertexAttribArray(vertexHandle);
glEnableVertexAttribArray(normalHandle);
glEnableVertexAttribArray(textureCoordHandle);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, thisTexture->mTextureID);
glUniformMatrix4fv(mvpMatrixHandle, 1, GL_FALSE,
(GLfloat*)&modelViewProjection.data[0] );
glDrawElements(GL_TRIANGLES, NUM_TEAPOT_OBJECT_INDEX, GL_UNSIGNED_SHORT,
(const GLvoid*) &teapotIndices[0]);
```

That is the "OpenGL ES 2.0 rendering code." It is the same for QCAR 1.0 and 1.5. Replace only that part with the code from my post.

- Kim

Quote:

And even I use same dimensional, it also show whole black.

That was going to be my first guess... Make sure the images are 1024x1024 or smaller, and it's safest to use power-of-two dimensions (e.g. 128, 256, 512, 1024).

Maybe the images were saved with a strange color profile? Could you attach one here, or send to

?

- Kim

Many devices do not support non-power-of-two (NPOT) textures. This is a hardware limitation.

You can stretch your image to a power-of-two (POT) and then render it on a plane of the correct dimensions. This will "undo" the stretch so the final image looks correct.

Another option is to write your own Texture class that places your NPOT image in the next closest POT texture. So for your 200x512 image it would create a 256x512 texture and place the image in one corner of the texture. Then you have to adjust the texcoords of your model to match. This is more advanced.

Or, if you really don't want to change the rendering code per image, you could pad out each image with transparent pixels to make it a POT. E.g. create a 256x512 canvas with a transparent background and place your image in the center. Then use OpenGL blending to hide the transparent border:

```glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
```

That's a little less efficient, but your code won't need to know the original image size.

- Kim

That code would go just before you render your textured plane. Look for similar calls to glEnable in the renderFrame method. Also make sure you disable blending at the end of the function:

```glDisable(GL_BLEND);
```

Again, this method assumes you've preprocessed all of your images to make them a power-of-two by padding them with transparent pixels.

- Kim

@ ozayolkan, Omen_20, tsengvn, gilesian, and lhslktg.

Guys, why don't you use the Unity3d game engine for all of this? It is really easy to use, QCAR integrates very nicely with it, and it will save you a lot of time.

i have used sample app and replaced teapot image with custom image but now am not getting texture in my 3d image it is displaying black, I am not getting why it is happening lik this, why texture is not getting any idea???. Thanks in advance..

i have used sample app and replaced teapot image with custom image but now am not getting texture in my 3d image it is displaying black, I am not getting why it is happening lik this, why texture is not getting any idea???. Thanks in advance..

What are the dimensions of your texture?

They need to be a power of 2 in size e.g. 256*256 pixels

N

Also make sure that you're loading the new texture. Which SDK are you using?