Flutter集成Vuforia SDK:跟踪第二个ImageTarget时关联对象消失问题
问题分析与解决方案
你的核心问题是:当前代码仅渲染当前帧跟踪到的单个ImageTarget,没有维护已跟踪目标的状态,导致切换跟踪目标时,之前的AR对象停止渲染。要实现多目标持续显示,需要保存所有已成功跟踪过的目标的位置矩阵,并在每一帧中遍历渲染所有目标。
关键问题点
getImageTargetResult仅返回单个跟踪目标,没有收集所有已跟踪目标的信息renderFrame中只调用一次renderImageTarget,仅渲染当前最新跟踪的目标renderRectangle每次调用都会重新创建着色器,造成性能浪费
解决方案步骤
1. 新增已跟踪目标的状态存储结构
在Controller类中添加数据结构,保存所有已跟踪目标的名称和矩阵信息:
// 定义跟踪目标结构体 struct TrackedTarget { std::string name; VuMatrix44F projectionMatrix; VuMatrix44F modelViewMatrix; VuMatrix44F scaledModelViewMatrix; }; // 维护已跟踪目标列表 std::vector<TrackedTarget> mTrackedTargets;
2. 更新目标跟踪逻辑,收集所有已跟踪目标
替换原getImageTargetResult方法,改为批量更新已跟踪目标列表:
void Controller::updateTrackedTargets() { VuTrackableList trackableList; vuStateGetTrackableList(getVuState(), &trackableList); for (int i = 0; i < vuTrackableListGetSize(&trackableList); ++i) { VuTrackable* trackable = vuTrackableListGetElement(&trackableList, i); VuTrackableType type; vuTrackableGetType(trackable, &type); if (type == VU_TRACKABLE_IMAGE_TARGET) { VuImageTarget* imageTarget = static_cast<VuImageTarget*>(trackable); const char* targetName = vuImageTargetGetName(imageTarget); VuTrackableStatus status; vuTrackableGetStatus(trackable, &status); // 仅处理正在跟踪的目标 if (status == VU_TRACKABLE_STATUS_TRACKED) { VuMatrix44F projectionMatrix, modelViewMatrix, scaledModelViewMatrix; vuTrackableGetProjectionMatrix(trackable, &projectionMatrix); vuTrackableGetModelViewMatrix(trackable, &modelViewMatrix); // 复用原缩放逻辑 VuVector3F scaleVec{0.3f, 0.3f, 1.0f}; scaledModelViewMatrix = vuMatrix44FScale(scaleVec, modelViewMatrix); VuVector3F positionVec{0.0f, 0.0f, 0.0f}; scaledModelViewMatrix = vuMatrix44FTranslate(positionVec, scaledModelViewMatrix); // 更新或添加目标到列表 bool targetExists = false; for (auto& existingTarget : mTrackedTargets) { if (existingTarget.name == targetName) { existingTarget.projectionMatrix = projectionMatrix; existingTarget.modelViewMatrix = modelViewMatrix; existingTarget.scaledModelViewMatrix = scaledModelViewMatrix; targetExists = true; break; } } if (!targetExists) { mTrackedTargets.push_back({targetName, projectionMatrix, modelViewMatrix, scaledModelViewMatrix}); } } } } vuTrackableListDestroy(&trackableList); } // 提供获取目标列表的方法 const std::vector<TrackedTarget>& Controller::getTrackedTargets() const { return mTrackedTargets; }
3. 修改渲染逻辑,遍历渲染所有已跟踪目标
更新renderFrame方法,批量渲染所有保存的目标:
JNIEXPORT jboolean JNICALL Java_com_smartboom_arengine_flutter_1smartboom_1ar_1engine_engine_vuforia_VuforiaARView_renderFrame(JNIEnv* /* env */, jobject /* this */) { if (!controller.isARStarted()) { return JNI_FALSE; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); int vbTextureUnit = 0; VuRenderVideoBackgroundData renderVideoBackgroundData; renderVideoBackgroundData.renderData = nullptr; renderVideoBackgroundData.textureData = nullptr; renderVideoBackgroundData.textureUnitData = &vbTextureUnit; double viewport[6]; if (controller.prepareToRender(viewport, &renderVideoBackgroundData)) { glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); auto renderState = controller.getRenderState(); gWrapperData.renderer.renderVideoBackground( renderState.vbProjectionMatrix, renderState.vbMesh->pos, renderState.vbMesh->tex, renderState.vbMesh->numFaces, renderState.vbMesh->faceIndices, vbTextureUnit); // 更新已跟踪目标列表 controller.updateTrackedTargets(); // 遍历渲染所有已跟踪目标 const auto& trackedTargets = controller.getTrackedTargets(); for (const auto& target : trackedTargets) { gWrapperData.renderer.renderImageTarget(target.projectionMatrix, target.modelViewMatrix, target.scaledModelViewMatrix, target.name.c_str()); } if (gWrapperData.usingARCore) { accessFusionProviderPointers(); } } controller.finishRender(); return JNI_TRUE; }
4. 优化着色器创建逻辑,避免重复创建
修改GLESRenderer类,缓存矩形着色器程序,避免每次渲染都重新编译:
class GLESRenderer { private: GLuint mRectangleShaderProgramID = 0; // ...其他成员变量 }; GLuint GLESRenderer::getRectangleShader() { if (mRectangleShaderProgramID == 0) { // 原createRectangleShader的完整逻辑 const char* vertexShaderSource = "attribute vec4 a_Position;\n" "attribute vec2 a_TexCoord;\n" "varying vec2 v_TexCoord;\n" "uniform mat4 u_MVPMatrix;\n" "void main() {\n" " gl_Position = u_MVPMatrix * a_Position;\n" " v_TexCoord = a_TexCoord;\n" "}\n"; const char* fragmentShaderSource = "precision mediump float;\n" "varying vec2 v_TexCoord;\n" "uniform sampler2D u_Texture;\n" "void main() {\n" " gl_FragColor = texture2D(u_Texture, v_TexCoord);\n" "}\n"; GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); glCompileShader(vertexShader); glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); glCompileShader(fragmentShader); mRectangleShaderProgramID = glCreateProgram(); glAttachShader(mRectangleShaderProgramID, vertexShader); glAttachShader(mRectangleShaderProgramID, fragmentShader); glLinkProgram(mRectangleShaderProgramID); glDeleteShader(vertexShader); glDeleteShader(fragmentShader); } return mRectangleShaderProgramID; } // 修改renderRectangle中的着色器获取方式 void GLESRenderer::renderRectangle(const VuMatrix44F& projectionMatrix, const VuMatrix44F& modelViewMatrix, GLuint textureId) { // ...其他代码 GLuint shaderProgramID = getRectangleShader(); // ...其他代码 }
效果说明
修改后,每帧会自动收集所有正在跟踪的ImageTarget,已成功跟踪过的目标会被保留在列表中持续渲染,即使切换跟踪其他目标,之前的AR对象也会保持在原位置显示。
内容的提问来源于stack exchange,提问作者Ali Sheykhi
相关产品推荐
相关产品推荐

