Android平台ARToolKit添加NFT Marker失败及检测异常问题问询
Hey there, let's walk through fixing your NFT Marker issues step by step—you're already halfway there, just a few key tweaks needed!
1. 先解决最开始的Marker类型错误
你第一次用2d;data/nft/Test.jpg报错是因为ARToolKit的NFT Marker标识已经更新了,旧文档里的2d是过时写法,现在必须用nft作为前缀,而且不需要加图片后缀,因为NFT Marker是靠.fset/.fset3/.iset这三个配套文件来识别的,不是直接用原图。
2. 搞定文件路径访问问题
你遇到的unable to open file错误,核心原因是ARToolKit的Native层没法直接读取APK里的Assets文件(Assets是压缩存储的,Native层访问有局限)。正确的做法是把NFT Marker文件复制到设备的内部存储再加载:
第一步:复制Assets文件到内部存储
先在Assets里建个清晰的目录,比如assets/nft_markers/,把pinball.fset、pinball.fset3、pinball.iset还有相机参数文件camera_para.dat都放进去。然后在Activity里加个复制逻辑:
private void copyNftMarkersToStorage() { AssetManager assetManager = getAssets(); String[] markerFiles; try { markerFiles = assetManager.list("nft_markers"); } catch (IOException e) { Log.e("ARSimple", "Failed to list NFT marker files", e); return; } File targetDir = new File(getFilesDir(), "nft_markers"); if (!targetDir.exists()) targetDir.mkdirs(); for (String filename : markerFiles) { try (InputStream in = assetManager.open("nft_markers/" + filename); OutputStream out = new FileOutputStream(new File(targetDir, filename))) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } } catch (IOException e) { Log.e("ARSimple", "Failed to copy " + filename, e); } } }
第二步:用内部存储路径加载Marker
修改你的configureARScene()方法,先复制文件,再用内部存储的绝对路径加载:
public boolean configureARScene() { // 先复制文件到可访问的目录 copyNftMarkersToStorage(); // 拼接NFT Marker的路径(不带后缀) String markerBasePath = new File(getFilesDir(), "nft_markers/pinball").getAbsolutePath(); pinballMarker = ARToolKit.getInstance().addMarker("nft;" + markerBasePath); // 同时确保相机参数文件正确加载(这步很容易忘!) String cameraParaPath = new File(getFilesDir(), "nft_markers/camera_para.dat").getAbsolutePath(); ARToolKit.getInstance().setCameraPara(cameraParaPath); if (pinballMarker == -1) { Log.e("ARSimple", "NFT Marker加载失败"); return false; } return true; }
3. 修复Marker检测与渲染不执行的问题
加载成功但检测不到、draw()不执行,大概率是你还在引用旧的Hiro Marker ID,或者渲染逻辑没更新:
第一步:替换所有Marker ID引用
把原来代码里所有检测Hiro Marker的地方,换成新的pinballMarker:
// 比如在帧更新逻辑里 @Override public void onFrame() { // 放弃原来的hiroMarker,用新的pinballMarker if (ARToolKit.getInstance().queryMarkerVisible(pinballMarker)) { float[] markerMatrix = ARToolKit.getInstance().queryMarkerTransformation(pinballMarker); // 这里更新你的3D模型变换矩阵 } }
第二步:更新Renderer的draw()逻辑
原来的SimpleRenderer#draw()可能只处理了Hiro Marker的情况,改成检测新的NFT Marker:
@Override public void draw(GL10 gl) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // 设置相机投影矩阵 gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadMatrixf(ARToolKit.getInstance().getProjectionMatrix(), 0); // 检查NFT Marker是否可见,可见才渲染 if (ARToolKit.getInstance().queryMarkerVisible(pinballMarker)) { gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadMatrixf(ARToolKit.getInstance().queryMarkerTransformation(pinballMarker), 0); // 调用你的模型绘制方法 draw3DModel(gl); } }
4. 最后检查两个关键细节
- 相机权限:Android 6.0+必须在运行时请求相机权限,在Activity的
onCreate()里加:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 100); }
- NFT Marker生成正确性:确保你用ARToolKit官方的NFT Marker Generator生成的文件,图片要清晰、分辨率不低于640x480,生成时参数不要乱改。
清理残留问题
如果还有旧的加载错误日志,彻底卸载应用、清除缓存后重新安装,避免旧文件干扰。
内容的提问来源于stack exchange,提问作者O.O.Balance




