8

In Android, I am trying to integrate JPCT to Vuforia by using this tutorial: http://www.jpct.net/wiki/index.php/Integrating_JPCT-AE_with_Vuforia

The first time the application is launched, it works, but when I go back and I touch "play" again, it crashes.

These are the errors in my LogCat when the application crashes:

FATAL EXCEPTION: main
java.lang.RuntimeException: [ 1362671862690 ] - ERROR:  A texture with the name  'texture' has been declared twice!
at com.threed.jpct.Logger.log(Logger.java:189)
at com.threed.jpct.TextureManager.addTexture(TextureManager.java:138)
at com.qualcomm.QCARSamples.ImageTargets.ImageTargetsRenderer.<init>    (ImageTargetsRenderer.java:78)
at     com.qualcomm.QCARSamples.ImageTargets.ImageTargets.initApplicationAR(ImageTargets.java:807)
at com.qualcomm.QCARSamples.ImageTargets.ImageTargets.updateApplicationStatus(ImageTargets.java:649)
at com.qualcomm.QCARSamples.ImageTargets.ImageTargets.updateApplicationStatus(ImageTargets.java:641)
at com.qualcomm.QCARSamples.ImageTargets.ImageTargets.access$3(ImageTargets.java:598)
at com.qualcomm.QCARSamples.ImageTargets.ImageTargets$InitQCARTask.onPostExecute(ImageTargets.java:226)
at com.qualcomm.QCARSamples.ImageTargets.ImageTargets$InitQCARTask.onPostExecute(ImageTargets.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:417)
at android.os.AsyncTask.access$300(AsyncTask.java:127)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605)
at dalvik.system.NativeStart.main(Native Method)

Here is Imagetargetsrenderer.java code

public class ImageTargetsRenderer implements GLSurfaceView.Renderer
{
public boolean mIsActive = false;

/** Reference to main activity **/
public ImageTargets mActivity;

/** Native function for initializing the renderer. */
public native void initRendering();

/** Native function to update the renderer. */
public native void updateRendering(int width, int height);

private World world=null;
private Light sun = null;
private Object3D cube = null;
private FrameBuffer fb = null;
private float[] modelViewMat=null;
private Camera cam=null;
private float fov=0;
private float fovy=0;

//private Camera cam=null;
private Object3D plane=null;

public ImageTargetsRenderer(ImageTargets activity){
    this.mActivity = activity;
    world = new World();
world.setAmbientLight(20, 20, 20);

sun = new Light(world);
sun.setIntensity(250, 250, 250);

// Create a texture out of the icon...:-)
Texture texture = new Texture(BitmapHelper.rescale(BitmapHelper.convert(mActivity.getResources().getDrawable(R.drawable.ic_launcher)), 64, 64));
TextureManager.getInstance().addTexture("texture", texture);

cube = Primitives.getCube(10);
cube.calcTextureWrapSpherical();
cube.setTexture("texture");
cube.strip();
cube.build();

world.addObject(cube);

 cam = world.getCamera();
/*cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
cam.lookAt(cube.getTransformedCenter());*/

SimpleVector sv = new SimpleVector();
SimpleVector position=new SimpleVector();
position.x=0;
position.y=0;
position.z=-10;

cube.setOrigin(position);
sv.set(cube.getTransformedCenter());
sv.y -= 100;
sv.z -= 100;

sun.setPosition(sv);
MemoryHelper.compact();

}




/** Called when the surface is created or recreated. */
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
    DebugLog.LOGD("GLRenderer::onSurfaceCreated");

    // Call native function to initialize rendering:
    initRendering();

    // Call QCAR function to (re)initialize rendering after first use
    // or after OpenGL ES context was lost (e.g. after onPause/onResume):
    QCAR.onSurfaceCreated();
}


/** Called when the surface changed size. */
public void onSurfaceChanged(GL10 gl, int width, int height)
{
    DebugLog.LOGD("GLRenderer::onSurfaceChanged");

    // Call native function to update rendering when render surface
    // parameters have changed:
    updateRendering(width, height);

    // Call QCAR function to handle render surface size changes:
    QCAR.onSurfaceChanged(width, height);

    if (fb != null) {
        fb.dispose();
   }
   fb = new FrameBuffer(width, height);
}


/** The native render function. */
public native void renderFrame();


/** Called to draw the current frame. */
public void onDrawFrame(GL10 gl)
{
    if (!mIsActive)
        return;

    // Update render view (projection matrix and viewport) if needed:
    mActivity.updateRenderView();

    //updateCamera();

    // Call our native function to render content

    renderFrame();

    world.renderScene(fb);

    world.draw(fb);

    fb.display(); 

}

public void updateModelviewMatrix(float mat[]) {
    modelViewMat = mat;
}

public void setFov(float fov_) {
    fov = fov_;
}

public void setFovy(float fovy_) {
    fovy = fovy_;
}

public void updateCamera() {
    Matrix m = new Matrix();
    m.setDump(modelViewMat);
        cam.setBack(m);
        cam.setFOV(fov);
        cam.setYFOV(fovy);

}

}

Code for imagetargets.cpp

JNIEXPORT void JNICALL
Java_com_qualcomm_QCARSamples_ImageTargets_ImageTargetsRenderer_renderFrame(JNIEnv  *env, jobject obj)
{

const QCAR::CameraCalibration& cameraCalibration =       QCAR::CameraDevice::getInstance().getCameraCalibration();
QCAR::Vec2F size = cameraCalibration.getSize();
QCAR::Vec2F focalLength = cameraCalibration.getFocalLength();
float fovyRadians = 2 * atan(0.5f * size.data[1] / focalLength.data[1]);
float fovRadians = 2 * atan(0.5f * size.data[0] / focalLength.data[0]);

jclass activityClass = env->GetObjectClass(obj);
jfloatArray modelviewArray = env->NewFloatArray(16);
jmethodID updateMatrixMethod = env->GetMethodID(activityClass, "updateModelviewMatrix",    "([F)V");

jmethodID fovMethod = env->GetMethodID(activityClass, "setFov", "(F)V");
jmethodID fovyMethod = env->GetMethodID(activityClass, "setFovy", "(F)V");

// test
jclass newClass = env->GetObjectClass(obj);
jmethodID updateCameraMethod = env->GetMethodID(newClass, "updateCamera", "()V");

// Clear color and depth buffer 
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Get the state from QCAR and mark the beginning of a rendering section
QCAR::State state = QCAR::Renderer::getInstance().begin();
// Explicitly render the Video Background
QCAR::Renderer::getInstance().drawVideoBackground();
// Did we find any trackables this frame?
for(int tIdx = 0; tIdx < state.getNumTrackableResults(); tIdx++)
{
    // Get the trackable:
    const QCAR::TrackableResult* result = state.getTrackableResult(tIdx);
    const QCAR::Trackable& trackable = result->getTrackable();
    QCAR::Matrix44F modelViewMatrix = QCAR::Tool::convertPose2GLMatrix(result-  >getPose());
}
QCAR::Renderer::getInstance().end();


for(int tIdx = 0; tIdx < state.getNumTrackableResults(); tIdx++)
{
// Get the trackable:
const QCAR::TrackableResult* result = state.getTrackableResult(tIdx);
const QCAR::Trackable& trackable = result->getTrackable();
QCAR::Matrix44F modelViewMatrix = QCAR::Tool::convertPose2GLMatrix(result-    >getPose());

    SampleUtils::rotatePoseMatrix(180.0f, 1.0f, 0, 0, &modelViewMatrix.data[0]);
    // Passes the model view matrix to java
    env->SetFloatArrayRegion(modelviewArray, 0, 16, modelViewMatrix.data);
    env->CallVoidMethod(obj, updateMatrixMethod , modelviewArray);
    env->CallVoidMethod(obj, updateCameraMethod);
    env->CallVoidMethod(obj, fovMethod, fovRadians);
    env->CallVoidMethod(obj, fovyMethod, fovyRadians);




}
env->DeleteLocalRef(modelviewArray);



}

What does that exception mean?

Sam R.
  • 16,027
  • 12
  • 69
  • 122
Romain
  • 173
  • 1
  • 7
  • What error do you get? – Sam R. Mar 04 '13 at 11:07
  • the application fails. The program compiles but the applications stops as it starts – Romain Mar 05 '13 at 11:28
  • Can you see anything on your _Logcat_ when it fails? – Sam R. Mar 05 '13 at 11:30
  • Yes I see The library libQCAR.so could not be loaded The library libImageTargets.so could not be loaded" but the .jar is in the referenced libraries. then I have errors like this : " FATAL EXCEPTION: main java.lang.UnsatisfiedLinkError: getOpenGlEsVersionNative at com.qualcomm.QCARSamples.ImageTargets.ImageTargets.getOpenGlEsVersionNative(Native Method) at com.qualcomm.QCARSamples.ImageTargets.ImageTargets.getInitializationFlags(ImageTargets.java:384) " – Romain Mar 05 '13 at 12:53
  • That's exactly your problem. _JAR_ has nothing to do with _libQCAR.so_. You should be able to compile with Android NDK first. Take a look at [here](https://developer.vuforia.com/resources/dev-guide/step-1-setting-development-environment-android-sdk). – Sam R. Mar 05 '13 at 13:03
  • for this problem you were right Sam, I apologize. I solved it. In fact the main problems are after this, we are several to be blocked because the tutorial is not precize enough for us. for this first part the application compiles but we don't get the cube over the scene, and when wee touch imagetargets.cpp (the renderframe function), there are errors. I have edited my message if you want to see it :) – Romain Mar 05 '13 at 14:04
  • Are you using `OpenGL ES 2` or `1.x`? – Sam R. Mar 05 '13 at 14:38
  • I'm using OpenGL ES 2 – Romain Mar 05 '13 at 14:49
  • I don't have access to my codes right now but AFAICR I didn't have much success with 2.0. I used 1.x for both QCAR and jPCT. For now I recommend to remove all of the rendering codes from QCAR and try to add some of those errors that u get from _Logcat_ to your question. If I find my code I will help you more. – Sam R. Mar 05 '13 at 14:56
  • 1
    By the way, from your code you are missing one line. I will add an answer. – Sam R. Mar 05 '13 at 15:04

3 Answers3

6

The beginning of your renderFrame method in ImageTarget.cpp should be this way:

jclass activityClass = env->GetObjectClass(obj);
jfloatArray modelviewArray = env->NewFloatArray(16);
jmethodID method = env->GetMethodID(activityClass, "updateModelviewMatrix", "([F)V");

This, I think, is gonna solve your error for activityClass was not declared in this scope

Comment out this line and test again. You don't need it anymore.

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

I would also recommend to comment out the renderFrame() method in onDrawFrame() to see if jPCT can render the cube if QCAR hasn't started the rendering earlier. (just for testing purpose)

Not to mention, QCAR initially changes the OpenGL states by default. Therefor, you have to enable some of them in order to render with jPCT. Check OpenGL State Changes in Video Background Renderer for more info.

I'm using this for OpenGL ES 1.x after I call renderFrame in onDrawFrame:

GL11 gl11 = (GL11) gl;
gl11.glEnable(GL11.GL_DEPTH_TEST);
gl11.glEnable(GL11.GL_CULL_FACE);
gl11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
gl11.glEnable(GL11.GL_LIGHTING);
gl11.glEnable(GL11.GL_BLEND);
Sam R.
  • 16,027
  • 12
  • 69
  • 122
  • Thank you, this error is solved. The applications compiles but I don't see a cube on the marker (I don't see the teapot anymore bu it's normal). As I said, in the first part of the tutorial, before changing the imagetargets.cpp, the cube should appear over the screen, but it didn't come. Maybe I have one error in the java code, but I don't see where. – Romain Mar 05 '13 at 15:30
  • I have edited the question with my new code in imagetargets and the logcat – Romain Mar 05 '13 at 15:43
  • ok :) I have commented the line but it doens't change anything. – Romain Mar 05 '13 at 16:23
  • I have this many times this error in the LogCat: E/lights(2696): write_int: path /sys/class/backlight/pwm-backlight/brightness, value 84 – Romain Mar 05 '13 at 16:26
  • when i comment ou render frame, the applications compiles but the camera doesn't work (the screen stay black). I m going to try the glTexture, disable, enable etc – Romain Mar 05 '13 at 18:12
  • That's obvious since the QCAR does not start rendering but you should see the cube or something anyway. – Sam R. Mar 05 '13 at 18:22
  • I have now the cube over the scene. 2 lines were missing, kelmer gave it in the second answer. But I haven't the cube on the marker – Romain Mar 05 '13 at 18:57
  • @SamRad hi, i just finished "Integrating JPCT-AE with Vuforia" tutorial. But i have an awkward problem. Cube moving wrong direction. When i move stones image to up cube moves to bottom instead of moving up with image. image to left but cube to right. what did i miss? – Mehmet Emre Portakal Jun 21 '13 at 14:36
  • 1
    @Amourreux, which tutorial? Have you rotated the matrix before sending to Java? – Sam R. Jun 21 '13 at 14:57
  • @SamRad i followed this tutorial: http://www.jpct.net/wiki/index.php/Integrating_JPCT-AE_with_Vuforia and i use this code block : SampleUtils::rotatePoseMatrix(180.0f, 1.0f, 0, 0, &modelViewMatrix.data[0]); // Passes the model view matrix to java env->SetFloatArrayRegion(modelviewArray, 0, 16, modelViewMatrix.data); env->CallVoidMethod(obj, updateMatrixMethod , modelviewArray); – Mehmet Emre Portakal Jun 21 '13 at 17:28
  • 1
    @Amourreux, Sorry I haven't touched my codes for a year. Do you have bitbucket's account? I can give access to the codes. – Sam R. Jun 23 '13 at 10:23
  • @SamRad actually i fınd out what my problem is with your comment help. also if i will be very happy if you share codes via birbucket. my account name is amourreux https://bitbucket.org/amourreux. thanks for advices. – Mehmet Emre Portakal Jun 24 '13 at 05:56
5

In order to see something before applying the matrix, you must first tell the camera to lookAt the object.

Camera cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
cam.lookAt(cube.getTransformedCenter());

Be aware that you should remove these lines when you update the camera with the modelview matrix from the marker.

If you follow my tutorial you actually don't have to activate any OpenGL states to see something over the marker (although you might be interested in activating them as Sam Rad suggested, for other reasons).

M Rajoy
  • 4,028
  • 14
  • 54
  • 111
  • BTW I've seen the tutorial has a few mistakes like omitting those lines Sam Rad told you. I will fix it ASAP. – M Rajoy Mar 05 '13 at 18:37
  • Thank you, I have the cube over the scene Now. But I don't succeed to put it on the marker. You can see the renderframe function in the "Question", did I make mistakes in the code ? – Romain Mar 05 '13 at 18:56
  • Well, you should be calling the updateCamera() method somewhere in your code. Try putting it right after renderFrame(). – M Rajoy Mar 05 '13 at 19:05
  • Ok. I tried to call updateCamera() in the OndrawFrame function after renderFrame(). The applications compiles but the camera doens't open and it crashes. Same result since I call it in every place in the onDrawFrame function. – Romain Mar 05 '13 at 19:31
  • 1
    Let the Native code calls the updateCamera() function. You don't need to call it explicitly in Java. – Sam R. Mar 05 '13 at 19:55
  • I was referring to the code that applies the camera matrix to jpct camera object. – M Rajoy Mar 05 '13 at 19:58
  • 1
    I was referring to same. But the `updateCamera` is only valid when there is a Trackable object in sight. Otherwise the `mat` is null. You can call it from native code inside the `for(int tIdx = 0; tIdx < state.getNumActiveTrackables(); tIdx++)`. – Sam R. Mar 05 '13 at 20:31
  • I try to implement it : I wrote "jclass newClass = env->GetObjectClass(obj); jmethodID updateCameraMethod = env->GetMethodID(newClass, "updateCamera", "()V");" at the beginning of the function, and I add " env->CallVoidMethod(obj, updateCameraMethod);" inside the loop. I edit my question to show it. The application compiles, the camera open, but when I look at the marker, the application chrashes. – Romain Mar 07 '13 at 10:26
  • 1
    Okay, in your constructor you're initializing a different Cam object than the one you have as a field. Use cam = World.getCamera() instead of Camera cam = World.getCamera(). – M Rajoy Mar 07 '13 at 10:37
  • Yes I didn't see it. Thanks you ! It works ! So I see now the cube over the marker. It was moving. Than I have followed the setting FOV part. the cube didn't move too much but a little yet, more than the teapot which didn't move. I thing the cube is too low relative to the marker. So I tried to change sv.z and sv.y but it didn't change. the altitude. – Romain Mar 07 '13 at 13:41
  • Try with a plane positioned at (0,0,0) and let us know. – M Rajoy Mar 07 '13 at 13:43
  • Ok I have found the solution. In fact I have to set the origin of the cube at (0,0,-10) in order to put it higher. I m going to editate my question with the final codes. It works, thank you very much Kelmer and Sam. Yet I have one problem, but I think it's a vuforia problem. When I want stop the application, I touch the back touch on the phone. Then I am again on the menu "about" of vuforia, and if I play start again, the application crashes. Is there somethong to do to avoid that ? – Romain Mar 07 '13 at 15:46
  • I wouldn't know since I deleted that activity. Maybe if you post LogCat I can try and help. Also please mark answer as accepted. – M Rajoy Mar 07 '13 at 15:55
  • You might be leaking the original imagerenderer, and since TextureManager is a Singleton, you are defining the texture twice. This is just a guess, though... – M Rajoy Mar 07 '13 at 16:07
  • To accept the answer, there are 2 answer, both helped me, and the final answer is the question I edited. it seems I can accept the 2 answer and I can highligh the fact the question is composed of the final codes so I accepted yours – Romain Mar 07 '13 at 16:10
  • @kelmer hi, i just finished "Integrating JPCT-AE with Vuforia" tutorial. But i have an awkward problem. Cube moving wrong direction. When i move stones image to up cube moves to bottom instead of moving up with image. image to left but cube to right. what did i miss? – Mehmet Emre Portakal Jun 21 '13 at 14:36
  • 1
    @Amourreux make sure you don't apply any translations or rotations to the cube when you create it – M Rajoy Jun 21 '13 at 15:50
0

Add this to Renderer for removing loaded Textures

public void cleanup()
{
    TextureManager.getInstance().removeTexture("texture");
}

Call this from Activity while closing/pausing

protected void onPause()
{
   mRenderer.cleanup();
}
Raja
  • 1