-
-
Notifications
You must be signed in to change notification settings - Fork 146
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Augmented Face - AugmentedFaceNode - FaceArFragment - AugmentedFace Sample - Texture names should only be set once on a GL thread Co-authored-by: Nikita Zaytsev <[email protected]> Co-authored-by: ThomasGorisse <[email protected]>
- Loading branch information
1 parent
4bdb114
commit de89d56
Showing
45 changed files
with
920 additions
and
194 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
apply plugin: 'com.android.application' | ||
|
||
android { | ||
compileSdkVersion 30 | ||
defaultConfig { | ||
applicationId "com.google.ar.sceneform.samples.augmentedfaces" | ||
|
||
// Sceneform requires minSdkVersion >= 24. | ||
minSdkVersion 24 | ||
targetSdkVersion 30 | ||
versionCode 1 | ||
versionName "1.0" | ||
} | ||
// Sceneform libraries use language constructs from Java 8. | ||
// Add these compile options if targeting minSdkVersion < 26. | ||
compileOptions { | ||
sourceCompatibility JavaVersion.VERSION_1_8 | ||
targetCompatibility JavaVersion.VERSION_1_8 | ||
} | ||
buildTypes { | ||
release { | ||
minifyEnabled false | ||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||
} | ||
} | ||
} | ||
|
||
dependencies { | ||
implementation 'androidx.appcompat:appcompat:1.2.0' | ||
implementation 'androidx.fragment:fragment:1.3.2' | ||
implementation 'com.google.android.material:material:1.3.0' | ||
|
||
api project(":sceneform") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
package="com.google.ar.sceneform.samples.augmentedfaces"> | ||
|
||
<!-- Always needed for AR. --> | ||
<uses-permission android:name="android.permission.CAMERA" /> | ||
|
||
<!-- Needed to load gltf from network. --> | ||
<uses-permission android:name="android.permission.INTERNET" /> | ||
|
||
<!-- Sceneform requires OpenGLES 3.0 or later. --> | ||
<uses-feature | ||
android:glEsVersion="0x00030000" | ||
android:required="true" /> | ||
|
||
<!-- Indicates that this app requires Google Play Services for AR ("AR Required") and results in | ||
the app only being visible in the Google Play Store on devices that support ARCore. | ||
For an "AR Optional" app, remove this tag. --> | ||
<uses-feature | ||
android:name="android.hardware.camera.ar" | ||
android:required="true" /> | ||
|
||
<application | ||
android:icon="@drawable/ic_launcher" | ||
android:label="@string/app_name" | ||
android:theme="@style/AppTheme"> | ||
|
||
<!-- Indicates that this app requires Google Play Services for AR ("AR Required") and causes | ||
the Google Play Store to download and intall Google Play Services for AR along with the app. | ||
For an "AR Optional" app, specify "optional" instead of "required". --> | ||
<meta-data | ||
android:name="com.google.ar.core" | ||
android:value="required" /> | ||
|
||
<activity | ||
android:name=".MainActivity" | ||
android:configChanges="orientation|screenSize" | ||
android:exported="true" | ||
android:label="@string/app_name" | ||
android:screenOrientation="locked" | ||
android:theme="@style/AppTheme"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
<category android:name="android.intent.category.LAUNCHER" /> | ||
</intent-filter> | ||
</activity> | ||
</application> | ||
</manifest> |
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
160 changes: 160 additions & 0 deletions
160
...nted-faces/src/main/java/com/google/ar/sceneform/samples/augmentedfaces/MainActivity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
package com.google.ar.sceneform.samples.augmentedfaces; | ||
|
||
import android.net.Uri; | ||
import android.os.Bundle; | ||
import android.widget.Toast; | ||
|
||
import androidx.annotation.NonNull; | ||
import androidx.appcompat.app.AppCompatActivity; | ||
import androidx.fragment.app.Fragment; | ||
import androidx.fragment.app.FragmentManager; | ||
|
||
import com.google.ar.core.AugmentedFace; | ||
import com.google.ar.core.Frame; | ||
import com.google.ar.sceneform.ArSceneView; | ||
import com.google.ar.sceneform.FrameTime; | ||
import com.google.ar.sceneform.Sceneform; | ||
import com.google.ar.sceneform.rendering.ModelRenderable; | ||
import com.google.ar.sceneform.rendering.Renderable; | ||
import com.google.ar.sceneform.rendering.RenderableInstance; | ||
import com.google.ar.sceneform.rendering.Texture; | ||
import com.google.ar.sceneform.ux.ArFragment; | ||
import com.google.ar.sceneform.ux.AugmentedFaceNode; | ||
import com.google.ar.sceneform.ux.FaceArFragment; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
import java.util.concurrent.CompletableFuture; | ||
|
||
public class MainActivity extends AppCompatActivity { | ||
|
||
private final Set<CompletableFuture<?>> loaders = new HashSet<>(); | ||
|
||
private FaceArFragment arFragment; | ||
private ArSceneView arSceneView; | ||
|
||
private Texture faceTexture; | ||
private ModelRenderable faceModel; | ||
|
||
private final HashMap<AugmentedFace, AugmentedFaceNode> facesNodes = new HashMap<>(); | ||
|
||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
|
||
setContentView(R.layout.activity_main); | ||
|
||
getSupportFragmentManager().addFragmentOnAttachListener(this::onAttachFragment); | ||
|
||
if (savedInstanceState == null) { | ||
if (Sceneform.isSupported(this)) { | ||
getSupportFragmentManager().beginTransaction() | ||
.add(R.id.arFragment, FaceArFragment.class, null) | ||
.commit(); | ||
} | ||
} | ||
|
||
loadModels(); | ||
loadTextures(); | ||
} | ||
|
||
public void onAttachFragment(@NonNull FragmentManager fragmentManager, @NonNull Fragment fragment) { | ||
if (fragment.getId() == R.id.arFragment) { | ||
arFragment = (FaceArFragment) fragment; | ||
arFragment.setOnViewCreatedListener(this::onViewCreated); | ||
} | ||
} | ||
|
||
public void onViewCreated(ArFragment arFragment, ArSceneView arSceneView) { | ||
this.arSceneView = arSceneView; | ||
|
||
// This is important to make sure that the camera stream renders first so that | ||
// the face mesh occlusion works correctly. | ||
arSceneView.setCameraStreamRenderPriority(Renderable.RENDER_PRIORITY_FIRST); | ||
|
||
// Check for face detections | ||
arSceneView.getScene().addOnUpdateListener(this::onUpdate); | ||
} | ||
|
||
@Override | ||
protected void onDestroy() { | ||
super.onDestroy(); | ||
|
||
for (CompletableFuture<?> loader : loaders) { | ||
if (!loader.isDone()) { | ||
loader.cancel(true); | ||
} | ||
} | ||
} | ||
|
||
private void loadModels() { | ||
loaders.add(ModelRenderable.builder() | ||
.setSource(this, Uri.parse("models/fox.glb")) | ||
.setIsFilamentGltf(true) | ||
.build() | ||
.thenAccept(model -> faceModel = model) | ||
.exceptionally(throwable -> { | ||
Toast.makeText(this, "Unable to load renderable", Toast.LENGTH_LONG).show(); | ||
return null; | ||
})); | ||
} | ||
|
||
private void loadTextures() { | ||
loaders.add(Texture.builder() | ||
.setSource(this, Uri.parse("textures/freckles.png")) | ||
.setUsage(Texture.Usage.COLOR_MAP) | ||
.build() | ||
.thenAccept(texture -> faceTexture = texture) | ||
.exceptionally(throwable -> { | ||
Toast.makeText(this, "Unable to load texture", Toast.LENGTH_LONG).show(); | ||
return null; | ||
})); | ||
} | ||
|
||
private void onUpdate(FrameTime frameTime) { | ||
if (faceModel == null || faceTexture == null) { | ||
return; | ||
} | ||
|
||
Frame frame = arFragment.getArSceneView().getArFrame(); | ||
|
||
// Get a list of AugmentedFace which are updated on this frame. | ||
Collection<AugmentedFace> augmentedFaces = frame.getUpdatedTrackables(AugmentedFace.class); | ||
|
||
// TODO: Check the difference with getAllTrackables. | ||
// See: https://stackoverflow.com/questions/49241526/what-is-the-difference-between-session-getalltrackables-and-frame-getupdatedtrac | ||
// Collection<AugmentedFace> augmentedFaces = arSceneView.getSession().getAllTrackables(AugmentedFace.class); | ||
|
||
// Make new AugmentedFaceNodes for any new faces. | ||
for (AugmentedFace augmentedFace : new ArrayList<>(augmentedFaces)) { | ||
AugmentedFaceNode existingFaceNode = facesNodes.get(augmentedFace); | ||
|
||
switch (augmentedFace.getTrackingState()) { | ||
case TRACKING: | ||
if (existingFaceNode == null) { | ||
AugmentedFaceNode faceNode = new AugmentedFaceNode(augmentedFace); | ||
|
||
RenderableInstance modelInstance = faceNode.setFaceRegionsRenderable(faceModel); | ||
modelInstance.setShadowCaster(false); | ||
modelInstance.setShadowReceiver(true); | ||
|
||
faceNode.setFaceMeshTexture(faceTexture); | ||
|
||
arSceneView.getScene().addChild(faceNode); | ||
|
||
facesNodes.put(augmentedFace, faceNode); | ||
} | ||
break; | ||
case STOPPED: | ||
if (existingFaceNode != null) { | ||
arSceneView.getScene().removeChild(existingFaceNode); | ||
} | ||
facesNodes.remove(augmentedFace); | ||
break; | ||
} | ||
} | ||
} | ||
} |
File renamed without changes
Oops, something went wrong.