You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android平台ARToolKit添加NFT Marker失败及检测异常问题问询

解决ARToolKit ARSimple替换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.fsetpinball.fset3pinball.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

火山引擎 最新活动