В Android я пытаюсь интегрировать JPCT в Vuforia, используя этот учебник:
http://www.jpct.net/wiki/index.php/Integrating_JPCT-AE_with_Vuforia
Первый раз, когда приложение запускается, оно работает, но когда я возвращаюсь и снова нажимаю «play», происходит сбой.
Это ошибки в моем LogCat при сбое приложения:
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)
Вот код Imagetargetsrenderer.java
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);
}
}
Код для 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);}
Что означает это исключение?
Чтобы увидеть что-то перед применением матрицы, вы должны сначала попросить камеру посмотреть на объект.
Camera cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
cam.lookAt(cube.getTransformedCenter());
Помните, что вы должны удалить эти линии при обновлении камеры с помощью матрицы вида модели из маркера.
Если вы следуете моему руководству, вам на самом деле не нужно активировать какие-либо состояния OpenGL, чтобы увидеть что-то поверх маркера (хотя вам может быть интересно активировать их, как предложил Сэм Рад, по другим причинам).
Начало вашего renderFrame
метод в ImageTarget.cpp
должно быть так:
jclass activityClass = env->GetObjectClass(obj);
jfloatArray modelviewArray = env->NewFloatArray(16);
jmethodID method = env->GetMethodID(activityClass, "updateModelviewMatrix", "([F)V");
Я думаю, это решит вашу ошибку для ActivityClass не был объявлен в этой области
Закомментируйте эту строку и протестируйте снова. Тебе это больше не нужно.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Я бы также рекомендовал закомментировать renderFrame()
метод в onDrawFrame()
чтобы увидеть, может ли jPCT визуализировать куб, если QCAR не начал рендеринг раньше. (только для тестирования)
Не говоря уже о том, что QCAR изначально изменяет состояния OpenGL по умолчанию. Для этого вам нужно включить некоторые из них, чтобы рендерить с помощью jPCT. Проверьте Изменения состояния OpenGL в видео-фоновом рендере для получения дополнительной информации.
Я использую это для OpenGL ES 1.x
после того как я позвоню renderFrame
в 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);
Добавьте это в Renderer для удаления загруженных текстур
public void cleanup()
{
TextureManager.getInstance().removeTexture("texture");
}
Вызовите это из Activity во время закрытия / приостановки
protected void onPause()
{
mRenderer.cleanup();
}