google ar core 在运行时如何在 ArSceneView 中切换 2D 纹理
How to switch a 2D texture in ArSceneView in google ar core at runtime
我们都在 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 中)。
找到了类似的 question(对于 3D)但没有答案。
编辑:
同样在调试之后,似乎只调用了一次 onUpdate 函数。我不明白这是怎么回事?
我在这个 kotlin app developed by Kristina Simakova 中找到了解决方案。
看来我走对了。我错过的是 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
变量,该变量根据单击的按钮获取值。
我们都在 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 中)。 找到了类似的 question(对于 3D)但没有答案。
编辑: 同样在调试之后,似乎只调用了一次 onUpdate 函数。我不明白这是怎么回事?
我在这个 kotlin app developed by Kristina Simakova 中找到了解决方案。
看来我走对了。我错过的是 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
变量,该变量根据单击的按钮获取值。