Скрыть PlaneRenderer при съемке фотографий в Sceneform - PullRequest
1 голос
/ 10 марта 2020

Я добавил функцию, основанную на обучающей программе Codelabs от Google (https://codelabs.developers.google.com/codelabs/sceneform-intro/index.html?index=..%2F..index#15), которая позволяет пользователям делать фотографии объектов AR, которые были добавлены в сцену. Код работает нормально, однако я sh могу скрыть PlaneRenderer (белые точки, которые появляются, когда ARCore обнаруживает поверхность) на фотографии, сделанной пользователями.

В onClickListener для кнопки «Захватить фотографию» я попытался установить PlaneRenderer в невидимое состояние перед вызовом takePhoto (). Это скрыло 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 содержит список трансформируемых узлов и используется для отслеживания объектов, добавленных пользователями (поскольку пользователи могут добавить более 1 объекта в сцена). Поскольку объекты являются трансформируемыми узлами, пользователи могут нажимать на них, чтобы изменять их размер / поворачивать, что показывает маленький круг под выбранным объектом. Таким образом, добавлено значение for-l oop для отмены выбора всех трансформируемых узлов при съемке фотографий, чтобы гарантировать, что маленький кружок также не появляется на фотографии.

Метод 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 скрывается на экране устройства при нажатии кнопки «Захватить фотографию». Это то, что видно сразу после того, как пользователь нажимает на кнопку «Захватить фотографию»: PlaneRenderer is hidden on screen

Однако PlaneRenderer по-прежнему отображается на снятой фотографии. Это полученное изображение, которое было получено: photo captured

, что не то, что я искал, так как я хочу скрыть PlaneRenderer на фотографии (ie. Фотография сделана должна не имеют белых точек)

Пользователи этого приложения добавляют объекты, выбирая объект из меню и нажимая на PlaneRenderer, поэтому полное отключение PlaneRenderer невозможно. Кроме того, у меня есть еще одна функция видеозаписи в приложении, которая смогла успешно скрыть PlaneRenderer в записи, просто установив PlaneRenderer в невидимое состояние, поэтому я не уверен, почему он не работает при захвате фотографий.

Любая помощь будет принята с благодарностью! :)

1 Ответ

0 голосов
/ 11 марта 2020

Наконец понял это после бесчисленных часов. Поделиться моим решением (может быть, не лучшим решением) на случай, если кто-то столкнется с такой же проблемой в будущем.

Я обнаружил, что из-за используемого handlerThread метод takePhoto () всегда происходит до того, как PlaneRenderer становится невидимым при каждом нажатии кнопки. Итак, я добавил небольшую задержку, чтобы убедиться, что происходит обратное - ie. задержать метод 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);
            }
        });

Этот метод работал для меня, но Я уверен, что есть лучшие решения для решения этой проблемы. Надеюсь, что это поможет кому-то с той же проблемой, и вы можете внести свой вклад, если вы знаете лучшее решение.

...