Home » Android » c++ – Integrating jpct-ae to Qualcomm's Vuforia engine in android

c++ – Integrating jpct-ae to Qualcomm's Vuforia engine in android

Posted by: admin June 15, 2020 Leave a comment

Questions:

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?

How to&Answers:

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).

Answer:

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

Answer:

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();
}