android - 如何在运行时在谷歌 ar 核心中的 ArSceneView 中切换 2D 纹理
问题描述
我们都在 Instagram 或 Snapchat 或任何其他应用程序上使用了增强的面部纹理。我正在尝试开发一个示例应用程序,人们可以在其中尝试一些 ar 对象在他们的脸上。到目前为止,我已经能够在脸上显示该对象。
然后我在下面(屏幕上)显示项目列表,以便用户可以将对象切换到其他对象(类似于在 instagram / snapchat 上尝试新过滤器)。
这是一个对象的默认代码:
Texture.builder()
.setSource(this, R.drawable.fox_face_mesh_texture)
.build()
.thenAccept(texture -> faceMeshTexture1 = texture);
ArSceneView sceneView = arFragment.getArSceneView();
sceneView.setCameraStreamRenderPriority(Renderable.RENDER_PRIORITY_FIRST);
Scene scene = sceneView.getScene();
scene.addOnUpdateListener(new Scene.OnUpdateListener() {
@Override
public void onUpdate(FrameTime frameTime) {
if (faceMeshTexture1 == null)
return;
Collection<AugmentedFace> faceList =
sceneView.getSession().getAllTrackables(AugmentedFace.class);
for (AugmentedFace face : faceList) {
if (!faceNodeMap.containsKey(face)) {
AugmentedFaceNode faceNode = new AugmentedFaceNode(face);
faceNode.setParent(scene);
faceNode.setFaceMeshTexture(faceMeshTexture1);
faceNodeMap.put(face, faceNode);
}
}
Iterator<Map.Entry<AugmentedFace, AugmentedFaceNode>> iter =
faceNodeMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<AugmentedFace, AugmentedFaceNode> entry = iter.next();
AugmentedFace face = entry.getKey();
if (face.getTrackingState() == TrackingState.STOPPED) {
AugmentedFaceNode faceNode = entry.getValue();
faceNode.setParent(null);
iter.remove();
}
}
}
});
我试过的
在按钮 onClick - 我通过做创建了一个新的纹理Texture.builder().setSource ...
1)我试图只写for循环for (AugmentedFace face : faceList) { ... }
但它什么也没做。
2)我试图包含onUpdate()
函数的全部内容。但这也没有用。
3)然后我尝试创建 2 个纹理并使用布尔变量通过反转布尔值(在按钮单击上)在这些纹理之间切换(在 onUpdate 方法中)。它看起来像这样:
Texture.builder()
.setSource(this, R.drawable.fox_face_mesh_texture)
.build()
.thenAccept(texture -> faceMeshTexture1 = texture);
Texture.builder()
.setSource(this, R.drawable.red_lipstick)
.build()
.thenAccept(texture -> faceMeshTexture2 = texture);
ArSceneView sceneView = arFragment.getArSceneView();
sceneView.setCameraStreamRenderPriority(Renderable.RENDER_PRIORITY_FIRST);
Scene scene = sceneView.getScene();
scene.addOnUpdateListener(new Scene.OnUpdateListener() {
@Override
public void onUpdate(FrameTime frameTime) {
if (faceMeshTexture1 == null || faceMeshTexture2 == null)
return;
Collection<AugmentedFace> faceList =
sceneView.getSession().getAllTrackables(AugmentedFace.class);
for (AugmentedFace face : faceList) {
if (!faceNodeMap.containsKey(face)) {
AugmentedFaceNode faceNode = new AugmentedFaceNode(face);
faceNode.setParent(scene);
if( !redOrFox ) {
faceNode.setFaceMeshTexture(faceMeshTexture1);
Log.d(TAG, "onUpdate: redorfox:" + redOrFox);
}
else {
faceNode.setFaceMeshTexture(faceMeshTexture2);
Log.d(TAG, "onUpdate: else redorfox:" + redOrFox);
}
faceNodeMap.put(face, faceNode);
}
}
Iterator<Map.Entry<AugmentedFace, AugmentedFaceNode>> iter = faceNodeMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<AugmentedFace, AugmentedFaceNode> entry = iter.next();
AugmentedFace face = entry.getKey();
if (face.getTrackingState() == TrackingState.STOPPED) {
AugmentedFaceNode faceNode = entry.getValue();
faceNode.setParent(null);
iter.remove();
}
}
}
});
mBtnBlueLip.setOnClickListener(v -> {
redOrFox = true;
Log.d(TAG, "onCreate: blue clicked");
});
mBtnRedLip.setOnClickListener(v -> {
redOrFox = false;
Log.d(TAG, "onCreate: red clicked");
});
但这也没有做任何事情。在这一点上,我不知道该做什么。几乎没有任何关于增强面和一些示例应用程序的文档(但在 Kotlin 中)。发现了一个类似的问题(对于 3D ),但没有答案。
编辑:同样在调试之后,似乎 onUpdate 函数只被调用了一次。我不明白这是怎么回事?
解决方案
我在Kristina Simakova开发的这个kotlin 应用程序中找到了解决方案。
看来我是在正确的轨道上。我错过的是该face
对象已经在faceList
数组中,所以它根本不符合这种 if 条件:
if (!faceNodeMap.containsKey(face)) { ... }
因为我没有别的,所以什么也没发生。
解决方案是使用另一个布尔变量来检查按钮是否被点击!
Boolean isFox = false, changeModel = false;
...
scene.addOnUpdateListener(frameTime -> {
...
for (AugmentedFace face : faceList) {
if (!faceNodeMap.containsKey(face)) {
AugmentedFaceNode faceNode = new AugmentedFaceNode(face);
faceNode.setParent(scene);
faceNode.setFaceMeshTexture(faceMeshTexture1);
faceNodeMap.put(face, faceNode);
}
else if (changeModel) { // check whether we want to change texture
if(isFox)
faceNodeMap.get(face).setFaceMeshTexture(faceMeshTexture1);
else
faceNodeMap.get(face).setFaceMeshTexture(faceMeshTexture2);
}
}
changeModel = false; // after the for loop ends
...
mBtnBlueLip.setOnClickListener(v -> {
isFox = true;
changeModel = true;
});
mBtnRedLip.setOnClickListener(v -> {
changeModel = true;
isFox = false;
});
克里斯蒂娜使用了类似的方法。由于我正在测试应用程序并且只有 2 个纹理,因此我使用了一个布尔变量isFox
。您还可以维护一组纹理并仅保留一个faceMeshTexture
变量,该变量根据单击的按钮获取值。
推荐阅读
- google-chrome - 柏树 | 由于跨源而进行登录测试的问题
- python - Python 嵌套字典问题
- javascript - 如何显示选中复选框的标签而不是其值
- java - 用 exec.mainClass 覆盖 exec-maven-plugin
- javascript - Express js/Handlebars 新手 - 使用 res.locals.currentPost 仅在某些情况下有效,无法弄清楚原因
- laravel - Laravel - 如何在文件夹应用程序内但在文件夹 http 之外创建控制器
- command - Discord.py mod 日志设置
- c++ - 寻找产生最大功能输出的输入的快速 STL 方法?(连续整数输入)
- javascript - Gatsby 静态路径无法解析
- video - 这个YUV420视频怎么会有尺寸不均匀的