ARCore:如何在表面上显示设备中保存的图像



我是AR新手。我想知道是否有一种方法可以使用适用于 android 的 ARCore 将保存在手机上的图片显示到表面上。就像我能够将 Sceneform 示例与预编码图像一起使用一样,但现在我想将图片文件夹中的照片显示到表面。我读过关于纹理的信息,但我也不确定它是如何工作的。 谢谢你的提示。

编辑: 所以我创建了一个类,用户可以从那里选择我通过 Uri 保存的图像

public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == this.RESULT_CANCELED) {
return;
}
if (requestCode == GALLERY) {
if (data != null) {
contentURI = data.getData();
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), contentURI);
String path = saveImage(bitmap);
Toast.makeText(imageSelector.this, "Image Saved!", Toast.LENGTH_SHORT).show();
//set the image selected to bitmap so that imageView can display it
imageview.setImageBitmap(bitmap);
Intent intent = new Intent(this, HelloSceneformActivity.class);
intent.putExtra("imageUri", contentURI.toString());
startActivity(intent);

从 ARclass 方面,我调用了意图并按如下方式解析它

//start the intent for the image chosen from the library
Bundle extras = getIntent().getExtras();
Uri myUri = Uri.parse(extras.getString("imageUri"));
// When you build a Renderable, Sceneform loads its resources in the background while returning
// a CompletableFuture. Call thenAccept(), handle(), or check isDone() before calling get().
ModelRenderable.builder()
.setSource(this, myUri)
.build()
.thenAccept(renderable -> andyRenderable = renderable)
.exceptionally(
throwable -> {
Toast toast =
Toast.makeText(this, "Unable to load andy renderable", Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
return null;
});

我能够选择图片,但程序崩溃,我收到此错误

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.google.ar.sceneform.samples.hellosceneform/com.google.ar.sceneform.samples.hellosceneform.HelloSceneformActivity}: java.lang.IllegalArgumentException: Unable to parse url: 'content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F460/ORIGINAL/NONE/1926270799'
Caused by: java.lang.IllegalArgumentException: Unable to parse url: 'content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F460/ORIGINAL/NONE/1926270799'
at com.google.ar.sceneform.utilities.LoadHelper.remoteUriToInputStreamCreator(Unknown Source:56)
at com.google.ar.sceneform.utilities.LoadHelper.fromUri(Unknown Source:40)
at com.google.ar.sceneform.rendering.Renderable$Builder.build(Renderable.java:343)
at com.google.ar.sceneform.rendering.ModelRenderable$Builder.build(ModelRenderable.java:44)
at com.google.ar.sceneform.samples.hellosceneform.HelloSceneformActivity.onCreate(HelloSceneformActivity.java:92)
at android.app.Activity.performCreate(Activity.java:7174)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)

根据https://github.com/google-ar/sceneform-android-sdk/issues/79,您目前无法从自定义URI加载:

在 1.0 中,我们将所有 URI 解释为相对于 assets 文件夹 file://这就是我们无法从外部存储加载的原因。因此,为了从 Uri 加载纹理,您需要放入 assets 文件夹(即捆绑到您的 apk 中(,或者将其在线托管在通过 http://方案可用的地方。

这意味着目前仅支持 http://和 file://URI,后者只能相对于 assets 文件夹。这在马利克在工作 https://github.com/google-ar/sceneform-android-sdk/issues/64 的回答中得到了证实:

基于 URI 的文件加载不会查看外部存储。目前,它只使用 file://和远程 uri 查找应用程序资产,从 http://

编辑:我建议的一种解决方法是将ViewRenderable与内部具有单个ImageView的布局结合使用。ViewRenderable可以在场景中创建2D布局,您只需像在通常的Android应用程序中一样将图像设置为ImageView,并根据自己的喜好定位/旋转生成的对象。您可以在solarsystem-Sceneform-example中找到ViewRenderable的示例用法,速度的滑块是用它实现的。

编辑2: 这似乎在 Sceneform 1.4 中得到了修复,因为第一个提到的问题现在已经关闭。

您可以将图像作为 Uri 列表传递

public class MainActivity2 extends AppCompatActivity {
Button Gallery, AR;
private static final int PICK_IMAGE = 100;
Uri imageUri;
ImageView imageview;
private ArFragment arFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Gallery = findViewById(R.id.select);
AR = findViewById(R.id.ar);
imageview = findViewById(R.id.imageView);
AR.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent myIntent = new Intent(MainActivity2.this, MainActivity.class);
MainActivity2.this.startActivity(myIntent);
}
});
Gallery.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openGallery();
}
});

}
private void openGallery() {
Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
startActivityForResult(gallery, PICK_IMAGE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == PICK_IMAGE) {
imageUri = data.getData();
imageview.setImageURI(imageUri);
setContentView(R.layout.activity_main);
arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
assert arFragment != null;
arFragment.setOnTapArPlaneListener((hitResult, plane, motionEvent) - > {
Anchor anchor = hitResult.createAnchor();
createViewRenderable(hitResult.createAnchor());
});
}
}
private void addModeltoScene(Anchor anchor, ModelRenderable modelRenderable) {
AnchorNode anchorNode = new AnchorNode(anchor);
TransformableNode transformableNode = new TransformableNode(arFragment.getTransformationSystem());
transformableNode.setParent(anchorNode);
transformableNode.setRenderable(modelRenderable);
arFragment.getArSceneView().getScene().addChild(anchorNode);
transformableNode.select();
}
private void createViewRenderable(Anchor anchor) {
ViewRenderable
.builder()
.setView(this, R.layout.text)
.build()
.thenAccept(viewRenderable - > {
addtoScene(viewRenderable, anchor);
});
}
private void addtoScene(ViewRenderable viewRenderable, Anchor anchor) {
AnchorNode anchorNode = new AnchorNode(anchor);
anchorNode.setRenderable(viewRenderable);
arFragment.getArSceneView().getScene().addChild(anchorNode);
View view = viewRenderable.getView();
ViewPager viewPager = view.findViewById(R.id.viewPager);
List < Uri > images = new ArrayList < > ();
images.add(imageUri);
Adapter adapter = new Adapter(images);
viewPager.setAdapter(adapter);

}
class Adapter extends PagerAdapter {
List < Uri > images;
Adapter(List < Uri > images) {
this.images = images;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View view = getLayoutInflater().inflate(R.layout.item, container, false);
ImageView imageView = view.findViewById(R.id.imageView);
imageView.setImageURI(imageUri);
container.addView(view);
return view;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView((ImageView) object);
}
@Override
public int getCount() {
return images.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
}
}

我写了一篇关于同样的文章。请检查一下。它是关于以AR形式显示图库中的2D图像。 https://medium.com/@deveshbhatla952/displaying-2-d-images-from-external-storage-in-ar-form-using-google-sceneform-2baae45f1a42 我已经尝试过了,效果很好。

最新更新