我基于Google的Codelabs教程(https://codelabs.developers.google.com/codelabs/sceneform-intro/index.html?index=..%2F..index#15)添加了一项功能,该功能允许用户拍摄添加到场景中的AR对象的照片。该代码可以正常工作,但是,我希望在用户拍摄的照片中隐藏PlaneRenderer(ARCore检测到表面时出现的白点)。

在“捕获照片”按钮的onClickListener中,我尝试在调用takePhoto()之前将PlaneRenderer设置为不可见。这会将PlaneRenderer隐藏在屏幕上,但未隐藏在捕获的照片中。

这是我的onClickListener:

capturePhotoBtn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                arFragment.getArSceneView().getPlaneRenderer().setVisible(false);
                for (TransformableNode vNode : videoNodeList){
                    if (vNode.isSelected()){
                        vNode.getTransformationSystem().selectNode(null);
                    }
                }
                takePhoto();
            }
        });


videoNodeList包含一个transformableNodes列表,用于跟踪用户添加的对象(因为用户可以在场景中添加多个对象)。由于对象是transformableNodes,因此用户可以点击它们以调整大小/旋转,这在所选对象下方显示了一个小圆圈。因此,添加的for循环是在拍照时取消选择所有transformableNodes,以确保小圆圈也不会出现在照片中。

takePhoto()方法来自CodeLabs教程,给出如下:

private void takePhoto() {

        final String filename = generateFilename();
        ArSceneView view = arFragment.getArSceneView();

        // Create a bitmap the size of the scene view.
        final Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
                Bitmap.Config.ARGB_8888);

        // Create a handler thread to offload the processing of the image.
        final HandlerThread handlerThread = new HandlerThread("PixelCopier");
        handlerThread.start();
        // Make the request to copy.
        PixelCopy.request(view, bitmap, (copyResult) -> {
            if (copyResult == PixelCopy.SUCCESS) {
                try {
                    File file = saveBitmapToDisk(bitmap, filename);
                    MediaScannerConnection.scanFile(this,
                            new String[] { file.toString() }, null,
                            new MediaScannerConnection.OnScanCompletedListener() {
                                public void onScanCompleted(String path, Uri uri) {
                                    Log.i("ExternalStorage", "Scanned " + path + ":");
                                    Log.i("ExternalStorage", "-> uri=" + uri);
                                }
                            });
                } catch (IOException e) {
                    Toast toast = Toast.makeText(ChromaKeyVideoActivity.this, e.toString(),
                            Toast.LENGTH_LONG);
                    toast.show();
                    return;
                }
                Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content),
                        "Photo saved", Snackbar.LENGTH_LONG);
                snackbar.setAction("Open in Photos", v -> {
                    File photoFile = new File(filename);

                    Uri photoURI = FileProvider.getUriForFile(ChromaKeyVideoActivity.this,
                            ChromaKeyVideoActivity.this.getPackageName() + ".provider",
                            photoFile);
                    Intent intent = new Intent(Intent.ACTION_VIEW, photoURI);
                    intent.setDataAndType(photoURI, "image/*");
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    startActivity(intent);

                });
                snackbar.show();
            } else {
                Toast toast = Toast.makeText(ChromaKeyVideoActivity.this,
                        "Failed to copyPixels: " + copyResult, Toast.LENGTH_LONG);
                toast.show();
            }
            handlerThread.quitSafely();
        }, new Handler(handlerThread.getLooper()));

    }


为了给您提供更清晰的图片,点击“捕获照片”按钮时,PlaneRenderer隐藏在设备屏幕上。这是在用户点击“捕获照片”按钮后立即看到的:
 java - 在Sceneform中拍照时隐藏PlaneRenderer-LMLPHP

但是,PlaneRenderer仍会出现在所拍摄的照片中。这是拍摄的结果图像:
java - 在Sceneform中拍照时隐藏PlaneRenderer-LMLPHP

这不是我想要的,因为我想在照片中隐藏PlaneRenderer(即,拍摄的照片不应带有白点)

此应用程序的用户通过从菜单中选择一个对象并点击PlaneRenderer来添加对象,因此完全禁用PlaneRenderer是不可行的。此外,我在应用程序中还有另一个视频录制功能,只需将PlaneRenderer设置为不可见,就可以成功地将PlaneRenderer隐藏在录制中,因此我不确定为什么在捕获照片时它不起作用。

任何帮助将不胜感激! :)

最佳答案

数小时的工作终于解决了。共享我的解决方案(可能不是最好的解决方案),以防将来有人遇到同样的问题。

我发现由于使用了handlerThread,在每次轻按按钮时,takePhoto()方法总是在将PlaneRenderer设置为不可见之前发生。因此,我添加了一个短暂的延迟以确保反向发生-即。将takePhoto()方法延迟一小段时间,以使该方法将始终在planeRenderer不可见之后发生。

这是代码片段:

capturePhotoBtn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                arFragment.getArSceneView().getPlaneRenderer().setVisible(false);
                for (TransformableNode vNode : videoNodeList){
                    if (vNode.isSelected()){
                        vNode.getTransformationSystem().selectNode(null);
                    }
                }

                v.postDelayed(new Runnable() {
                    public void run() {
                        takePhoto();
                    }
                }, 80);
            }
        });


这种方法对我有用,但是我确信有更好的解决方案来解决此问题。希望这对遇到相同问题的人有所帮助,如果您知道更好的解决方案,请随时为我们做出贡献。

07-24 19:25