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