├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── part0_work
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── models
│ │ ├── andy.obj
│ │ ├── andy.png
│ │ └── andy_spec.png
│ └── shaders
│ │ ├── object.frag
│ │ ├── object.vert
│ │ ├── screenquad.frag
│ │ └── screenquad.vert
│ ├── java
│ └── com
│ │ └── google
│ │ └── ar
│ │ └── core
│ │ └── codelab
│ │ ├── common
│ │ ├── helpers
│ │ │ ├── CameraPermissionHelper.java
│ │ │ ├── DisplayRotationHelper.java
│ │ │ ├── FullScreenHelper.java
│ │ │ ├── SnackbarHelper.java
│ │ │ ├── TapHelper.java
│ │ │ └── TrackingStateHelper.java
│ │ └── rendering
│ │ │ ├── BackgroundRenderer.java
│ │ │ ├── ObjectRenderer.java
│ │ │ └── ShaderUtil.java
│ │ └── depth
│ │ └── DepthCodelabActivity.java
│ └── res
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── activity_main.xml
│ └── values
│ ├── strings.xml
│ └── styles.xml
├── part1
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── models
│ │ ├── andy.obj
│ │ ├── andy.png
│ │ └── andy_spec.png
│ └── shaders
│ │ ├── object.frag
│ │ ├── object.vert
│ │ ├── screenquad.frag
│ │ └── screenquad.vert
│ ├── java
│ └── com
│ │ └── google
│ │ └── ar
│ │ └── core
│ │ └── codelab
│ │ ├── common
│ │ ├── helpers
│ │ │ ├── CameraPermissionHelper.java
│ │ │ ├── DisplayRotationHelper.java
│ │ │ ├── FullScreenHelper.java
│ │ │ ├── SnackbarHelper.java
│ │ │ ├── TapHelper.java
│ │ │ └── TrackingStateHelper.java
│ │ └── rendering
│ │ │ ├── BackgroundRenderer.java
│ │ │ ├── ObjectRenderer.java
│ │ │ └── ShaderUtil.java
│ │ └── depth
│ │ └── DepthCodelabActivity.java
│ └── res
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── activity_main.xml
│ └── values
│ ├── strings.xml
│ └── styles.xml
├── part2
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── models
│ │ ├── andy.obj
│ │ ├── andy.png
│ │ └── andy_spec.png
│ └── shaders
│ │ ├── object.frag
│ │ ├── object.vert
│ │ ├── screenquad.frag
│ │ └── screenquad.vert
│ ├── java
│ └── com
│ │ └── google
│ │ └── ar
│ │ └── core
│ │ └── codelab
│ │ ├── common
│ │ ├── helpers
│ │ │ ├── CameraPermissionHelper.java
│ │ │ ├── DisplayRotationHelper.java
│ │ │ ├── FullScreenHelper.java
│ │ │ ├── SnackbarHelper.java
│ │ │ ├── TapHelper.java
│ │ │ └── TrackingStateHelper.java
│ │ └── rendering
│ │ │ ├── BackgroundRenderer.java
│ │ │ ├── ObjectRenderer.java
│ │ │ └── ShaderUtil.java
│ │ └── depth
│ │ ├── DepthCodelabActivity.java
│ │ └── DepthTextureHandler.java
│ └── res
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── activity_main.xml
│ └── values
│ ├── strings.xml
│ └── styles.xml
├── part3
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── models
│ │ ├── andy.obj
│ │ ├── andy.png
│ │ └── andy_spec.png
│ └── shaders
│ │ ├── background_show_depth_map.frag
│ │ ├── background_show_depth_map.vert
│ │ ├── object.frag
│ │ ├── object.vert
│ │ ├── screenquad.frag
│ │ └── screenquad.vert
│ ├── java
│ └── com
│ │ └── google
│ │ └── ar
│ │ └── core
│ │ └── codelab
│ │ ├── common
│ │ ├── helpers
│ │ │ ├── CameraPermissionHelper.java
│ │ │ ├── DisplayRotationHelper.java
│ │ │ ├── FullScreenHelper.java
│ │ │ ├── SnackbarHelper.java
│ │ │ ├── TapHelper.java
│ │ │ └── TrackingStateHelper.java
│ │ └── rendering
│ │ │ ├── BackgroundRenderer.java
│ │ │ ├── ObjectRenderer.java
│ │ │ └── ShaderUtil.java
│ │ └── depth
│ │ ├── DepthCodelabActivity.java
│ │ └── DepthTextureHandler.java
│ └── res
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── activity_main.xml
│ └── values
│ ├── strings.xml
│ └── styles.xml
├── part4_completed
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── models
│ │ ├── andy.obj
│ │ ├── andy.png
│ │ └── andy_spec.png
│ └── shaders
│ │ ├── background_show_depth_map.frag
│ │ ├── background_show_depth_map.vert
│ │ ├── object.frag
│ │ ├── object.vert
│ │ ├── occlusion_object.frag
│ │ ├── occlusion_object.vert
│ │ ├── screenquad.frag
│ │ └── screenquad.vert
│ ├── java
│ └── com
│ │ └── google
│ │ └── ar
│ │ └── core
│ │ └── codelab
│ │ ├── common
│ │ ├── helpers
│ │ │ ├── CameraPermissionHelper.java
│ │ │ ├── DisplayRotationHelper.java
│ │ │ ├── FullScreenHelper.java
│ │ │ ├── SnackbarHelper.java
│ │ │ ├── TapHelper.java
│ │ │ └── TrackingStateHelper.java
│ │ └── rendering
│ │ │ ├── BackgroundRenderer.java
│ │ │ ├── ObjectRenderer.java
│ │ │ ├── OcclusionObjectRenderer.java
│ │ │ └── ShaderUtil.java
│ │ └── depth
│ │ ├── DepthCodelabActivity.java
│ │ └── DepthTextureHandler.java
│ └── res
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── activity_main.xml
│ └── values
│ ├── strings.xml
│ └── styles.xml
└── settings.gradle
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 | ### SPECIFIC ISSUE ENCOUNTERED
14 |
15 |
16 | ### VERSIONS USED
17 | - Android Studio:
18 | - ARCore SDK for Android:
19 | - Device manufacturer, model, and O/S:
20 | - ARCore:
21 | On Windows, use: `adb shell pm dump com.google.ar.core | findstr /i "packages: versionName"`
22 | On macOS, use: `adb shell pm dump com.google.ar.core | egrep -i versionName\|packages:`
23 | - Output of `adb shell getprop ro.build.fingerprint`:
24 |
25 |
26 | ### STEPS TO REPRODUCE THE ISSUE
27 | 1.
28 | 1.
29 | 1.
30 |
31 |
32 | ### WORKAROUNDS (IF ANY)
33 |
34 |
35 | ### ADDITIONAL COMMENTS
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Android Studio configuration.
2 | *.iml
3 | .idea/
4 |
5 | # Gradle configuration.
6 | .gradle/
7 | build/
8 |
9 | # User configuration.
10 | local.properties
11 |
12 | # OS configurations.
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution;
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
25 | ## Community Guidelines
26 |
27 | This project follows [Google's Open Source Community
28 | Guidelines](https://opensource.google/conduct/).
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ARCore Depth API Codelab
2 | ========================
3 | Copyright 2020 Google LLC. All rights reserved.
4 |
5 | This Codelab provides examples for how developers can use the Depth API in ARCore to expand the realism of their AR applications.
6 |
7 | This codelab provides step-by-step instructions for how to use depth for the following use-cases:
8 | * Depth-based occlusion: Allowing virtual objects to hide behind real-world objects.
9 | * Visual effects: Showing the 3D geometry of the scene with pulsing colors.
10 |
11 | ## Android Studio projects
12 |
13 | This codelab contains the following projects:
14 | * `part0_work`: The starter app. You should make edits to this module when doing this codelab.
15 | * `part1`: Reference code of what your edits should look like when you complete Part 1 (checking depth support).
16 | * `part2`: Reference code when you complete Part 2 (retrieving the depth texture).
17 | * `part3`: Reference code when you complete Part 3 (visualizing the depth texture).
18 | * `part4_completed`: The final version of the app (including depth-based occlusion). Reference code when you complete Part 4 and this codelab.
19 |
20 | ## Related links
21 |
22 | * https://codelabs.developers.google.com/codelabs/arcore-depth/#0
23 | * https://developers.google.com/ar/develop/java/depth/overview
24 | * https://developers.googleblog.com/2020/06/a-new-wave-of-ar-realism-with-arcore-depth-api.html
25 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.0.1'
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | mavenLocal()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
19 | # Enables Android X.
20 | android.useAndroidX=true
21 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 20 16:28:34 EDT 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/part0_work/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | google-services.json
3 |
--------------------------------------------------------------------------------
/part0_work/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | def setVersionName = { ->
4 | if (project.hasProperty("androidVersionName")) {
5 | println("Replacing versionName with supplied build parameter: " +
6 | "$androidVersionName")
7 | return androidVersionName
8 | } else {
9 | return "1.0"
10 | }
11 | }
12 |
13 | android {
14 | compileSdkVersion 28
15 | defaultConfig {
16 | applicationId "com.google.ar.core.codelab.depth"
17 |
18 | // AR Optional apps must declare minSdkVersion >= 14.
19 | // AR Required apps must declare minSdkVersion >= 24.
20 | minSdkVersion 24
21 | targetSdkVersion 28
22 | versionCode 1
23 | versionName setVersionName()
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | buildTypes {
30 | release {
31 | minifyEnabled false
32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
33 | }
34 | }
35 | }
36 |
37 | dependencies {
38 | // ARCore library
39 | // Dependency version is rewritten at build time.
40 | implementation 'com.google.ar:core:1.31.0'
41 |
42 | // Obj - a simple Wavefront OBJ file loader
43 | // https://github.com/javagl/Obj
44 | implementation 'de.javagl:obj:0.2.1'
45 |
46 | implementation 'com.android.support:appcompat-v7:28.0.0'
47 | implementation 'com.android.support:design:28.0.0'
48 | }
49 |
--------------------------------------------------------------------------------
/part0_work/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/part0_work/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
34 |
35 |
41 |
42 |
43 |
44 |
45 |
46 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/part0_work/src/main/assets/models/andy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part0_work/src/main/assets/models/andy.png
--------------------------------------------------------------------------------
/part0_work/src/main/assets/models/andy_spec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part0_work/src/main/assets/models/andy_spec.png
--------------------------------------------------------------------------------
/part0_work/src/main/assets/shaders/object.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | precision mediump float;
17 |
18 | uniform sampler2D u_Texture;
19 |
20 | uniform vec4 u_LightingParameters;
21 | uniform vec4 u_MaterialParameters;
22 | uniform vec4 u_ColorCorrectionParameters;
23 |
24 | varying vec3 v_ViewPosition;
25 | varying vec3 v_ViewNormal;
26 | varying vec2 v_TexCoord;
27 | uniform vec4 u_ObjColor;
28 |
29 | void main() {
30 | // We support approximate sRGB gamma.
31 | const float kGamma = 0.4545454;
32 | const float kInverseGamma = 2.2;
33 | const float kMiddleGrayGamma = 0.466;
34 |
35 | // Unpack lighting and material parameters for better naming.
36 | vec3 viewLightDirection = u_LightingParameters.xyz;
37 | vec3 colorShift = u_ColorCorrectionParameters.rgb;
38 | float averagePixelIntensity = u_ColorCorrectionParameters.a;
39 |
40 | float materialAmbient = u_MaterialParameters.x;
41 | float materialDiffuse = u_MaterialParameters.y;
42 | float materialSpecular = u_MaterialParameters.z;
43 | float materialSpecularPower = u_MaterialParameters.w;
44 |
45 | // Normalize varying parameters, because they are linearly interpolated in the vertex shader.
46 | vec3 viewFragmentDirection = normalize(v_ViewPosition);
47 | vec3 viewNormal = normalize(v_ViewNormal);
48 |
49 | // Flip the y-texture coordinate to address the texture from top-left.
50 | vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y));
51 |
52 | // Apply color to grayscale image only if the alpha of u_ObjColor is
53 | // greater and equal to 255.0.
54 | if (u_ObjColor.a >= 255.0) {
55 | float intensity = objectColor.r;
56 | objectColor.rgb = u_ObjColor.rgb * intensity / 255.0;
57 | }
58 |
59 | // Apply inverse SRGB gamma to the texture before making lighting calculations.
60 | objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma));
61 |
62 | // Ambient light is unaffected by the light intensity.
63 | float ambient = materialAmbient;
64 |
65 | // Approximate a hemisphere light (not a harsh directional light).
66 | float diffuse = materialDiffuse *
67 | 0.5 * (dot(viewNormal, viewLightDirection) + 1.0);
68 |
69 | // Compute specular light.
70 | vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal);
71 | float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection));
72 | float specular = materialSpecular *
73 | pow(specularStrength, materialSpecularPower);
74 |
75 | vec3 color = objectColor.rgb * (ambient + diffuse) + specular;
76 | // Apply SRGB gamma before writing the fragment color.
77 | color.rgb = pow(color, vec3(kGamma));
78 | // Apply average pixel intensity and color shift
79 | color *= colorShift * (averagePixelIntensity / kMiddleGrayGamma);
80 | gl_FragColor.rgb = color;
81 | gl_FragColor.a = objectColor.a;
82 | }
83 |
--------------------------------------------------------------------------------
/part0_work/src/main/assets/shaders/object.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | uniform mat4 u_ModelView;
17 | uniform mat4 u_ModelViewProjection;
18 |
19 | attribute vec4 a_Position;
20 | attribute vec3 a_Normal;
21 | attribute vec2 a_TexCoord;
22 |
23 | varying vec3 v_ViewPosition;
24 | varying vec3 v_ViewNormal;
25 | varying vec2 v_TexCoord;
26 |
27 | void main() {
28 | v_ViewPosition = (u_ModelView * a_Position).xyz;
29 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz);
30 | v_TexCoord = a_TexCoord;
31 | gl_Position = u_ModelViewProjection * a_Position;
32 | }
33 |
--------------------------------------------------------------------------------
/part0_work/src/main/assets/shaders/screenquad.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | #extension GL_OES_EGL_image_external : require
16 |
17 | precision mediump float;
18 | varying vec2 v_TexCoord;
19 | uniform samplerExternalOES sTexture;
20 |
21 |
22 | void main() {
23 | gl_FragColor = texture2D(sTexture, v_TexCoord);
24 | }
25 |
--------------------------------------------------------------------------------
/part0_work/src/main/assets/shaders/screenquad.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | attribute vec4 a_Position;
17 | attribute vec2 a_TexCoord;
18 |
19 | varying vec2 v_TexCoord;
20 |
21 | void main() {
22 | gl_Position = a_Position;
23 | v_TexCoord = a_TexCoord;
24 | }
25 |
--------------------------------------------------------------------------------
/part0_work/src/main/java/com/google/ar/core/codelab/common/helpers/CameraPermissionHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.Manifest;
18 | import android.app.Activity;
19 | import android.content.Intent;
20 | import android.content.pm.PackageManager;
21 | import android.net.Uri;
22 | import android.provider.Settings;
23 | import android.support.v4.app.ActivityCompat;
24 | import android.support.v4.content.ContextCompat;
25 |
26 | /** Helper to ask camera permission. */
27 | public final class CameraPermissionHelper {
28 | private static final int CAMERA_PERMISSION_CODE = 0;
29 | private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA;
30 |
31 | /** Check to see we have the necessary permissions for this app. */
32 | public static boolean hasCameraPermission(Activity activity) {
33 | return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION)
34 | == PackageManager.PERMISSION_GRANTED;
35 | }
36 |
37 | /** Check to see we have the necessary permissions for this app, and ask for them if we don't. */
38 | public static void requestCameraPermission(Activity activity) {
39 | ActivityCompat.requestPermissions(
40 | activity, new String[] {CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE);
41 | }
42 |
43 | /** Check to see if we need to show the rationale for this permission. */
44 | public static boolean shouldShowRequestPermissionRationale(Activity activity) {
45 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION);
46 | }
47 |
48 | /** Launch Application Setting to grant permission. */
49 | public static void launchPermissionSettings(Activity activity) {
50 | Intent intent = new Intent();
51 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
52 | intent.setData(Uri.fromParts("package", activity.getPackageName(), null));
53 | activity.startActivity(intent);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/part0_work/src/main/java/com/google/ar/core/codelab/common/helpers/FullScreenHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.view.View;
19 |
20 | /** Helper to set up the Android full screen mode. */
21 | public final class FullScreenHelper {
22 | /**
23 | * Sets the Android fullscreen flags. Expected to be called from {@link
24 | * Activity#onWindowFocusChanged(boolean hasFocus)}.
25 | *
26 | * @param activity the Activity on which the full screen mode will be set.
27 | * @param hasFocus the hasFocus flag passed from the {@link Activity#onWindowFocusChanged(boolean
28 | * hasFocus)} callback.
29 | */
30 | public static void setFullScreenOnWindowFocusChanged(Activity activity, boolean hasFocus) {
31 | if (hasFocus) {
32 | // https://developer.android.com/training/system-ui/immersive.html#sticky
33 | activity
34 | .getWindow()
35 | .getDecorView()
36 | .setSystemUiVisibility(
37 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
38 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
39 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
40 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
41 | | View.SYSTEM_UI_FLAG_FULLSCREEN
42 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/part0_work/src/main/java/com/google/ar/core/codelab/common/helpers/SnackbarHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.support.design.widget.BaseTransientBottomBar;
19 | import android.support.design.widget.Snackbar;
20 | import android.view.View;
21 | import android.widget.TextView;
22 |
23 | /**
24 | * Helper to manage the sample snackbar. Hides the Android boilerplate code, and exposes simpler
25 | * methods.
26 | */
27 | public final class SnackbarHelper {
28 | private static final int BACKGROUND_COLOR = 0xbf323232;
29 | private Snackbar messageSnackbar;
30 | private enum DismissBehavior { HIDE, SHOW, FINISH };
31 | private int maxLines = 2;
32 | private String lastMessage = "";
33 |
34 | public boolean isShowing() {
35 | return messageSnackbar != null;
36 | }
37 |
38 | /** Shows a snackbar with a given message. */
39 | public void showMessage(Activity activity, String message) {
40 | if (!message.isEmpty() && (!isShowing() || !lastMessage.equals(message))) {
41 | lastMessage = message;
42 | show(activity, message, DismissBehavior.HIDE);
43 | }
44 | }
45 |
46 | /** Shows a snackbar with a given message, and a dismiss button. */
47 | public void showMessageWithDismiss(Activity activity, String message) {
48 | show(activity, message, DismissBehavior.SHOW);
49 | }
50 |
51 | /**
52 | * Shows a snackbar with a given error message. When dismissed, will finish the activity. Useful
53 | * for notifying errors, where no further interaction with the activity is possible.
54 | */
55 | public void showError(Activity activity, String errorMessage) {
56 | show(activity, errorMessage, DismissBehavior.FINISH);
57 | }
58 |
59 | /**
60 | * Hides the currently showing snackbar, if there is one. Safe to call from any thread. Safe to
61 | * call even if snackbar is not shown.
62 | */
63 | public void hide(Activity activity) {
64 | if (!isShowing()) {
65 | return;
66 | }
67 | lastMessage = "";
68 | Snackbar messageSnackbarToHide = messageSnackbar;
69 | messageSnackbar = null;
70 | activity.runOnUiThread(
71 | new Runnable() {
72 | @Override
73 | public void run() {
74 | messageSnackbarToHide.dismiss();
75 | }
76 | });
77 | }
78 |
79 | public void setMaxLines(int lines) {
80 | maxLines = lines;
81 | }
82 |
83 | private void show(
84 | final Activity activity, final String message, final DismissBehavior dismissBehavior) {
85 | activity.runOnUiThread(
86 | new Runnable() {
87 | @Override
88 | public void run() {
89 | messageSnackbar =
90 | Snackbar.make(
91 | activity.findViewById(android.R.id.content),
92 | message,
93 | Snackbar.LENGTH_INDEFINITE);
94 | messageSnackbar.getView().setBackgroundColor(BACKGROUND_COLOR);
95 | if (dismissBehavior != DismissBehavior.HIDE) {
96 | messageSnackbar.setAction(
97 | "Dismiss",
98 | new View.OnClickListener() {
99 | @Override
100 | public void onClick(View v) {
101 | messageSnackbar.dismiss();
102 | }
103 | });
104 | if (dismissBehavior == DismissBehavior.FINISH) {
105 | messageSnackbar.addCallback(
106 | new BaseTransientBottomBar.BaseCallback() {
107 | @Override
108 | public void onDismissed(Snackbar transientBottomBar, int event) {
109 | super.onDismissed(transientBottomBar, event);
110 | activity.finish();
111 | }
112 | });
113 | }
114 | }
115 | ((TextView)
116 | messageSnackbar
117 | .getView()
118 | .findViewById(android.support.design.R.id.snackbar_text))
119 | .setMaxLines(maxLines);
120 | messageSnackbar.show();
121 | }
122 | });
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/part0_work/src/main/java/com/google/ar/core/codelab/common/helpers/TapHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.content.Context;
18 | import android.view.GestureDetector;
19 | import android.view.MotionEvent;
20 | import android.view.View;
21 | import android.view.View.OnTouchListener;
22 | import java.util.concurrent.ArrayBlockingQueue;
23 | import java.util.concurrent.BlockingQueue;
24 |
25 | /**
26 | * Helper to detect taps using Android GestureDetector, and pass the taps between UI thread and
27 | * render thread.
28 | */
29 | public final class TapHelper implements OnTouchListener {
30 | private final GestureDetector gestureDetector;
31 | private final BlockingQueue queuedSingleTaps = new ArrayBlockingQueue<>(16);
32 |
33 | /**
34 | * Creates the tap helper.
35 | *
36 | * @param context the application's context.
37 | */
38 | public TapHelper(Context context) {
39 | gestureDetector =
40 | new GestureDetector(
41 | context,
42 | new GestureDetector.SimpleOnGestureListener() {
43 | @Override
44 | public boolean onSingleTapUp(MotionEvent e) {
45 | // Queue tap if there is space. Tap is lost if queue is full.
46 | queuedSingleTaps.offer(e);
47 | return true;
48 | }
49 |
50 | @Override
51 | public boolean onDown(MotionEvent e) {
52 | return true;
53 | }
54 | });
55 | }
56 |
57 | /**
58 | * Polls for a tap.
59 | *
60 | * @return if a tap was queued, a MotionEvent for the tap. Otherwise null if no taps are queued.
61 | */
62 | public MotionEvent poll() {
63 | return queuedSingleTaps.poll();
64 | }
65 |
66 | @Override
67 | public boolean onTouch(View view, MotionEvent motionEvent) {
68 | return gestureDetector.onTouchEvent(motionEvent);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/part0_work/src/main/java/com/google/ar/core/codelab/common/helpers/TrackingStateHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.view.WindowManager;
19 | import com.google.ar.core.Camera;
20 | import com.google.ar.core.TrackingFailureReason;
21 | import com.google.ar.core.TrackingState;
22 |
23 | /** Gets human readibly tracking failure reasons and suggested actions. */
24 | public final class TrackingStateHelper {
25 | private static final String INSUFFICIENT_FEATURES_MESSAGE =
26 | "Can't find anything. Aim device at a surface with more texture or color.";
27 | private static final String EXCESSIVE_MOTION_MESSAGE = "Moving too fast. Slow down.";
28 | private static final String INSUFFICIENT_LIGHT_MESSAGE =
29 | "Too dark. Try moving to a well-lit area.";
30 | private static final String BAD_STATE_MESSAGE =
31 | "Tracking lost due to bad internal state. Please try restarting the AR experience.";
32 | private static final String CAMERA_UNAVAILABLE_MESSAGE =
33 | "Another app is using the camera. Tap on this app or try closing the other one.";
34 |
35 | private final Activity activity;
36 |
37 | private TrackingState previousTrackingState;
38 |
39 | public TrackingStateHelper(Activity activity) {
40 | this.activity = activity;
41 | }
42 |
43 | /** Keep the screen unlocked while tracking, but allow it to lock when tracking stops. */
44 | public void updateKeepScreenOnFlag(TrackingState trackingState) {
45 | if (trackingState == previousTrackingState) {
46 | return;
47 | }
48 |
49 | previousTrackingState = trackingState;
50 | switch (trackingState) {
51 | case PAUSED:
52 | case STOPPED:
53 | activity.runOnUiThread(
54 | () -> activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
55 | break;
56 | case TRACKING:
57 | activity.runOnUiThread(
58 | () -> activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
59 | break;
60 | }
61 | }
62 |
63 | public static String getTrackingFailureReasonString(Camera camera) {
64 | TrackingFailureReason reason = camera.getTrackingFailureReason();
65 | switch (reason) {
66 | case NONE:
67 | return "";
68 | case BAD_STATE:
69 | return BAD_STATE_MESSAGE;
70 | case INSUFFICIENT_LIGHT:
71 | return INSUFFICIENT_LIGHT_MESSAGE;
72 | case EXCESSIVE_MOTION:
73 | return EXCESSIVE_MOTION_MESSAGE;
74 | case INSUFFICIENT_FEATURES:
75 | return INSUFFICIENT_FEATURES_MESSAGE;
76 | case CAMERA_UNAVAILABLE:
77 | return CAMERA_UNAVAILABLE_MESSAGE;
78 | }
79 | return "Unknown tracking failure reason: " + reason;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/part0_work/src/main/java/com/google/ar/core/codelab/common/rendering/ShaderUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.rendering;
16 |
17 | import android.content.Context;
18 | import android.opengl.GLES20;
19 | import android.util.Log;
20 | import java.io.BufferedReader;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.io.InputStreamReader;
24 |
25 | /** Shader helper functions. */
26 | public class ShaderUtil {
27 | /**
28 | * Converts a raw text file, saved as a resource, into an OpenGL ES shader.
29 | *
30 | * @param type The type of shader we will be creating.
31 | * @param filename The filename of the asset file about to be turned into a shader.
32 | * @return The shader object handler.
33 | */
34 | public static int loadGLShader(String tag, Context context, int type, String filename)
35 | throws IOException {
36 | String code = readShaderFileFromAssets(context, filename);
37 | int shader = GLES20.glCreateShader(type);
38 | GLES20.glShaderSource(shader, code);
39 | GLES20.glCompileShader(shader);
40 |
41 | // Get the compilation status.
42 | final int[] compileStatus = new int[1];
43 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
44 |
45 | // If the compilation failed, delete the shader.
46 | if (compileStatus[0] == 0) {
47 | Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader));
48 | GLES20.glDeleteShader(shader);
49 | shader = 0;
50 | }
51 |
52 | if (shader == 0) {
53 | throw new RuntimeException("Error creating shader.");
54 | }
55 |
56 | return shader;
57 | }
58 |
59 | /**
60 | * Checks if we've had an error inside of OpenGL ES, and if so what that error is.
61 | *
62 | * @param label Label to report in case of error.
63 | * @throws RuntimeException If an OpenGL error is detected.
64 | */
65 | public static void checkGLError(String tag, String label) {
66 | int lastError = GLES20.GL_NO_ERROR;
67 | // Drain the queue of all errors.
68 | int error;
69 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
70 | Log.e(tag, label + ": glError " + error);
71 | lastError = error;
72 | }
73 | if (lastError != GLES20.GL_NO_ERROR) {
74 | throw new RuntimeException(label + ": glError " + lastError);
75 | }
76 | }
77 |
78 | /**
79 | * Converts a raw shader file into a string.
80 | *
81 | * @param filename The filename of the shader file about to be turned into a shader.
82 | * @return The context of the text file, or null in case of error.
83 | */
84 | private static String readShaderFileFromAssets(Context context, String filename)
85 | throws IOException {
86 | try (InputStream inputStream = context.getAssets().open(filename);
87 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
88 | StringBuilder sb = new StringBuilder();
89 | String line;
90 | while ((line = reader.readLine()) != null) {
91 | String[] tokens = line.split(" ", -1);
92 | if (tokens[0].equals("#include")) {
93 | String includeFilename = tokens[1];
94 | includeFilename = includeFilename.replace("\"", "");
95 | if (includeFilename.equals(filename)) {
96 | throw new IOException("Do not include the calling file.");
97 | }
98 | sb.append(readShaderFileFromAssets(context, includeFilename));
99 | } else {
100 | sb.append(line).append("\n");
101 | }
102 | }
103 | return sb.toString();
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/part0_work/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part0_work/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/part0_work/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
16 |
21 |
22 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/part0_work/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | Depth Codelab
19 |
20 |
--------------------------------------------------------------------------------
/part0_work/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
22 |
29 |
30 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/part1/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | google-services.json
3 |
--------------------------------------------------------------------------------
/part1/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | def setVersionName = { ->
4 | if (project.hasProperty("androidVersionName")) {
5 | println("Replacing versionName with supplied build parameter: " +
6 | "$androidVersionName")
7 | return androidVersionName
8 | } else {
9 | return "1.0"
10 | }
11 | }
12 |
13 | android {
14 | compileSdkVersion 28
15 | defaultConfig {
16 | applicationId "com.google.ar.core.codelab.depth"
17 |
18 | // AR Optional apps must declare minSdkVersion >= 14.
19 | // AR Required apps must declare minSdkVersion >= 24.
20 | minSdkVersion 24
21 | targetSdkVersion 28
22 | versionCode 1
23 | versionName setVersionName()
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | buildTypes {
30 | release {
31 | minifyEnabled false
32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
33 | }
34 | }
35 | }
36 |
37 | dependencies {
38 | // ARCore library
39 | // Dependency version is rewritten at build time.
40 | implementation 'com.google.ar:core:1.31.0'
41 |
42 | // Obj - a simple Wavefront OBJ file loader
43 | // https://github.com/javagl/Obj
44 | implementation 'de.javagl:obj:0.2.1'
45 |
46 | implementation 'com.android.support:appcompat-v7:28.0.0'
47 | implementation 'com.android.support:design:28.0.0'
48 | }
49 |
--------------------------------------------------------------------------------
/part1/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/part1/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
34 |
35 |
41 |
42 |
43 |
44 |
45 |
46 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/part1/src/main/assets/models/andy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part1/src/main/assets/models/andy.png
--------------------------------------------------------------------------------
/part1/src/main/assets/models/andy_spec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part1/src/main/assets/models/andy_spec.png
--------------------------------------------------------------------------------
/part1/src/main/assets/shaders/object.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | precision mediump float;
17 |
18 | uniform sampler2D u_Texture;
19 |
20 | uniform vec4 u_LightingParameters;
21 | uniform vec4 u_MaterialParameters;
22 | uniform vec4 u_ColorCorrectionParameters;
23 |
24 | varying vec3 v_ViewPosition;
25 | varying vec3 v_ViewNormal;
26 | varying vec2 v_TexCoord;
27 | uniform vec4 u_ObjColor;
28 |
29 | void main() {
30 | // We support approximate sRGB gamma.
31 | const float kGamma = 0.4545454;
32 | const float kInverseGamma = 2.2;
33 | const float kMiddleGrayGamma = 0.466;
34 |
35 | // Unpack lighting and material parameters for better naming.
36 | vec3 viewLightDirection = u_LightingParameters.xyz;
37 | vec3 colorShift = u_ColorCorrectionParameters.rgb;
38 | float averagePixelIntensity = u_ColorCorrectionParameters.a;
39 |
40 | float materialAmbient = u_MaterialParameters.x;
41 | float materialDiffuse = u_MaterialParameters.y;
42 | float materialSpecular = u_MaterialParameters.z;
43 | float materialSpecularPower = u_MaterialParameters.w;
44 |
45 | // Normalize varying parameters, because they are linearly interpolated in the vertex shader.
46 | vec3 viewFragmentDirection = normalize(v_ViewPosition);
47 | vec3 viewNormal = normalize(v_ViewNormal);
48 |
49 | // Flip the y-texture coordinate to address the texture from top-left.
50 | vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y));
51 |
52 | // Apply color to grayscale image only if the alpha of u_ObjColor is
53 | // greater and equal to 255.0.
54 | if (u_ObjColor.a >= 255.0) {
55 | float intensity = objectColor.r;
56 | objectColor.rgb = u_ObjColor.rgb * intensity / 255.0;
57 | }
58 |
59 | // Apply inverse SRGB gamma to the texture before making lighting calculations.
60 | objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma));
61 |
62 | // Ambient light is unaffected by the light intensity.
63 | float ambient = materialAmbient;
64 |
65 | // Approximate a hemisphere light (not a harsh directional light).
66 | float diffuse = materialDiffuse *
67 | 0.5 * (dot(viewNormal, viewLightDirection) + 1.0);
68 |
69 | // Compute specular light.
70 | vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal);
71 | float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection));
72 | float specular = materialSpecular *
73 | pow(specularStrength, materialSpecularPower);
74 |
75 | vec3 color = objectColor.rgb * (ambient + diffuse) + specular;
76 | // Apply SRGB gamma before writing the fragment color.
77 | color.rgb = pow(color, vec3(kGamma));
78 | // Apply average pixel intensity and color shift
79 | color *= colorShift * (averagePixelIntensity / kMiddleGrayGamma);
80 | gl_FragColor.rgb = color;
81 | gl_FragColor.a = objectColor.a;
82 | }
83 |
--------------------------------------------------------------------------------
/part1/src/main/assets/shaders/object.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | uniform mat4 u_ModelView;
17 | uniform mat4 u_ModelViewProjection;
18 |
19 | attribute vec4 a_Position;
20 | attribute vec3 a_Normal;
21 | attribute vec2 a_TexCoord;
22 |
23 | varying vec3 v_ViewPosition;
24 | varying vec3 v_ViewNormal;
25 | varying vec2 v_TexCoord;
26 |
27 | void main() {
28 | v_ViewPosition = (u_ModelView * a_Position).xyz;
29 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz);
30 | v_TexCoord = a_TexCoord;
31 | gl_Position = u_ModelViewProjection * a_Position;
32 | }
33 |
--------------------------------------------------------------------------------
/part1/src/main/assets/shaders/screenquad.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | #extension GL_OES_EGL_image_external : require
16 |
17 | precision mediump float;
18 | varying vec2 v_TexCoord;
19 | uniform samplerExternalOES sTexture;
20 |
21 |
22 | void main() {
23 | gl_FragColor = texture2D(sTexture, v_TexCoord);
24 | }
25 |
--------------------------------------------------------------------------------
/part1/src/main/assets/shaders/screenquad.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | attribute vec4 a_Position;
17 | attribute vec2 a_TexCoord;
18 |
19 | varying vec2 v_TexCoord;
20 |
21 | void main() {
22 | gl_Position = a_Position;
23 | v_TexCoord = a_TexCoord;
24 | }
25 |
--------------------------------------------------------------------------------
/part1/src/main/java/com/google/ar/core/codelab/common/helpers/CameraPermissionHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.Manifest;
18 | import android.app.Activity;
19 | import android.content.Intent;
20 | import android.content.pm.PackageManager;
21 | import android.net.Uri;
22 | import android.provider.Settings;
23 | import android.support.v4.app.ActivityCompat;
24 | import android.support.v4.content.ContextCompat;
25 |
26 | /** Helper to ask camera permission. */
27 | public final class CameraPermissionHelper {
28 | private static final int CAMERA_PERMISSION_CODE = 0;
29 | private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA;
30 |
31 | /** Check to see we have the necessary permissions for this app. */
32 | public static boolean hasCameraPermission(Activity activity) {
33 | return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION)
34 | == PackageManager.PERMISSION_GRANTED;
35 | }
36 |
37 | /** Check to see we have the necessary permissions for this app, and ask for them if we don't. */
38 | public static void requestCameraPermission(Activity activity) {
39 | ActivityCompat.requestPermissions(
40 | activity, new String[] {CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE);
41 | }
42 |
43 | /** Check to see if we need to show the rationale for this permission. */
44 | public static boolean shouldShowRequestPermissionRationale(Activity activity) {
45 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION);
46 | }
47 |
48 | /** Launch Application Setting to grant permission. */
49 | public static void launchPermissionSettings(Activity activity) {
50 | Intent intent = new Intent();
51 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
52 | intent.setData(Uri.fromParts("package", activity.getPackageName(), null));
53 | activity.startActivity(intent);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/part1/src/main/java/com/google/ar/core/codelab/common/helpers/DisplayRotationHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.content.Context;
19 | import android.hardware.camera2.CameraAccessException;
20 | import android.hardware.camera2.CameraCharacteristics;
21 | import android.hardware.camera2.CameraManager;
22 | import android.hardware.display.DisplayManager;
23 | import android.hardware.display.DisplayManager.DisplayListener;
24 | import android.view.Display;
25 | import android.view.Surface;
26 | import android.view.WindowManager;
27 | import com.google.ar.core.Session;
28 |
29 | /**
30 | * Helper to track the display rotations. In particular, the 180 degree rotations are not notified
31 | * by the onSurfaceChanged() callback, and thus they require listening to the android display
32 | * events.
33 | */
34 | public final class DisplayRotationHelper implements DisplayListener {
35 | private boolean viewportChanged;
36 | private int viewportWidth;
37 | private int viewportHeight;
38 | private final Display display;
39 | private final DisplayManager displayManager;
40 | private final CameraManager cameraManager;
41 |
42 | /**
43 | * Constructs the DisplayRotationHelper but does not register the listener yet.
44 | *
45 | * @param context the Android {@link Context}.
46 | */
47 | public DisplayRotationHelper(Context context) {
48 | displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
49 | cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
50 | WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
51 | display = windowManager.getDefaultDisplay();
52 | }
53 |
54 | /** Registers the display listener. Should be called from {@link Activity#onResume()}. */
55 | public void onResume() {
56 | displayManager.registerDisplayListener(this, null);
57 | }
58 |
59 | /** Unregisters the display listener. Should be called from {@link Activity#onPause()}. */
60 | public void onPause() {
61 | displayManager.unregisterDisplayListener(this);
62 | }
63 |
64 | /**
65 | * Records a change in surface dimensions. This will be later used by {@link
66 | * #updateSessionIfNeeded(Session)}. Should be called from {@link
67 | * android.opengl.GLSurfaceView.Renderer
68 | * #onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int)}.
69 | *
70 | * @param width the updated width of the surface.
71 | * @param height the updated height of the surface.
72 | */
73 | public void onSurfaceChanged(int width, int height) {
74 | viewportWidth = width;
75 | viewportHeight = height;
76 | viewportChanged = true;
77 | }
78 |
79 | /**
80 | * Updates the session display geometry if a change was posted either by {@link
81 | * #onSurfaceChanged(int, int)} call or by {@link #onDisplayChanged(int)} system callback. This
82 | * function should be called explicitly before each call to {@link Session#update()}. This
83 | * function will also clear the 'pending update' (viewportChanged) flag.
84 | *
85 | * @param session the {@link Session} object to update if display geometry changed.
86 | */
87 | public void updateSessionIfNeeded(Session session) {
88 | if (viewportChanged) {
89 | int displayRotation = display.getRotation();
90 | session.setDisplayGeometry(displayRotation, viewportWidth, viewportHeight);
91 | viewportChanged = false;
92 | }
93 | }
94 |
95 | /**
96 | * Returns the aspect ratio of the GL surface viewport while accounting for the display rotation
97 | * relative to the device camera sensor orientation.
98 | */
99 | public float getCameraSensorRelativeViewportAspectRatio(String cameraId) {
100 | float aspectRatio;
101 | int cameraSensorToDisplayRotation = getCameraSensorToDisplayRotation(cameraId);
102 | switch (cameraSensorToDisplayRotation) {
103 | case 90:
104 | case 270:
105 | aspectRatio = (float) viewportHeight / (float) viewportWidth;
106 | break;
107 | case 0:
108 | case 180:
109 | aspectRatio = (float) viewportWidth / (float) viewportHeight;
110 | break;
111 | default:
112 | throw new RuntimeException("Unhandled rotation: " + cameraSensorToDisplayRotation);
113 | }
114 | return aspectRatio;
115 | }
116 |
117 | /**
118 | * Returns the rotation of the back-facing camera with respect to the display. The value is one of
119 | * 0, 90, 180, 270.
120 | */
121 | public int getCameraSensorToDisplayRotation(String cameraId) {
122 | CameraCharacteristics characteristics;
123 | try {
124 | characteristics = cameraManager.getCameraCharacteristics(cameraId);
125 | } catch (CameraAccessException e) {
126 | throw new RuntimeException("Unable to determine display orientation", e);
127 | }
128 |
129 | // Camera sensor orientation.
130 | int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
131 |
132 | // Current display orientation.
133 | int displayOrientation = toDegrees(display.getRotation());
134 |
135 | // Make sure we return 0, 90, 180, or 270 degrees.
136 | return (sensorOrientation - displayOrientation + 360) % 360;
137 | }
138 |
139 | private int toDegrees(int rotation) {
140 | switch (rotation) {
141 | case Surface.ROTATION_0:
142 | return 0;
143 | case Surface.ROTATION_90:
144 | return 90;
145 | case Surface.ROTATION_180:
146 | return 180;
147 | case Surface.ROTATION_270:
148 | return 270;
149 | default:
150 | throw new RuntimeException("Unknown rotation " + rotation);
151 | }
152 | }
153 |
154 | @Override
155 | public void onDisplayAdded(int displayId) {}
156 |
157 | @Override
158 | public void onDisplayRemoved(int displayId) {}
159 |
160 | @Override
161 | public void onDisplayChanged(int displayId) {
162 | viewportChanged = true;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/part1/src/main/java/com/google/ar/core/codelab/common/helpers/FullScreenHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.view.View;
19 |
20 | /** Helper to set up the Android full screen mode. */
21 | public final class FullScreenHelper {
22 | /**
23 | * Sets the Android fullscreen flags. Expected to be called from {@link
24 | * Activity#onWindowFocusChanged(boolean hasFocus)}.
25 | *
26 | * @param activity the Activity on which the full screen mode will be set.
27 | * @param hasFocus the hasFocus flag passed from the {@link Activity#onWindowFocusChanged(boolean
28 | * hasFocus)} callback.
29 | */
30 | public static void setFullScreenOnWindowFocusChanged(Activity activity, boolean hasFocus) {
31 | if (hasFocus) {
32 | // https://developer.android.com/training/system-ui/immersive.html#sticky
33 | activity
34 | .getWindow()
35 | .getDecorView()
36 | .setSystemUiVisibility(
37 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
38 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
39 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
40 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
41 | | View.SYSTEM_UI_FLAG_FULLSCREEN
42 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/part1/src/main/java/com/google/ar/core/codelab/common/helpers/SnackbarHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.support.design.widget.BaseTransientBottomBar;
19 | import android.support.design.widget.Snackbar;
20 | import android.view.View;
21 | import android.widget.TextView;
22 |
23 | /**
24 | * Helper to manage the sample snackbar. Hides the Android boilerplate code, and exposes simpler
25 | * methods.
26 | */
27 | public final class SnackbarHelper {
28 | private static final int BACKGROUND_COLOR = 0xbf323232;
29 | private Snackbar messageSnackbar;
30 | private enum DismissBehavior { HIDE, SHOW, FINISH };
31 | private int maxLines = 2;
32 | private String lastMessage = "";
33 |
34 | public boolean isShowing() {
35 | return messageSnackbar != null;
36 | }
37 |
38 | /** Shows a snackbar with a given message. */
39 | public void showMessage(Activity activity, String message) {
40 | if (!message.isEmpty() && (!isShowing() || !lastMessage.equals(message))) {
41 | lastMessage = message;
42 | show(activity, message, DismissBehavior.HIDE);
43 | }
44 | }
45 |
46 | /** Shows a snackbar with a given message, and a dismiss button. */
47 | public void showMessageWithDismiss(Activity activity, String message) {
48 | show(activity, message, DismissBehavior.SHOW);
49 | }
50 |
51 | /**
52 | * Shows a snackbar with a given error message. When dismissed, will finish the activity. Useful
53 | * for notifying errors, where no further interaction with the activity is possible.
54 | */
55 | public void showError(Activity activity, String errorMessage) {
56 | show(activity, errorMessage, DismissBehavior.FINISH);
57 | }
58 |
59 | /**
60 | * Hides the currently showing snackbar, if there is one. Safe to call from any thread. Safe to
61 | * call even if snackbar is not shown.
62 | */
63 | public void hide(Activity activity) {
64 | if (!isShowing()) {
65 | return;
66 | }
67 | lastMessage = "";
68 | Snackbar messageSnackbarToHide = messageSnackbar;
69 | messageSnackbar = null;
70 | activity.runOnUiThread(
71 | new Runnable() {
72 | @Override
73 | public void run() {
74 | messageSnackbarToHide.dismiss();
75 | }
76 | });
77 | }
78 |
79 | public void setMaxLines(int lines) {
80 | maxLines = lines;
81 | }
82 |
83 | private void show(
84 | final Activity activity, final String message, final DismissBehavior dismissBehavior) {
85 | activity.runOnUiThread(
86 | new Runnable() {
87 | @Override
88 | public void run() {
89 | messageSnackbar =
90 | Snackbar.make(
91 | activity.findViewById(android.R.id.content),
92 | message,
93 | Snackbar.LENGTH_INDEFINITE);
94 | messageSnackbar.getView().setBackgroundColor(BACKGROUND_COLOR);
95 | if (dismissBehavior != DismissBehavior.HIDE) {
96 | messageSnackbar.setAction(
97 | "Dismiss",
98 | new View.OnClickListener() {
99 | @Override
100 | public void onClick(View v) {
101 | messageSnackbar.dismiss();
102 | }
103 | });
104 | if (dismissBehavior == DismissBehavior.FINISH) {
105 | messageSnackbar.addCallback(
106 | new BaseTransientBottomBar.BaseCallback() {
107 | @Override
108 | public void onDismissed(Snackbar transientBottomBar, int event) {
109 | super.onDismissed(transientBottomBar, event);
110 | activity.finish();
111 | }
112 | });
113 | }
114 | }
115 | ((TextView)
116 | messageSnackbar
117 | .getView()
118 | .findViewById(android.support.design.R.id.snackbar_text))
119 | .setMaxLines(maxLines);
120 | messageSnackbar.show();
121 | }
122 | });
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/part1/src/main/java/com/google/ar/core/codelab/common/helpers/TapHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.content.Context;
18 | import android.view.GestureDetector;
19 | import android.view.MotionEvent;
20 | import android.view.View;
21 | import android.view.View.OnTouchListener;
22 | import java.util.concurrent.ArrayBlockingQueue;
23 | import java.util.concurrent.BlockingQueue;
24 |
25 | /**
26 | * Helper to detect taps using Android GestureDetector, and pass the taps between UI thread and
27 | * render thread.
28 | */
29 | public final class TapHelper implements OnTouchListener {
30 | private final GestureDetector gestureDetector;
31 | private final BlockingQueue queuedSingleTaps = new ArrayBlockingQueue<>(16);
32 |
33 | /**
34 | * Creates the tap helper.
35 | *
36 | * @param context the application's context.
37 | */
38 | public TapHelper(Context context) {
39 | gestureDetector =
40 | new GestureDetector(
41 | context,
42 | new GestureDetector.SimpleOnGestureListener() {
43 | @Override
44 | public boolean onSingleTapUp(MotionEvent e) {
45 | // Queue tap if there is space. Tap is lost if queue is full.
46 | queuedSingleTaps.offer(e);
47 | return true;
48 | }
49 |
50 | @Override
51 | public boolean onDown(MotionEvent e) {
52 | return true;
53 | }
54 | });
55 | }
56 |
57 | /**
58 | * Polls for a tap.
59 | *
60 | * @return if a tap was queued, a MotionEvent for the tap. Otherwise null if no taps are queued.
61 | */
62 | public MotionEvent poll() {
63 | return queuedSingleTaps.poll();
64 | }
65 |
66 | @Override
67 | public boolean onTouch(View view, MotionEvent motionEvent) {
68 | return gestureDetector.onTouchEvent(motionEvent);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/part1/src/main/java/com/google/ar/core/codelab/common/helpers/TrackingStateHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.view.WindowManager;
19 | import com.google.ar.core.Camera;
20 | import com.google.ar.core.TrackingFailureReason;
21 | import com.google.ar.core.TrackingState;
22 |
23 | /** Gets human readibly tracking failure reasons and suggested actions. */
24 | public final class TrackingStateHelper {
25 | private static final String INSUFFICIENT_FEATURES_MESSAGE =
26 | "Can't find anything. Aim device at a surface with more texture or color.";
27 | private static final String EXCESSIVE_MOTION_MESSAGE = "Moving too fast. Slow down.";
28 | private static final String INSUFFICIENT_LIGHT_MESSAGE =
29 | "Too dark. Try moving to a well-lit area.";
30 | private static final String BAD_STATE_MESSAGE =
31 | "Tracking lost due to bad internal state. Please try restarting the AR experience.";
32 | private static final String CAMERA_UNAVAILABLE_MESSAGE =
33 | "Another app is using the camera. Tap on this app or try closing the other one.";
34 |
35 | private final Activity activity;
36 |
37 | private TrackingState previousTrackingState;
38 |
39 | public TrackingStateHelper(Activity activity) {
40 | this.activity = activity;
41 | }
42 |
43 | /** Keep the screen unlocked while tracking, but allow it to lock when tracking stops. */
44 | public void updateKeepScreenOnFlag(TrackingState trackingState) {
45 | if (trackingState == previousTrackingState) {
46 | return;
47 | }
48 |
49 | previousTrackingState = trackingState;
50 | switch (trackingState) {
51 | case PAUSED:
52 | case STOPPED:
53 | activity.runOnUiThread(
54 | () -> activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
55 | break;
56 | case TRACKING:
57 | activity.runOnUiThread(
58 | () -> activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
59 | break;
60 | }
61 | }
62 |
63 | public static String getTrackingFailureReasonString(Camera camera) {
64 | TrackingFailureReason reason = camera.getTrackingFailureReason();
65 | switch (reason) {
66 | case NONE:
67 | return "";
68 | case BAD_STATE:
69 | return BAD_STATE_MESSAGE;
70 | case INSUFFICIENT_LIGHT:
71 | return INSUFFICIENT_LIGHT_MESSAGE;
72 | case EXCESSIVE_MOTION:
73 | return EXCESSIVE_MOTION_MESSAGE;
74 | case INSUFFICIENT_FEATURES:
75 | return INSUFFICIENT_FEATURES_MESSAGE;
76 | case CAMERA_UNAVAILABLE:
77 | return CAMERA_UNAVAILABLE_MESSAGE;
78 | }
79 | return "Unknown tracking failure reason: " + reason;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/part1/src/main/java/com/google/ar/core/codelab/common/rendering/ShaderUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.rendering;
16 |
17 | import android.content.Context;
18 | import android.opengl.GLES20;
19 | import android.util.Log;
20 | import java.io.BufferedReader;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.io.InputStreamReader;
24 |
25 | /** Shader helper functions. */
26 | public class ShaderUtil {
27 | /**
28 | * Converts a raw text file, saved as a resource, into an OpenGL ES shader.
29 | *
30 | * @param type The type of shader we will be creating.
31 | * @param filename The filename of the asset file about to be turned into a shader.
32 | * @return The shader object handler.
33 | */
34 | public static int loadGLShader(String tag, Context context, int type, String filename)
35 | throws IOException {
36 | String code = readShaderFileFromAssets(context, filename);
37 | int shader = GLES20.glCreateShader(type);
38 | GLES20.glShaderSource(shader, code);
39 | GLES20.glCompileShader(shader);
40 |
41 | // Get the compilation status.
42 | final int[] compileStatus = new int[1];
43 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
44 |
45 | // If the compilation failed, delete the shader.
46 | if (compileStatus[0] == 0) {
47 | Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader));
48 | GLES20.glDeleteShader(shader);
49 | shader = 0;
50 | }
51 |
52 | if (shader == 0) {
53 | throw new RuntimeException("Error creating shader.");
54 | }
55 |
56 | return shader;
57 | }
58 |
59 | /**
60 | * Checks if we've had an error inside of OpenGL ES, and if so what that error is.
61 | *
62 | * @param label Label to report in case of error.
63 | * @throws RuntimeException If an OpenGL error is detected.
64 | */
65 | public static void checkGLError(String tag, String label) {
66 | int lastError = GLES20.GL_NO_ERROR;
67 | // Drain the queue of all errors.
68 | int error;
69 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
70 | Log.e(tag, label + ": glError " + error);
71 | lastError = error;
72 | }
73 | if (lastError != GLES20.GL_NO_ERROR) {
74 | throw new RuntimeException(label + ": glError " + lastError);
75 | }
76 | }
77 |
78 | /**
79 | * Converts a raw shader file into a string.
80 | *
81 | * @param filename The filename of the shader file about to be turned into a shader.
82 | * @return The context of the text file, or null in case of error.
83 | */
84 | private static String readShaderFileFromAssets(Context context, String filename)
85 | throws IOException {
86 | try (InputStream inputStream = context.getAssets().open(filename);
87 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
88 | StringBuilder sb = new StringBuilder();
89 | String line;
90 | while ((line = reader.readLine()) != null) {
91 | String[] tokens = line.split(" ", -1);
92 | if (tokens[0].equals("#include")) {
93 | String includeFilename = tokens[1];
94 | includeFilename = includeFilename.replace("\"", "");
95 | if (includeFilename.equals(filename)) {
96 | throw new IOException("Do not include the calling file.");
97 | }
98 | sb.append(readShaderFileFromAssets(context, includeFilename));
99 | } else {
100 | sb.append(line).append("\n");
101 | }
102 | }
103 | return sb.toString();
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/part1/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part1/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/part1/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
16 |
21 |
22 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/part1/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | Depth Codelab
19 |
20 |
--------------------------------------------------------------------------------
/part1/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
22 |
29 |
30 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/part2/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | google-services.json
3 |
--------------------------------------------------------------------------------
/part2/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | def setVersionName = { ->
4 | if (project.hasProperty("androidVersionName")) {
5 | println("Replacing versionName with supplied build parameter: " +
6 | "$androidVersionName")
7 | return androidVersionName
8 | } else {
9 | return "1.0"
10 | }
11 | }
12 |
13 | android {
14 | compileSdkVersion 28
15 | defaultConfig {
16 | applicationId "com.google.ar.core.codelab.depth"
17 |
18 | // AR Optional apps must declare minSdkVersion >= 14.
19 | // AR Required apps must declare minSdkVersion >= 24.
20 | minSdkVersion 24
21 | targetSdkVersion 28
22 | versionCode 1
23 | versionName setVersionName()
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | buildTypes {
30 | release {
31 | minifyEnabled false
32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
33 | }
34 | }
35 | }
36 |
37 | dependencies {
38 | // ARCore library
39 | // Dependency version is rewritten at build time.
40 | implementation 'com.google.ar:core:1.31.0'
41 |
42 | // Obj - a simple Wavefront OBJ file loader
43 | // https://github.com/javagl/Obj
44 | implementation 'de.javagl:obj:0.2.1'
45 |
46 | implementation 'com.android.support:appcompat-v7:28.0.0'
47 | implementation 'com.android.support:design:28.0.0'
48 | }
49 |
--------------------------------------------------------------------------------
/part2/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/part2/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
34 |
35 |
41 |
42 |
43 |
44 |
45 |
46 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/part2/src/main/assets/models/andy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part2/src/main/assets/models/andy.png
--------------------------------------------------------------------------------
/part2/src/main/assets/models/andy_spec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part2/src/main/assets/models/andy_spec.png
--------------------------------------------------------------------------------
/part2/src/main/assets/shaders/object.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | precision mediump float;
17 |
18 | uniform sampler2D u_Texture;
19 |
20 | uniform vec4 u_LightingParameters;
21 | uniform vec4 u_MaterialParameters;
22 | uniform vec4 u_ColorCorrectionParameters;
23 |
24 | varying vec3 v_ViewPosition;
25 | varying vec3 v_ViewNormal;
26 | varying vec2 v_TexCoord;
27 | uniform vec4 u_ObjColor;
28 |
29 | void main() {
30 | // We support approximate sRGB gamma.
31 | const float kGamma = 0.4545454;
32 | const float kInverseGamma = 2.2;
33 | const float kMiddleGrayGamma = 0.466;
34 |
35 | // Unpack lighting and material parameters for better naming.
36 | vec3 viewLightDirection = u_LightingParameters.xyz;
37 | vec3 colorShift = u_ColorCorrectionParameters.rgb;
38 | float averagePixelIntensity = u_ColorCorrectionParameters.a;
39 |
40 | float materialAmbient = u_MaterialParameters.x;
41 | float materialDiffuse = u_MaterialParameters.y;
42 | float materialSpecular = u_MaterialParameters.z;
43 | float materialSpecularPower = u_MaterialParameters.w;
44 |
45 | // Normalize varying parameters, because they are linearly interpolated in the vertex shader.
46 | vec3 viewFragmentDirection = normalize(v_ViewPosition);
47 | vec3 viewNormal = normalize(v_ViewNormal);
48 |
49 | // Flip the y-texture coordinate to address the texture from top-left.
50 | vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y));
51 |
52 | // Apply color to grayscale image only if the alpha of u_ObjColor is
53 | // greater and equal to 255.0.
54 | if (u_ObjColor.a >= 255.0) {
55 | float intensity = objectColor.r;
56 | objectColor.rgb = u_ObjColor.rgb * intensity / 255.0;
57 | }
58 |
59 | // Apply inverse SRGB gamma to the texture before making lighting calculations.
60 | objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma));
61 |
62 | // Ambient light is unaffected by the light intensity.
63 | float ambient = materialAmbient;
64 |
65 | // Approximate a hemisphere light (not a harsh directional light).
66 | float diffuse = materialDiffuse *
67 | 0.5 * (dot(viewNormal, viewLightDirection) + 1.0);
68 |
69 | // Compute specular light.
70 | vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal);
71 | float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection));
72 | float specular = materialSpecular *
73 | pow(specularStrength, materialSpecularPower);
74 |
75 | vec3 color = objectColor.rgb * (ambient + diffuse) + specular;
76 | // Apply SRGB gamma before writing the fragment color.
77 | color.rgb = pow(color, vec3(kGamma));
78 | // Apply average pixel intensity and color shift
79 | color *= colorShift * (averagePixelIntensity / kMiddleGrayGamma);
80 | gl_FragColor.rgb = color;
81 | gl_FragColor.a = objectColor.a;
82 | }
83 |
--------------------------------------------------------------------------------
/part2/src/main/assets/shaders/object.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | uniform mat4 u_ModelView;
17 | uniform mat4 u_ModelViewProjection;
18 |
19 | attribute vec4 a_Position;
20 | attribute vec3 a_Normal;
21 | attribute vec2 a_TexCoord;
22 |
23 | varying vec3 v_ViewPosition;
24 | varying vec3 v_ViewNormal;
25 | varying vec2 v_TexCoord;
26 |
27 | void main() {
28 | v_ViewPosition = (u_ModelView * a_Position).xyz;
29 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz);
30 | v_TexCoord = a_TexCoord;
31 | gl_Position = u_ModelViewProjection * a_Position;
32 | }
33 |
--------------------------------------------------------------------------------
/part2/src/main/assets/shaders/screenquad.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | #extension GL_OES_EGL_image_external : require
16 |
17 | precision mediump float;
18 | varying vec2 v_TexCoord;
19 | uniform samplerExternalOES sTexture;
20 |
21 |
22 | void main() {
23 | gl_FragColor = texture2D(sTexture, v_TexCoord);
24 | }
25 |
--------------------------------------------------------------------------------
/part2/src/main/assets/shaders/screenquad.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | attribute vec4 a_Position;
17 | attribute vec2 a_TexCoord;
18 |
19 | varying vec2 v_TexCoord;
20 |
21 | void main() {
22 | gl_Position = a_Position;
23 | v_TexCoord = a_TexCoord;
24 | }
25 |
--------------------------------------------------------------------------------
/part2/src/main/java/com/google/ar/core/codelab/common/helpers/CameraPermissionHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.Manifest;
18 | import android.app.Activity;
19 | import android.content.Intent;
20 | import android.content.pm.PackageManager;
21 | import android.net.Uri;
22 | import android.provider.Settings;
23 | import android.support.v4.app.ActivityCompat;
24 | import android.support.v4.content.ContextCompat;
25 |
26 | /** Helper to ask camera permission. */
27 | public final class CameraPermissionHelper {
28 | private static final int CAMERA_PERMISSION_CODE = 0;
29 | private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA;
30 |
31 | /** Check to see we have the necessary permissions for this app. */
32 | public static boolean hasCameraPermission(Activity activity) {
33 | return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION)
34 | == PackageManager.PERMISSION_GRANTED;
35 | }
36 |
37 | /** Check to see we have the necessary permissions for this app, and ask for them if we don't. */
38 | public static void requestCameraPermission(Activity activity) {
39 | ActivityCompat.requestPermissions(
40 | activity, new String[] {CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE);
41 | }
42 |
43 | /** Check to see if we need to show the rationale for this permission. */
44 | public static boolean shouldShowRequestPermissionRationale(Activity activity) {
45 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION);
46 | }
47 |
48 | /** Launch Application Setting to grant permission. */
49 | public static void launchPermissionSettings(Activity activity) {
50 | Intent intent = new Intent();
51 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
52 | intent.setData(Uri.fromParts("package", activity.getPackageName(), null));
53 | activity.startActivity(intent);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/part2/src/main/java/com/google/ar/core/codelab/common/helpers/DisplayRotationHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.content.Context;
19 | import android.hardware.camera2.CameraAccessException;
20 | import android.hardware.camera2.CameraCharacteristics;
21 | import android.hardware.camera2.CameraManager;
22 | import android.hardware.display.DisplayManager;
23 | import android.hardware.display.DisplayManager.DisplayListener;
24 | import android.view.Display;
25 | import android.view.Surface;
26 | import android.view.WindowManager;
27 | import com.google.ar.core.Session;
28 |
29 | /**
30 | * Helper to track the display rotations. In particular, the 180 degree rotations are not notified
31 | * by the onSurfaceChanged() callback, and thus they require listening to the android display
32 | * events.
33 | */
34 | public final class DisplayRotationHelper implements DisplayListener {
35 | private boolean viewportChanged;
36 | private int viewportWidth;
37 | private int viewportHeight;
38 | private final Display display;
39 | private final DisplayManager displayManager;
40 | private final CameraManager cameraManager;
41 |
42 | /**
43 | * Constructs the DisplayRotationHelper but does not register the listener yet.
44 | *
45 | * @param context the Android {@link Context}.
46 | */
47 | public DisplayRotationHelper(Context context) {
48 | displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
49 | cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
50 | WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
51 | display = windowManager.getDefaultDisplay();
52 | }
53 |
54 | /** Registers the display listener. Should be called from {@link Activity#onResume()}. */
55 | public void onResume() {
56 | displayManager.registerDisplayListener(this, null);
57 | }
58 |
59 | /** Unregisters the display listener. Should be called from {@link Activity#onPause()}. */
60 | public void onPause() {
61 | displayManager.unregisterDisplayListener(this);
62 | }
63 |
64 | /**
65 | * Records a change in surface dimensions. This will be later used by {@link
66 | * #updateSessionIfNeeded(Session)}. Should be called from {@link
67 | * android.opengl.GLSurfaceView.Renderer
68 | * #onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int)}.
69 | *
70 | * @param width the updated width of the surface.
71 | * @param height the updated height of the surface.
72 | */
73 | public void onSurfaceChanged(int width, int height) {
74 | viewportWidth = width;
75 | viewportHeight = height;
76 | viewportChanged = true;
77 | }
78 |
79 | /**
80 | * Updates the session display geometry if a change was posted either by {@link
81 | * #onSurfaceChanged(int, int)} call or by {@link #onDisplayChanged(int)} system callback. This
82 | * function should be called explicitly before each call to {@link Session#update()}. This
83 | * function will also clear the 'pending update' (viewportChanged) flag.
84 | *
85 | * @param session the {@link Session} object to update if display geometry changed.
86 | */
87 | public void updateSessionIfNeeded(Session session) {
88 | if (viewportChanged) {
89 | int displayRotation = display.getRotation();
90 | session.setDisplayGeometry(displayRotation, viewportWidth, viewportHeight);
91 | viewportChanged = false;
92 | }
93 | }
94 |
95 | /**
96 | * Returns the aspect ratio of the GL surface viewport while accounting for the display rotation
97 | * relative to the device camera sensor orientation.
98 | */
99 | public float getCameraSensorRelativeViewportAspectRatio(String cameraId) {
100 | float aspectRatio;
101 | int cameraSensorToDisplayRotation = getCameraSensorToDisplayRotation(cameraId);
102 | switch (cameraSensorToDisplayRotation) {
103 | case 90:
104 | case 270:
105 | aspectRatio = (float) viewportHeight / (float) viewportWidth;
106 | break;
107 | case 0:
108 | case 180:
109 | aspectRatio = (float) viewportWidth / (float) viewportHeight;
110 | break;
111 | default:
112 | throw new RuntimeException("Unhandled rotation: " + cameraSensorToDisplayRotation);
113 | }
114 | return aspectRatio;
115 | }
116 |
117 | /**
118 | * Returns the rotation of the back-facing camera with respect to the display. The value is one of
119 | * 0, 90, 180, 270.
120 | */
121 | public int getCameraSensorToDisplayRotation(String cameraId) {
122 | CameraCharacteristics characteristics;
123 | try {
124 | characteristics = cameraManager.getCameraCharacteristics(cameraId);
125 | } catch (CameraAccessException e) {
126 | throw new RuntimeException("Unable to determine display orientation", e);
127 | }
128 |
129 | // Camera sensor orientation.
130 | int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
131 |
132 | // Current display orientation.
133 | int displayOrientation = toDegrees(display.getRotation());
134 |
135 | // Make sure we return 0, 90, 180, or 270 degrees.
136 | return (sensorOrientation - displayOrientation + 360) % 360;
137 | }
138 |
139 | private int toDegrees(int rotation) {
140 | switch (rotation) {
141 | case Surface.ROTATION_0:
142 | return 0;
143 | case Surface.ROTATION_90:
144 | return 90;
145 | case Surface.ROTATION_180:
146 | return 180;
147 | case Surface.ROTATION_270:
148 | return 270;
149 | default:
150 | throw new RuntimeException("Unknown rotation " + rotation);
151 | }
152 | }
153 |
154 | @Override
155 | public void onDisplayAdded(int displayId) {}
156 |
157 | @Override
158 | public void onDisplayRemoved(int displayId) {}
159 |
160 | @Override
161 | public void onDisplayChanged(int displayId) {
162 | viewportChanged = true;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/part2/src/main/java/com/google/ar/core/codelab/common/helpers/FullScreenHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.view.View;
19 |
20 | /** Helper to set up the Android full screen mode. */
21 | public final class FullScreenHelper {
22 | /**
23 | * Sets the Android fullscreen flags. Expected to be called from {@link
24 | * Activity#onWindowFocusChanged(boolean hasFocus)}.
25 | *
26 | * @param activity the Activity on which the full screen mode will be set.
27 | * @param hasFocus the hasFocus flag passed from the {@link Activity#onWindowFocusChanged(boolean
28 | * hasFocus)} callback.
29 | */
30 | public static void setFullScreenOnWindowFocusChanged(Activity activity, boolean hasFocus) {
31 | if (hasFocus) {
32 | // https://developer.android.com/training/system-ui/immersive.html#sticky
33 | activity
34 | .getWindow()
35 | .getDecorView()
36 | .setSystemUiVisibility(
37 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
38 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
39 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
40 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
41 | | View.SYSTEM_UI_FLAG_FULLSCREEN
42 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/part2/src/main/java/com/google/ar/core/codelab/common/helpers/SnackbarHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.support.design.widget.BaseTransientBottomBar;
19 | import android.support.design.widget.Snackbar;
20 | import android.view.View;
21 | import android.widget.TextView;
22 |
23 | /**
24 | * Helper to manage the sample snackbar. Hides the Android boilerplate code, and exposes simpler
25 | * methods.
26 | */
27 | public final class SnackbarHelper {
28 | private static final int BACKGROUND_COLOR = 0xbf323232;
29 | private Snackbar messageSnackbar;
30 | private enum DismissBehavior { HIDE, SHOW, FINISH };
31 | private int maxLines = 2;
32 | private String lastMessage = "";
33 |
34 | public boolean isShowing() {
35 | return messageSnackbar != null;
36 | }
37 |
38 | /** Shows a snackbar with a given message. */
39 | public void showMessage(Activity activity, String message) {
40 | if (!message.isEmpty() && (!isShowing() || !lastMessage.equals(message))) {
41 | lastMessage = message;
42 | show(activity, message, DismissBehavior.HIDE);
43 | }
44 | }
45 |
46 | /** Shows a snackbar with a given message, and a dismiss button. */
47 | public void showMessageWithDismiss(Activity activity, String message) {
48 | show(activity, message, DismissBehavior.SHOW);
49 | }
50 |
51 | /**
52 | * Shows a snackbar with a given error message. When dismissed, will finish the activity. Useful
53 | * for notifying errors, where no further interaction with the activity is possible.
54 | */
55 | public void showError(Activity activity, String errorMessage) {
56 | show(activity, errorMessage, DismissBehavior.FINISH);
57 | }
58 |
59 | /**
60 | * Hides the currently showing snackbar, if there is one. Safe to call from any thread. Safe to
61 | * call even if snackbar is not shown.
62 | */
63 | public void hide(Activity activity) {
64 | if (!isShowing()) {
65 | return;
66 | }
67 | lastMessage = "";
68 | Snackbar messageSnackbarToHide = messageSnackbar;
69 | messageSnackbar = null;
70 | activity.runOnUiThread(
71 | new Runnable() {
72 | @Override
73 | public void run() {
74 | messageSnackbarToHide.dismiss();
75 | }
76 | });
77 | }
78 |
79 | public void setMaxLines(int lines) {
80 | maxLines = lines;
81 | }
82 |
83 | private void show(
84 | final Activity activity, final String message, final DismissBehavior dismissBehavior) {
85 | activity.runOnUiThread(
86 | new Runnable() {
87 | @Override
88 | public void run() {
89 | messageSnackbar =
90 | Snackbar.make(
91 | activity.findViewById(android.R.id.content),
92 | message,
93 | Snackbar.LENGTH_INDEFINITE);
94 | messageSnackbar.getView().setBackgroundColor(BACKGROUND_COLOR);
95 | if (dismissBehavior != DismissBehavior.HIDE) {
96 | messageSnackbar.setAction(
97 | "Dismiss",
98 | new View.OnClickListener() {
99 | @Override
100 | public void onClick(View v) {
101 | messageSnackbar.dismiss();
102 | }
103 | });
104 | if (dismissBehavior == DismissBehavior.FINISH) {
105 | messageSnackbar.addCallback(
106 | new BaseTransientBottomBar.BaseCallback() {
107 | @Override
108 | public void onDismissed(Snackbar transientBottomBar, int event) {
109 | super.onDismissed(transientBottomBar, event);
110 | activity.finish();
111 | }
112 | });
113 | }
114 | }
115 | ((TextView)
116 | messageSnackbar
117 | .getView()
118 | .findViewById(android.support.design.R.id.snackbar_text))
119 | .setMaxLines(maxLines);
120 | messageSnackbar.show();
121 | }
122 | });
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/part2/src/main/java/com/google/ar/core/codelab/common/helpers/TapHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.content.Context;
18 | import android.view.GestureDetector;
19 | import android.view.MotionEvent;
20 | import android.view.View;
21 | import android.view.View.OnTouchListener;
22 | import java.util.concurrent.ArrayBlockingQueue;
23 | import java.util.concurrent.BlockingQueue;
24 |
25 | /**
26 | * Helper to detect taps using Android GestureDetector, and pass the taps between UI thread and
27 | * render thread.
28 | */
29 | public final class TapHelper implements OnTouchListener {
30 | private final GestureDetector gestureDetector;
31 | private final BlockingQueue queuedSingleTaps = new ArrayBlockingQueue<>(16);
32 |
33 | /**
34 | * Creates the tap helper.
35 | *
36 | * @param context the application's context.
37 | */
38 | public TapHelper(Context context) {
39 | gestureDetector =
40 | new GestureDetector(
41 | context,
42 | new GestureDetector.SimpleOnGestureListener() {
43 | @Override
44 | public boolean onSingleTapUp(MotionEvent e) {
45 | // Queue tap if there is space. Tap is lost if queue is full.
46 | queuedSingleTaps.offer(e);
47 | return true;
48 | }
49 |
50 | @Override
51 | public boolean onDown(MotionEvent e) {
52 | return true;
53 | }
54 | });
55 | }
56 |
57 | /**
58 | * Polls for a tap.
59 | *
60 | * @return if a tap was queued, a MotionEvent for the tap. Otherwise null if no taps are queued.
61 | */
62 | public MotionEvent poll() {
63 | return queuedSingleTaps.poll();
64 | }
65 |
66 | @Override
67 | public boolean onTouch(View view, MotionEvent motionEvent) {
68 | return gestureDetector.onTouchEvent(motionEvent);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/part2/src/main/java/com/google/ar/core/codelab/common/helpers/TrackingStateHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.view.WindowManager;
19 | import com.google.ar.core.Camera;
20 | import com.google.ar.core.TrackingFailureReason;
21 | import com.google.ar.core.TrackingState;
22 |
23 | /** Gets human readibly tracking failure reasons and suggested actions. */
24 | public final class TrackingStateHelper {
25 | private static final String INSUFFICIENT_FEATURES_MESSAGE =
26 | "Can't find anything. Aim device at a surface with more texture or color.";
27 | private static final String EXCESSIVE_MOTION_MESSAGE = "Moving too fast. Slow down.";
28 | private static final String INSUFFICIENT_LIGHT_MESSAGE =
29 | "Too dark. Try moving to a well-lit area.";
30 | private static final String BAD_STATE_MESSAGE =
31 | "Tracking lost due to bad internal state. Please try restarting the AR experience.";
32 | private static final String CAMERA_UNAVAILABLE_MESSAGE =
33 | "Another app is using the camera. Tap on this app or try closing the other one.";
34 |
35 | private final Activity activity;
36 |
37 | private TrackingState previousTrackingState;
38 |
39 | public TrackingStateHelper(Activity activity) {
40 | this.activity = activity;
41 | }
42 |
43 | /** Keep the screen unlocked while tracking, but allow it to lock when tracking stops. */
44 | public void updateKeepScreenOnFlag(TrackingState trackingState) {
45 | if (trackingState == previousTrackingState) {
46 | return;
47 | }
48 |
49 | previousTrackingState = trackingState;
50 | switch (trackingState) {
51 | case PAUSED:
52 | case STOPPED:
53 | activity.runOnUiThread(
54 | () -> activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
55 | break;
56 | case TRACKING:
57 | activity.runOnUiThread(
58 | () -> activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
59 | break;
60 | }
61 | }
62 |
63 | public static String getTrackingFailureReasonString(Camera camera) {
64 | TrackingFailureReason reason = camera.getTrackingFailureReason();
65 | switch (reason) {
66 | case NONE:
67 | return "";
68 | case BAD_STATE:
69 | return BAD_STATE_MESSAGE;
70 | case INSUFFICIENT_LIGHT:
71 | return INSUFFICIENT_LIGHT_MESSAGE;
72 | case EXCESSIVE_MOTION:
73 | return EXCESSIVE_MOTION_MESSAGE;
74 | case INSUFFICIENT_FEATURES:
75 | return INSUFFICIENT_FEATURES_MESSAGE;
76 | case CAMERA_UNAVAILABLE:
77 | return CAMERA_UNAVAILABLE_MESSAGE;
78 | }
79 | return "Unknown tracking failure reason: " + reason;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/part2/src/main/java/com/google/ar/core/codelab/common/rendering/ShaderUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.rendering;
16 |
17 | import android.content.Context;
18 | import android.opengl.GLES20;
19 | import android.util.Log;
20 | import java.io.BufferedReader;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.io.InputStreamReader;
24 |
25 | /** Shader helper functions. */
26 | public class ShaderUtil {
27 | /**
28 | * Converts a raw text file, saved as a resource, into an OpenGL ES shader.
29 | *
30 | * @param type The type of shader we will be creating.
31 | * @param filename The filename of the asset file about to be turned into a shader.
32 | * @return The shader object handler.
33 | */
34 | public static int loadGLShader(String tag, Context context, int type, String filename)
35 | throws IOException {
36 | String code = readShaderFileFromAssets(context, filename);
37 | int shader = GLES20.glCreateShader(type);
38 | GLES20.glShaderSource(shader, code);
39 | GLES20.glCompileShader(shader);
40 |
41 | // Get the compilation status.
42 | final int[] compileStatus = new int[1];
43 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
44 |
45 | // If the compilation failed, delete the shader.
46 | if (compileStatus[0] == 0) {
47 | Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader));
48 | GLES20.glDeleteShader(shader);
49 | shader = 0;
50 | }
51 |
52 | if (shader == 0) {
53 | throw new RuntimeException("Error creating shader.");
54 | }
55 |
56 | return shader;
57 | }
58 |
59 | /**
60 | * Checks if we've had an error inside of OpenGL ES, and if so what that error is.
61 | *
62 | * @param label Label to report in case of error.
63 | * @throws RuntimeException If an OpenGL error is detected.
64 | */
65 | public static void checkGLError(String tag, String label) {
66 | int lastError = GLES20.GL_NO_ERROR;
67 | // Drain the queue of all errors.
68 | int error;
69 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
70 | Log.e(tag, label + ": glError " + error);
71 | lastError = error;
72 | }
73 | if (lastError != GLES20.GL_NO_ERROR) {
74 | throw new RuntimeException(label + ": glError " + lastError);
75 | }
76 | }
77 |
78 | /**
79 | * Converts a raw shader file into a string.
80 | *
81 | * @param filename The filename of the shader file about to be turned into a shader.
82 | * @return The context of the text file, or null in case of error.
83 | */
84 | private static String readShaderFileFromAssets(Context context, String filename)
85 | throws IOException {
86 | try (InputStream inputStream = context.getAssets().open(filename);
87 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
88 | StringBuilder sb = new StringBuilder();
89 | String line;
90 | while ((line = reader.readLine()) != null) {
91 | String[] tokens = line.split(" ", -1);
92 | if (tokens[0].equals("#include")) {
93 | String includeFilename = tokens[1];
94 | includeFilename = includeFilename.replace("\"", "");
95 | if (includeFilename.equals(filename)) {
96 | throw new IOException("Do not include the calling file.");
97 | }
98 | sb.append(readShaderFileFromAssets(context, includeFilename));
99 | } else {
100 | sb.append(line).append("\n");
101 | }
102 | }
103 | return sb.toString();
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/part2/src/main/java/com/google/ar/core/codelab/depth/DepthTextureHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package com.google.ar.core.codelab.depth;
16 |
17 | import static android.opengl.GLES20.GL_CLAMP_TO_EDGE;
18 | import static android.opengl.GLES20.GL_TEXTURE_2D;
19 | import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
20 | import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
21 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_S;
22 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_T;
23 | import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
24 | import static android.opengl.GLES20.glBindTexture;
25 | import static android.opengl.GLES20.glGenTextures;
26 | import static android.opengl.GLES20.glTexImage2D;
27 | import static android.opengl.GLES20.glTexParameteri;
28 | import static android.opengl.GLES30.GL_LINEAR;
29 | import static android.opengl.GLES30.GL_RG;
30 | import static android.opengl.GLES30.GL_RG8;
31 |
32 | import android.media.Image;
33 | import com.google.ar.core.Frame;
34 | import com.google.ar.core.exceptions.NotYetAvailableException;
35 |
36 | /** Handle RG8 GPU texture containing a DEPTH16 depth image. */
37 | public final class DepthTextureHandler {
38 |
39 | private int depthTextureId = -1;
40 | private int depthTextureWidth = -1;
41 | private int depthTextureHeight = -1;
42 |
43 | /**
44 | * Creates and initializes the depth texture. This method needs to be called on a
45 | * thread with a EGL context attached.
46 | */
47 | public void createOnGlThread() {
48 | int[] textureId = new int[1];
49 | glGenTextures(1, textureId, 0);
50 | depthTextureId = textureId[0];
51 | glBindTexture(GL_TEXTURE_2D, depthTextureId);
52 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
53 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
54 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
55 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
56 | }
57 |
58 | /**
59 | * Updates the depth texture with the content from acquireDepthImage().
60 | * This method needs to be called on a thread with a EGL context attached.
61 | */
62 | public void update(final Frame frame) {
63 | try {
64 | Image depthImage = frame.acquireDepthImage16Bits();
65 | depthTextureWidth = depthImage.getWidth();
66 | depthTextureHeight = depthImage.getHeight();
67 | glBindTexture(GL_TEXTURE_2D, depthTextureId);
68 | glTexImage2D(
69 | GL_TEXTURE_2D,
70 | 0,
71 | GL_RG8,
72 | depthTextureWidth,
73 | depthTextureHeight,
74 | 0,
75 | GL_RG,
76 | GL_UNSIGNED_BYTE,
77 | depthImage.getPlanes()[0].getBuffer());
78 | depthImage.close();
79 | } catch (NotYetAvailableException e) {
80 | // This normally means that depth data is not available yet.
81 | }
82 | }
83 |
84 | public int getDepthTexture() {
85 | return depthTextureId;
86 | }
87 |
88 | public int getDepthWidth() {
89 | return depthTextureWidth;
90 | }
91 |
92 | public int getDepthHeight() {
93 | return depthTextureHeight;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/part2/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part2/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/part2/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
16 |
21 |
22 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/part2/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | Depth Codelab
19 |
20 |
--------------------------------------------------------------------------------
/part2/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
22 |
29 |
30 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/part3/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | google-services.json
3 |
--------------------------------------------------------------------------------
/part3/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | def setVersionName = { ->
4 | if (project.hasProperty("androidVersionName")) {
5 | println("Replacing versionName with supplied build parameter: " +
6 | "$androidVersionName")
7 | return androidVersionName
8 | } else {
9 | return "1.0"
10 | }
11 | }
12 |
13 | android {
14 | compileSdkVersion 28
15 | defaultConfig {
16 | applicationId "com.google.ar.core.codelab.depth"
17 |
18 | // AR Optional apps must declare minSdkVersion >= 14.
19 | // AR Required apps must declare minSdkVersion >= 24.
20 | minSdkVersion 24
21 | targetSdkVersion 28
22 | versionCode 1
23 | versionName setVersionName()
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | buildTypes {
30 | release {
31 | minifyEnabled false
32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
33 | }
34 | }
35 | }
36 |
37 | dependencies {
38 | // ARCore library
39 | // Dependency version is rewritten at build time.
40 | implementation 'com.google.ar:core:1.31.0'
41 |
42 | // Obj - a simple Wavefront OBJ file loader
43 | // https://github.com/javagl/Obj
44 | implementation 'de.javagl:obj:0.2.1'
45 |
46 | implementation 'com.android.support:appcompat-v7:28.0.0'
47 | implementation 'com.android.support:design:28.0.0'
48 | }
49 |
--------------------------------------------------------------------------------
/part3/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/part3/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
34 |
35 |
41 |
42 |
43 |
44 |
45 |
46 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/part3/src/main/assets/models/andy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part3/src/main/assets/models/andy.png
--------------------------------------------------------------------------------
/part3/src/main/assets/models/andy_spec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part3/src/main/assets/models/andy_spec.png
--------------------------------------------------------------------------------
/part3/src/main/assets/shaders/background_show_depth_map.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | precision mediump float;
17 | uniform sampler2D u_Depth;
18 | varying vec2 v_TexCoord;
19 | const highp float kMaxDepth = 20000.0; // In millimeters.
20 |
21 | uniform float u_DepthRangeToRenderMm;
22 | const float kDepthWidthToRenderMm = 350.0;
23 |
24 | float GetDepthMillimeters(vec4 depth_pixel_value) {
25 | return 255.0 * (depth_pixel_value.r + depth_pixel_value.g * 256.0);
26 | }
27 |
28 | // Returns an interpolated color in a 6 degree polynomial interpolation.
29 | vec3 GetPolynomialColor(in float x,
30 | in vec4 kRedVec4, in vec4 kGreenVec4, in vec4 kBlueVec4,
31 | in vec2 kRedVec2, in vec2 kGreenVec2, in vec2 kBlueVec2) {
32 | // Moves the color space a little bit to avoid pure red.
33 | // Removes this line for more contrast.
34 | x = clamp(x * 0.9 + 0.03, 0.0, 1.0);
35 | vec4 v4 = vec4(1.0, x, x * x, x * x * x);
36 | vec2 v2 = v4.zw * v4.z;
37 | return vec3(
38 | dot(v4, kRedVec4) + dot(v2, kRedVec2),
39 | dot(v4, kGreenVec4) + dot(v2, kGreenVec2),
40 | dot(v4, kBlueVec4) + dot(v2, kBlueVec2)
41 | );
42 | }
43 |
44 | // Returns a smooth Percept colormap based upon the Turbo colormap:
45 | // https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html
46 | vec3 PerceptColormap(in float x) {
47 | const vec4 kRedVec4 = vec4(0.55305649, 3.00913185, -5.46192616, -11.11819092);
48 | const vec4 kGreenVec4 = vec4(0.16207513, 0.17712472, 15.24091500, -36.50657960);
49 | const vec4 kBlueVec4 = vec4(-0.05195877, 5.18000081, -30.94853351, 81.96403246);
50 | const vec2 kRedVec2 = vec2(27.81927491, -14.87899417);
51 | const vec2 kGreenVec2 = vec2(25.95549545, -5.02738237);
52 | const vec2 kBlueVec2 = vec2(-86.53476570, 30.23299484);
53 | const float kInvalidDepthThreshold = 0.01;
54 | return step(kInvalidDepthThreshold, x) *
55 | GetPolynomialColor(x, kRedVec4, kGreenVec4, kBlueVec4,
56 | kRedVec2, kGreenVec2, kBlueVec2);
57 | }
58 |
59 | void main() {
60 | vec4 packed_depth = texture2D(u_Depth, v_TexCoord.xy);
61 | highp float depth_mm = GetDepthMillimeters(packed_depth);
62 | highp float normalized_depth = depth_mm / kMaxDepth;
63 | vec4 depth_color = vec4(PerceptColormap(normalized_depth), 1.0);
64 | gl_FragColor = depth_color;
65 | gl_FragColor.a = clamp(1.0 - abs((depth_mm - u_DepthRangeToRenderMm) / kDepthWidthToRenderMm), 0.0, 1.0);
66 | }
67 |
--------------------------------------------------------------------------------
/part3/src/main/assets/shaders/background_show_depth_map.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | attribute vec4 a_Position;
17 | attribute vec2 a_TexCoord;
18 |
19 | varying vec2 v_TexCoord;
20 |
21 | void main() {
22 | gl_Position = a_Position;
23 | v_TexCoord = a_TexCoord;
24 | }
--------------------------------------------------------------------------------
/part3/src/main/assets/shaders/object.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | precision mediump float;
17 |
18 | uniform sampler2D u_Texture;
19 |
20 | uniform vec4 u_LightingParameters;
21 | uniform vec4 u_MaterialParameters;
22 | uniform vec4 u_ColorCorrectionParameters;
23 |
24 | varying vec3 v_ViewPosition;
25 | varying vec3 v_ViewNormal;
26 | varying vec2 v_TexCoord;
27 | uniform vec4 u_ObjColor;
28 |
29 | void main() {
30 | // We support approximate sRGB gamma.
31 | const float kGamma = 0.4545454;
32 | const float kInverseGamma = 2.2;
33 | const float kMiddleGrayGamma = 0.466;
34 |
35 | // Unpack lighting and material parameters for better naming.
36 | vec3 viewLightDirection = u_LightingParameters.xyz;
37 | vec3 colorShift = u_ColorCorrectionParameters.rgb;
38 | float averagePixelIntensity = u_ColorCorrectionParameters.a;
39 |
40 | float materialAmbient = u_MaterialParameters.x;
41 | float materialDiffuse = u_MaterialParameters.y;
42 | float materialSpecular = u_MaterialParameters.z;
43 | float materialSpecularPower = u_MaterialParameters.w;
44 |
45 | // Normalize varying parameters, because they are linearly interpolated in the vertex shader.
46 | vec3 viewFragmentDirection = normalize(v_ViewPosition);
47 | vec3 viewNormal = normalize(v_ViewNormal);
48 |
49 | // Flip the y-texture coordinate to address the texture from top-left.
50 | vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y));
51 |
52 | // Apply color to grayscale image only if the alpha of u_ObjColor is
53 | // greater and equal to 255.0.
54 | if (u_ObjColor.a >= 255.0) {
55 | float intensity = objectColor.r;
56 | objectColor.rgb = u_ObjColor.rgb * intensity / 255.0;
57 | }
58 |
59 | // Apply inverse SRGB gamma to the texture before making lighting calculations.
60 | objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma));
61 |
62 | // Ambient light is unaffected by the light intensity.
63 | float ambient = materialAmbient;
64 |
65 | // Approximate a hemisphere light (not a harsh directional light).
66 | float diffuse = materialDiffuse *
67 | 0.5 * (dot(viewNormal, viewLightDirection) + 1.0);
68 |
69 | // Compute specular light.
70 | vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal);
71 | float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection));
72 | float specular = materialSpecular *
73 | pow(specularStrength, materialSpecularPower);
74 |
75 | vec3 color = objectColor.rgb * (ambient + diffuse) + specular;
76 | // Apply SRGB gamma before writing the fragment color.
77 | color.rgb = pow(color, vec3(kGamma));
78 | // Apply average pixel intensity and color shift
79 | color *= colorShift * (averagePixelIntensity / kMiddleGrayGamma);
80 | gl_FragColor.rgb = color;
81 | gl_FragColor.a = objectColor.a;
82 | }
83 |
--------------------------------------------------------------------------------
/part3/src/main/assets/shaders/object.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | uniform mat4 u_ModelView;
17 | uniform mat4 u_ModelViewProjection;
18 |
19 | attribute vec4 a_Position;
20 | attribute vec3 a_Normal;
21 | attribute vec2 a_TexCoord;
22 |
23 | varying vec3 v_ViewPosition;
24 | varying vec3 v_ViewNormal;
25 | varying vec2 v_TexCoord;
26 |
27 | void main() {
28 | v_ViewPosition = (u_ModelView * a_Position).xyz;
29 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz);
30 | v_TexCoord = a_TexCoord;
31 | gl_Position = u_ModelViewProjection * a_Position;
32 | }
33 |
--------------------------------------------------------------------------------
/part3/src/main/assets/shaders/screenquad.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | #extension GL_OES_EGL_image_external : require
16 |
17 | precision mediump float;
18 | varying vec2 v_TexCoord;
19 | uniform samplerExternalOES sTexture;
20 |
21 |
22 | void main() {
23 | gl_FragColor = texture2D(sTexture, v_TexCoord);
24 | }
25 |
--------------------------------------------------------------------------------
/part3/src/main/assets/shaders/screenquad.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | attribute vec4 a_Position;
17 | attribute vec2 a_TexCoord;
18 |
19 | varying vec2 v_TexCoord;
20 |
21 | void main() {
22 | gl_Position = a_Position;
23 | v_TexCoord = a_TexCoord;
24 | }
25 |
--------------------------------------------------------------------------------
/part3/src/main/java/com/google/ar/core/codelab/common/helpers/CameraPermissionHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.Manifest;
18 | import android.app.Activity;
19 | import android.content.Intent;
20 | import android.content.pm.PackageManager;
21 | import android.net.Uri;
22 | import android.provider.Settings;
23 | import android.support.v4.app.ActivityCompat;
24 | import android.support.v4.content.ContextCompat;
25 |
26 | /** Helper to ask camera permission. */
27 | public final class CameraPermissionHelper {
28 | private static final int CAMERA_PERMISSION_CODE = 0;
29 | private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA;
30 |
31 | /** Check to see we have the necessary permissions for this app. */
32 | public static boolean hasCameraPermission(Activity activity) {
33 | return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION)
34 | == PackageManager.PERMISSION_GRANTED;
35 | }
36 |
37 | /** Check to see we have the necessary permissions for this app, and ask for them if we don't. */
38 | public static void requestCameraPermission(Activity activity) {
39 | ActivityCompat.requestPermissions(
40 | activity, new String[] {CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE);
41 | }
42 |
43 | /** Check to see if we need to show the rationale for this permission. */
44 | public static boolean shouldShowRequestPermissionRationale(Activity activity) {
45 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION);
46 | }
47 |
48 | /** Launch Application Setting to grant permission. */
49 | public static void launchPermissionSettings(Activity activity) {
50 | Intent intent = new Intent();
51 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
52 | intent.setData(Uri.fromParts("package", activity.getPackageName(), null));
53 | activity.startActivity(intent);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/part3/src/main/java/com/google/ar/core/codelab/common/helpers/FullScreenHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.view.View;
19 |
20 | /** Helper to set up the Android full screen mode. */
21 | public final class FullScreenHelper {
22 | /**
23 | * Sets the Android fullscreen flags. Expected to be called from {@link
24 | * Activity#onWindowFocusChanged(boolean hasFocus)}.
25 | *
26 | * @param activity the Activity on which the full screen mode will be set.
27 | * @param hasFocus the hasFocus flag passed from the {@link Activity#onWindowFocusChanged(boolean
28 | * hasFocus)} callback.
29 | */
30 | public static void setFullScreenOnWindowFocusChanged(Activity activity, boolean hasFocus) {
31 | if (hasFocus) {
32 | // https://developer.android.com/training/system-ui/immersive.html#sticky
33 | activity
34 | .getWindow()
35 | .getDecorView()
36 | .setSystemUiVisibility(
37 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
38 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
39 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
40 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
41 | | View.SYSTEM_UI_FLAG_FULLSCREEN
42 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/part3/src/main/java/com/google/ar/core/codelab/common/helpers/SnackbarHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.support.design.widget.BaseTransientBottomBar;
19 | import android.support.design.widget.Snackbar;
20 | import android.view.View;
21 | import android.widget.TextView;
22 |
23 | /**
24 | * Helper to manage the sample snackbar. Hides the Android boilerplate code, and exposes simpler
25 | * methods.
26 | */
27 | public final class SnackbarHelper {
28 | private static final int BACKGROUND_COLOR = 0xbf323232;
29 | private Snackbar messageSnackbar;
30 | private enum DismissBehavior { HIDE, SHOW, FINISH };
31 | private int maxLines = 2;
32 | private String lastMessage = "";
33 |
34 | public boolean isShowing() {
35 | return messageSnackbar != null;
36 | }
37 |
38 | /** Shows a snackbar with a given message. */
39 | public void showMessage(Activity activity, String message) {
40 | if (!message.isEmpty() && (!isShowing() || !lastMessage.equals(message))) {
41 | lastMessage = message;
42 | show(activity, message, DismissBehavior.HIDE);
43 | }
44 | }
45 |
46 | /** Shows a snackbar with a given message, and a dismiss button. */
47 | public void showMessageWithDismiss(Activity activity, String message) {
48 | show(activity, message, DismissBehavior.SHOW);
49 | }
50 |
51 | /**
52 | * Shows a snackbar with a given error message. When dismissed, will finish the activity. Useful
53 | * for notifying errors, where no further interaction with the activity is possible.
54 | */
55 | public void showError(Activity activity, String errorMessage) {
56 | show(activity, errorMessage, DismissBehavior.FINISH);
57 | }
58 |
59 | /**
60 | * Hides the currently showing snackbar, if there is one. Safe to call from any thread. Safe to
61 | * call even if snackbar is not shown.
62 | */
63 | public void hide(Activity activity) {
64 | if (!isShowing()) {
65 | return;
66 | }
67 | lastMessage = "";
68 | Snackbar messageSnackbarToHide = messageSnackbar;
69 | messageSnackbar = null;
70 | activity.runOnUiThread(
71 | new Runnable() {
72 | @Override
73 | public void run() {
74 | messageSnackbarToHide.dismiss();
75 | }
76 | });
77 | }
78 |
79 | public void setMaxLines(int lines) {
80 | maxLines = lines;
81 | }
82 |
83 | private void show(
84 | final Activity activity, final String message, final DismissBehavior dismissBehavior) {
85 | activity.runOnUiThread(
86 | new Runnable() {
87 | @Override
88 | public void run() {
89 | messageSnackbar =
90 | Snackbar.make(
91 | activity.findViewById(android.R.id.content),
92 | message,
93 | Snackbar.LENGTH_INDEFINITE);
94 | messageSnackbar.getView().setBackgroundColor(BACKGROUND_COLOR);
95 | if (dismissBehavior != DismissBehavior.HIDE) {
96 | messageSnackbar.setAction(
97 | "Dismiss",
98 | new View.OnClickListener() {
99 | @Override
100 | public void onClick(View v) {
101 | messageSnackbar.dismiss();
102 | }
103 | });
104 | if (dismissBehavior == DismissBehavior.FINISH) {
105 | messageSnackbar.addCallback(
106 | new BaseTransientBottomBar.BaseCallback() {
107 | @Override
108 | public void onDismissed(Snackbar transientBottomBar, int event) {
109 | super.onDismissed(transientBottomBar, event);
110 | activity.finish();
111 | }
112 | });
113 | }
114 | }
115 | ((TextView)
116 | messageSnackbar
117 | .getView()
118 | .findViewById(android.support.design.R.id.snackbar_text))
119 | .setMaxLines(maxLines);
120 | messageSnackbar.show();
121 | }
122 | });
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/part3/src/main/java/com/google/ar/core/codelab/common/helpers/TapHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.content.Context;
18 | import android.view.GestureDetector;
19 | import android.view.MotionEvent;
20 | import android.view.View;
21 | import android.view.View.OnTouchListener;
22 | import java.util.concurrent.ArrayBlockingQueue;
23 | import java.util.concurrent.BlockingQueue;
24 |
25 | /**
26 | * Helper to detect taps using Android GestureDetector, and pass the taps between UI thread and
27 | * render thread.
28 | */
29 | public final class TapHelper implements OnTouchListener {
30 | private final GestureDetector gestureDetector;
31 | private final BlockingQueue queuedSingleTaps = new ArrayBlockingQueue<>(16);
32 |
33 | /**
34 | * Creates the tap helper.
35 | *
36 | * @param context the application's context.
37 | */
38 | public TapHelper(Context context) {
39 | gestureDetector =
40 | new GestureDetector(
41 | context,
42 | new GestureDetector.SimpleOnGestureListener() {
43 | @Override
44 | public boolean onSingleTapUp(MotionEvent e) {
45 | // Queue tap if there is space. Tap is lost if queue is full.
46 | queuedSingleTaps.offer(e);
47 | return true;
48 | }
49 |
50 | @Override
51 | public boolean onDown(MotionEvent e) {
52 | return true;
53 | }
54 | });
55 | }
56 |
57 | /**
58 | * Polls for a tap.
59 | *
60 | * @return if a tap was queued, a MotionEvent for the tap. Otherwise null if no taps are queued.
61 | */
62 | public MotionEvent poll() {
63 | return queuedSingleTaps.poll();
64 | }
65 |
66 | @Override
67 | public boolean onTouch(View view, MotionEvent motionEvent) {
68 | return gestureDetector.onTouchEvent(motionEvent);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/part3/src/main/java/com/google/ar/core/codelab/common/helpers/TrackingStateHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.view.WindowManager;
19 | import com.google.ar.core.Camera;
20 | import com.google.ar.core.TrackingFailureReason;
21 | import com.google.ar.core.TrackingState;
22 |
23 | /** Gets human readibly tracking failure reasons and suggested actions. */
24 | public final class TrackingStateHelper {
25 | private static final String INSUFFICIENT_FEATURES_MESSAGE =
26 | "Can't find anything. Aim device at a surface with more texture or color.";
27 | private static final String EXCESSIVE_MOTION_MESSAGE = "Moving too fast. Slow down.";
28 | private static final String INSUFFICIENT_LIGHT_MESSAGE =
29 | "Too dark. Try moving to a well-lit area.";
30 | private static final String BAD_STATE_MESSAGE =
31 | "Tracking lost due to bad internal state. Please try restarting the AR experience.";
32 | private static final String CAMERA_UNAVAILABLE_MESSAGE =
33 | "Another app is using the camera. Tap on this app or try closing the other one.";
34 |
35 | private final Activity activity;
36 |
37 | private TrackingState previousTrackingState;
38 |
39 | public TrackingStateHelper(Activity activity) {
40 | this.activity = activity;
41 | }
42 |
43 | /** Keep the screen unlocked while tracking, but allow it to lock when tracking stops. */
44 | public void updateKeepScreenOnFlag(TrackingState trackingState) {
45 | if (trackingState == previousTrackingState) {
46 | return;
47 | }
48 |
49 | previousTrackingState = trackingState;
50 | switch (trackingState) {
51 | case PAUSED:
52 | case STOPPED:
53 | activity.runOnUiThread(
54 | () -> activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
55 | break;
56 | case TRACKING:
57 | activity.runOnUiThread(
58 | () -> activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
59 | break;
60 | }
61 | }
62 |
63 | public static String getTrackingFailureReasonString(Camera camera) {
64 | TrackingFailureReason reason = camera.getTrackingFailureReason();
65 | switch (reason) {
66 | case NONE:
67 | return "";
68 | case BAD_STATE:
69 | return BAD_STATE_MESSAGE;
70 | case INSUFFICIENT_LIGHT:
71 | return INSUFFICIENT_LIGHT_MESSAGE;
72 | case EXCESSIVE_MOTION:
73 | return EXCESSIVE_MOTION_MESSAGE;
74 | case INSUFFICIENT_FEATURES:
75 | return INSUFFICIENT_FEATURES_MESSAGE;
76 | case CAMERA_UNAVAILABLE:
77 | return CAMERA_UNAVAILABLE_MESSAGE;
78 | }
79 | return "Unknown tracking failure reason: " + reason;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/part3/src/main/java/com/google/ar/core/codelab/common/rendering/ShaderUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.rendering;
16 |
17 | import android.content.Context;
18 | import android.opengl.GLES20;
19 | import android.util.Log;
20 | import java.io.BufferedReader;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.io.InputStreamReader;
24 |
25 | /** Shader helper functions. */
26 | public class ShaderUtil {
27 | /**
28 | * Converts a raw text file, saved as a resource, into an OpenGL ES shader.
29 | *
30 | * @param type The type of shader we will be creating.
31 | * @param filename The filename of the asset file about to be turned into a shader.
32 | * @return The shader object handler.
33 | */
34 | public static int loadGLShader(String tag, Context context, int type, String filename)
35 | throws IOException {
36 | String code = readShaderFileFromAssets(context, filename);
37 | int shader = GLES20.glCreateShader(type);
38 | GLES20.glShaderSource(shader, code);
39 | GLES20.glCompileShader(shader);
40 |
41 | // Get the compilation status.
42 | final int[] compileStatus = new int[1];
43 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
44 |
45 | // If the compilation failed, delete the shader.
46 | if (compileStatus[0] == 0) {
47 | Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader));
48 | GLES20.glDeleteShader(shader);
49 | shader = 0;
50 | }
51 |
52 | if (shader == 0) {
53 | throw new RuntimeException("Error creating shader.");
54 | }
55 |
56 | return shader;
57 | }
58 |
59 | /**
60 | * Checks if we've had an error inside of OpenGL ES, and if so what that error is.
61 | *
62 | * @param label Label to report in case of error.
63 | * @throws RuntimeException If an OpenGL error is detected.
64 | */
65 | public static void checkGLError(String tag, String label) {
66 | int lastError = GLES20.GL_NO_ERROR;
67 | // Drain the queue of all errors.
68 | int error;
69 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
70 | Log.e(tag, label + ": glError " + error);
71 | lastError = error;
72 | }
73 | if (lastError != GLES20.GL_NO_ERROR) {
74 | throw new RuntimeException(label + ": glError " + lastError);
75 | }
76 | }
77 |
78 | /**
79 | * Converts a raw shader file into a string.
80 | *
81 | * @param filename The filename of the shader file about to be turned into a shader.
82 | * @return The context of the text file, or null in case of error.
83 | */
84 | private static String readShaderFileFromAssets(Context context, String filename)
85 | throws IOException {
86 | try (InputStream inputStream = context.getAssets().open(filename);
87 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
88 | StringBuilder sb = new StringBuilder();
89 | String line;
90 | while ((line = reader.readLine()) != null) {
91 | String[] tokens = line.split(" ", -1);
92 | if (tokens[0].equals("#include")) {
93 | String includeFilename = tokens[1];
94 | includeFilename = includeFilename.replace("\"", "");
95 | if (includeFilename.equals(filename)) {
96 | throw new IOException("Do not include the calling file.");
97 | }
98 | sb.append(readShaderFileFromAssets(context, includeFilename));
99 | } else {
100 | sb.append(line).append("\n");
101 | }
102 | }
103 | return sb.toString();
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/part3/src/main/java/com/google/ar/core/codelab/depth/DepthTextureHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package com.google.ar.core.codelab.depth;
16 |
17 | import static android.opengl.GLES20.GL_CLAMP_TO_EDGE;
18 | import static android.opengl.GLES20.GL_TEXTURE_2D;
19 | import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
20 | import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
21 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_S;
22 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_T;
23 | import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
24 | import static android.opengl.GLES20.glBindTexture;
25 | import static android.opengl.GLES20.glGenTextures;
26 | import static android.opengl.GLES20.glTexImage2D;
27 | import static android.opengl.GLES20.glTexParameteri;
28 | import static android.opengl.GLES30.GL_LINEAR;
29 | import static android.opengl.GLES30.GL_RG;
30 | import static android.opengl.GLES30.GL_RG8;
31 |
32 | import android.media.Image;
33 | import com.google.ar.core.Frame;
34 | import com.google.ar.core.exceptions.NotYetAvailableException;
35 |
36 | /** Handle RG8 GPU texture containing a DEPTH16 depth image. */
37 | public final class DepthTextureHandler {
38 |
39 | private int depthTextureId = -1;
40 | private int depthTextureWidth = -1;
41 | private int depthTextureHeight = -1;
42 |
43 | /**
44 | * Creates and initializes the depth texture. This method needs to be called on a
45 | * thread with a EGL context attached.
46 | */
47 | public void createOnGlThread() {
48 | int[] textureId = new int[1];
49 | glGenTextures(1, textureId, 0);
50 | depthTextureId = textureId[0];
51 | glBindTexture(GL_TEXTURE_2D, depthTextureId);
52 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
53 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
54 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
55 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
56 | }
57 |
58 | /**
59 | * Updates the depth texture with the content from acquireDepthImage().
60 | * This method needs to be called on a thread with a EGL context attached.
61 | */
62 | public void update(final Frame frame) {
63 | try {
64 | Image depthImage = frame.acquireDepthImage16Bits();
65 | depthTextureWidth = depthImage.getWidth();
66 | depthTextureHeight = depthImage.getHeight();
67 | glBindTexture(GL_TEXTURE_2D, depthTextureId);
68 | glTexImage2D(
69 | GL_TEXTURE_2D,
70 | 0,
71 | GL_RG8,
72 | depthTextureWidth,
73 | depthTextureHeight,
74 | 0,
75 | GL_RG,
76 | GL_UNSIGNED_BYTE,
77 | depthImage.getPlanes()[0].getBuffer());
78 | depthImage.close();
79 | } catch (NotYetAvailableException e) {
80 | // This normally means that depth data is not available yet.
81 | }
82 | }
83 |
84 | public int getDepthTexture() {
85 | return depthTextureId;
86 | }
87 |
88 | public int getDepthWidth() {
89 | return depthTextureWidth;
90 | }
91 |
92 | public int getDepthHeight() {
93 | return depthTextureHeight;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/part3/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part3/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/part3/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
16 |
21 |
22 |
27 |
28 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/part3/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | Depth Codelab
19 | Show Depth
20 | Hide Depth
21 | Depth Not Available
22 |
23 |
--------------------------------------------------------------------------------
/part3/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
22 |
29 |
30 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/part4_completed/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | google-services.json
3 |
--------------------------------------------------------------------------------
/part4_completed/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | def setVersionName = { ->
4 | if (project.hasProperty("androidVersionName")) {
5 | println("Replacing versionName with supplied build parameter: " +
6 | "$androidVersionName")
7 | return androidVersionName
8 | } else {
9 | return "1.0"
10 | }
11 | }
12 |
13 | android {
14 | compileSdkVersion 28
15 | defaultConfig {
16 | applicationId "com.google.ar.core.codelab.depth"
17 |
18 | // AR Optional apps must declare minSdkVersion >= 14.
19 | // AR Required apps must declare minSdkVersion >= 24.
20 | minSdkVersion 24
21 | targetSdkVersion 28
22 | versionCode 1
23 | versionName setVersionName()
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | buildTypes {
30 | release {
31 | minifyEnabled false
32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
33 | }
34 | }
35 | }
36 |
37 | dependencies {
38 | // ARCore library
39 | // Dependency version is rewritten at build time.
40 | implementation 'com.google.ar:core:1.31.0'
41 |
42 | // Obj - a simple Wavefront OBJ file loader
43 | // https://github.com/javagl/Obj
44 | implementation 'de.javagl:obj:0.2.1'
45 |
46 | implementation 'com.android.support:appcompat-v7:28.0.0'
47 | implementation 'com.android.support:design:28.0.0'
48 | }
49 |
--------------------------------------------------------------------------------
/part4_completed/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/part4_completed/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
34 |
35 |
41 |
42 |
43 |
44 |
45 |
46 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/part4_completed/src/main/assets/models/andy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part4_completed/src/main/assets/models/andy.png
--------------------------------------------------------------------------------
/part4_completed/src/main/assets/models/andy_spec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part4_completed/src/main/assets/models/andy_spec.png
--------------------------------------------------------------------------------
/part4_completed/src/main/assets/shaders/background_show_depth_map.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | precision mediump float;
17 | uniform sampler2D u_Depth;
18 | varying vec2 v_TexCoord;
19 | const highp float kMaxDepth = 20000.0; // In millimeters.
20 |
21 | uniform float u_DepthRangeToRenderMm;
22 | const float kDepthWidthToRenderMm = 350.0;
23 |
24 | float GetDepthMillimeters(vec4 depth_pixel_value) {
25 | return 255.0 * (depth_pixel_value.r + depth_pixel_value.g * 256.0);
26 | }
27 |
28 | // Returns an interpolated color in a 6 degree polynomial interpolation.
29 | vec3 GetPolynomialColor(in float x,
30 | in vec4 kRedVec4, in vec4 kGreenVec4, in vec4 kBlueVec4,
31 | in vec2 kRedVec2, in vec2 kGreenVec2, in vec2 kBlueVec2) {
32 | // Moves the color space a little bit to avoid pure red.
33 | // Removes this line for more contrast.
34 | x = clamp(x * 0.9 + 0.03, 0.0, 1.0);
35 | vec4 v4 = vec4(1.0, x, x * x, x * x * x);
36 | vec2 v2 = v4.zw * v4.z;
37 | return vec3(
38 | dot(v4, kRedVec4) + dot(v2, kRedVec2),
39 | dot(v4, kGreenVec4) + dot(v2, kGreenVec2),
40 | dot(v4, kBlueVec4) + dot(v2, kBlueVec2)
41 | );
42 | }
43 |
44 | // Returns a smooth Percept colormap based upon the Turbo colormap:
45 | // https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html
46 | vec3 PerceptColormap(in float x) {
47 | const vec4 kRedVec4 = vec4(0.55305649, 3.00913185, -5.46192616, -11.11819092);
48 | const vec4 kGreenVec4 = vec4(0.16207513, 0.17712472, 15.24091500, -36.50657960);
49 | const vec4 kBlueVec4 = vec4(-0.05195877, 5.18000081, -30.94853351, 81.96403246);
50 | const vec2 kRedVec2 = vec2(27.81927491, -14.87899417);
51 | const vec2 kGreenVec2 = vec2(25.95549545, -5.02738237);
52 | const vec2 kBlueVec2 = vec2(-86.53476570, 30.23299484);
53 | const float kInvalidDepthThreshold = 0.01;
54 | return step(kInvalidDepthThreshold, x) *
55 | GetPolynomialColor(x, kRedVec4, kGreenVec4, kBlueVec4,
56 | kRedVec2, kGreenVec2, kBlueVec2);
57 | }
58 |
59 | void main() {
60 | vec4 packed_depth = texture2D(u_Depth, v_TexCoord.xy);
61 | highp float depth_mm = GetDepthMillimeters(packed_depth);
62 | highp float normalized_depth = depth_mm / kMaxDepth;
63 | vec4 depth_color = vec4(PerceptColormap(normalized_depth), 1.0);
64 | gl_FragColor = depth_color;
65 | gl_FragColor.a = clamp(1.0 - abs((depth_mm - u_DepthRangeToRenderMm) / kDepthWidthToRenderMm), 0.0, 1.0);
66 | }
67 |
--------------------------------------------------------------------------------
/part4_completed/src/main/assets/shaders/background_show_depth_map.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | attribute vec4 a_Position;
17 | attribute vec2 a_TexCoord;
18 |
19 | varying vec2 v_TexCoord;
20 |
21 | void main() {
22 | gl_Position = a_Position;
23 | v_TexCoord = a_TexCoord;
24 | }
--------------------------------------------------------------------------------
/part4_completed/src/main/assets/shaders/object.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | precision mediump float;
17 |
18 | uniform sampler2D u_Texture;
19 |
20 | uniform vec4 u_LightingParameters;
21 | uniform vec4 u_MaterialParameters;
22 | uniform vec4 u_ColorCorrectionParameters;
23 |
24 | varying vec3 v_ViewPosition;
25 | varying vec3 v_ViewNormal;
26 | varying vec2 v_TexCoord;
27 | uniform vec4 u_ObjColor;
28 |
29 | void main() {
30 | // We support approximate sRGB gamma.
31 | const float kGamma = 0.4545454;
32 | const float kInverseGamma = 2.2;
33 | const float kMiddleGrayGamma = 0.466;
34 |
35 | // Unpack lighting and material parameters for better naming.
36 | vec3 viewLightDirection = u_LightingParameters.xyz;
37 | vec3 colorShift = u_ColorCorrectionParameters.rgb;
38 | float averagePixelIntensity = u_ColorCorrectionParameters.a;
39 |
40 | float materialAmbient = u_MaterialParameters.x;
41 | float materialDiffuse = u_MaterialParameters.y;
42 | float materialSpecular = u_MaterialParameters.z;
43 | float materialSpecularPower = u_MaterialParameters.w;
44 |
45 | // Normalize varying parameters, because they are linearly interpolated in the vertex shader.
46 | vec3 viewFragmentDirection = normalize(v_ViewPosition);
47 | vec3 viewNormal = normalize(v_ViewNormal);
48 |
49 | // Flip the y-texture coordinate to address the texture from top-left.
50 | vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y));
51 |
52 | // Apply color to grayscale image only if the alpha of u_ObjColor is
53 | // greater and equal to 255.0.
54 | if (u_ObjColor.a >= 255.0) {
55 | float intensity = objectColor.r;
56 | objectColor.rgb = u_ObjColor.rgb * intensity / 255.0;
57 | }
58 |
59 | // Apply inverse SRGB gamma to the texture before making lighting calculations.
60 | objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma));
61 |
62 | // Ambient light is unaffected by the light intensity.
63 | float ambient = materialAmbient;
64 |
65 | // Approximate a hemisphere light (not a harsh directional light).
66 | float diffuse = materialDiffuse *
67 | 0.5 * (dot(viewNormal, viewLightDirection) + 1.0);
68 |
69 | // Compute specular light.
70 | vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal);
71 | float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection));
72 | float specular = materialSpecular *
73 | pow(specularStrength, materialSpecularPower);
74 |
75 | vec3 color = objectColor.rgb * (ambient + diffuse) + specular;
76 | // Apply SRGB gamma before writing the fragment color.
77 | color.rgb = pow(color, vec3(kGamma));
78 | // Apply average pixel intensity and color shift
79 | color *= colorShift * (averagePixelIntensity / kMiddleGrayGamma);
80 | gl_FragColor.rgb = color;
81 | gl_FragColor.a = objectColor.a;
82 | }
83 |
--------------------------------------------------------------------------------
/part4_completed/src/main/assets/shaders/object.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | uniform mat4 u_ModelView;
17 | uniform mat4 u_ModelViewProjection;
18 |
19 | attribute vec4 a_Position;
20 | attribute vec3 a_Normal;
21 | attribute vec2 a_TexCoord;
22 |
23 | varying vec3 v_ViewPosition;
24 | varying vec3 v_ViewNormal;
25 | varying vec2 v_TexCoord;
26 |
27 | void main() {
28 | v_ViewPosition = (u_ModelView * a_Position).xyz;
29 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz);
30 | v_TexCoord = a_TexCoord;
31 | gl_Position = u_ModelViewProjection * a_Position;
32 | }
33 |
--------------------------------------------------------------------------------
/part4_completed/src/main/assets/shaders/occlusion_object.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | uniform mat4 u_ModelView;
17 | uniform mat4 u_ModelViewProjection;
18 |
19 | attribute vec4 a_Position;
20 | attribute vec3 a_Normal;
21 | attribute vec2 a_TexCoord;
22 |
23 | varying vec3 v_ViewPosition;
24 | varying vec3 v_ViewNormal;
25 | varying vec2 v_TexCoord;
26 | varying vec3 v_ScreenSpacePosition;
27 |
28 | void main() {
29 | v_ViewPosition = (u_ModelView * a_Position).xyz;
30 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz);
31 | v_TexCoord = a_TexCoord;
32 | gl_Position = u_ModelViewProjection * a_Position;
33 | v_ScreenSpacePosition = gl_Position.xyz / gl_Position.w;
34 | }
--------------------------------------------------------------------------------
/part4_completed/src/main/assets/shaders/screenquad.frag:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | #extension GL_OES_EGL_image_external : require
16 |
17 | precision mediump float;
18 | varying vec2 v_TexCoord;
19 | uniform samplerExternalOES sTexture;
20 |
21 |
22 | void main() {
23 | gl_FragColor = texture2D(sTexture, v_TexCoord);
24 | }
25 |
--------------------------------------------------------------------------------
/part4_completed/src/main/assets/shaders/screenquad.vert:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | attribute vec4 a_Position;
17 | attribute vec2 a_TexCoord;
18 |
19 | varying vec2 v_TexCoord;
20 |
21 | void main() {
22 | gl_Position = a_Position;
23 | v_TexCoord = a_TexCoord;
24 | }
25 |
--------------------------------------------------------------------------------
/part4_completed/src/main/java/com/google/ar/core/codelab/common/helpers/CameraPermissionHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.Manifest;
18 | import android.app.Activity;
19 | import android.content.Intent;
20 | import android.content.pm.PackageManager;
21 | import android.net.Uri;
22 | import android.provider.Settings;
23 | import android.support.v4.app.ActivityCompat;
24 | import android.support.v4.content.ContextCompat;
25 |
26 | /** Helper to ask camera permission. */
27 | public final class CameraPermissionHelper {
28 | private static final int CAMERA_PERMISSION_CODE = 0;
29 | private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA;
30 |
31 | /** Check to see we have the necessary permissions for this app. */
32 | public static boolean hasCameraPermission(Activity activity) {
33 | return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION)
34 | == PackageManager.PERMISSION_GRANTED;
35 | }
36 |
37 | /** Check to see we have the necessary permissions for this app, and ask for them if we don't. */
38 | public static void requestCameraPermission(Activity activity) {
39 | ActivityCompat.requestPermissions(
40 | activity, new String[] {CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE);
41 | }
42 |
43 | /** Check to see if we need to show the rationale for this permission. */
44 | public static boolean shouldShowRequestPermissionRationale(Activity activity) {
45 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION);
46 | }
47 |
48 | /** Launch Application Setting to grant permission. */
49 | public static void launchPermissionSettings(Activity activity) {
50 | Intent intent = new Intent();
51 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
52 | intent.setData(Uri.fromParts("package", activity.getPackageName(), null));
53 | activity.startActivity(intent);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/part4_completed/src/main/java/com/google/ar/core/codelab/common/helpers/FullScreenHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.view.View;
19 |
20 | /** Helper to set up the Android full screen mode. */
21 | public final class FullScreenHelper {
22 | /**
23 | * Sets the Android fullscreen flags. Expected to be called from {@link
24 | * Activity#onWindowFocusChanged(boolean hasFocus)}.
25 | *
26 | * @param activity the Activity on which the full screen mode will be set.
27 | * @param hasFocus the hasFocus flag passed from the {@link Activity#onWindowFocusChanged(boolean
28 | * hasFocus)} callback.
29 | */
30 | public static void setFullScreenOnWindowFocusChanged(Activity activity, boolean hasFocus) {
31 | if (hasFocus) {
32 | // https://developer.android.com/training/system-ui/immersive.html#sticky
33 | activity
34 | .getWindow()
35 | .getDecorView()
36 | .setSystemUiVisibility(
37 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
38 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
39 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
40 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
41 | | View.SYSTEM_UI_FLAG_FULLSCREEN
42 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/part4_completed/src/main/java/com/google/ar/core/codelab/common/helpers/SnackbarHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.support.design.widget.BaseTransientBottomBar;
19 | import android.support.design.widget.Snackbar;
20 | import android.view.View;
21 | import android.widget.TextView;
22 |
23 | /**
24 | * Helper to manage the sample snackbar. Hides the Android boilerplate code, and exposes simpler
25 | * methods.
26 | */
27 | public final class SnackbarHelper {
28 | private static final int BACKGROUND_COLOR = 0xbf323232;
29 | private Snackbar messageSnackbar;
30 | private enum DismissBehavior { HIDE, SHOW, FINISH };
31 | private int maxLines = 2;
32 | private String lastMessage = "";
33 |
34 | public boolean isShowing() {
35 | return messageSnackbar != null;
36 | }
37 |
38 | /** Shows a snackbar with a given message. */
39 | public void showMessage(Activity activity, String message) {
40 | if (!message.isEmpty() && (!isShowing() || !lastMessage.equals(message))) {
41 | lastMessage = message;
42 | show(activity, message, DismissBehavior.HIDE);
43 | }
44 | }
45 |
46 | /** Shows a snackbar with a given message, and a dismiss button. */
47 | public void showMessageWithDismiss(Activity activity, String message) {
48 | show(activity, message, DismissBehavior.SHOW);
49 | }
50 |
51 | /**
52 | * Shows a snackbar with a given error message. When dismissed, will finish the activity. Useful
53 | * for notifying errors, where no further interaction with the activity is possible.
54 | */
55 | public void showError(Activity activity, String errorMessage) {
56 | show(activity, errorMessage, DismissBehavior.FINISH);
57 | }
58 |
59 | /**
60 | * Hides the currently showing snackbar, if there is one. Safe to call from any thread. Safe to
61 | * call even if snackbar is not shown.
62 | */
63 | public void hide(Activity activity) {
64 | if (!isShowing()) {
65 | return;
66 | }
67 | lastMessage = "";
68 | Snackbar messageSnackbarToHide = messageSnackbar;
69 | messageSnackbar = null;
70 | activity.runOnUiThread(
71 | new Runnable() {
72 | @Override
73 | public void run() {
74 | messageSnackbarToHide.dismiss();
75 | }
76 | });
77 | }
78 |
79 | public void setMaxLines(int lines) {
80 | maxLines = lines;
81 | }
82 |
83 | private void show(
84 | final Activity activity, final String message, final DismissBehavior dismissBehavior) {
85 | activity.runOnUiThread(
86 | new Runnable() {
87 | @Override
88 | public void run() {
89 | messageSnackbar =
90 | Snackbar.make(
91 | activity.findViewById(android.R.id.content),
92 | message,
93 | Snackbar.LENGTH_INDEFINITE);
94 | messageSnackbar.getView().setBackgroundColor(BACKGROUND_COLOR);
95 | if (dismissBehavior != DismissBehavior.HIDE) {
96 | messageSnackbar.setAction(
97 | "Dismiss",
98 | new View.OnClickListener() {
99 | @Override
100 | public void onClick(View v) {
101 | messageSnackbar.dismiss();
102 | }
103 | });
104 | if (dismissBehavior == DismissBehavior.FINISH) {
105 | messageSnackbar.addCallback(
106 | new BaseTransientBottomBar.BaseCallback() {
107 | @Override
108 | public void onDismissed(Snackbar transientBottomBar, int event) {
109 | super.onDismissed(transientBottomBar, event);
110 | activity.finish();
111 | }
112 | });
113 | }
114 | }
115 | ((TextView)
116 | messageSnackbar
117 | .getView()
118 | .findViewById(android.support.design.R.id.snackbar_text))
119 | .setMaxLines(maxLines);
120 | messageSnackbar.show();
121 | }
122 | });
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/part4_completed/src/main/java/com/google/ar/core/codelab/common/helpers/TapHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.content.Context;
18 | import android.view.GestureDetector;
19 | import android.view.MotionEvent;
20 | import android.view.View;
21 | import android.view.View.OnTouchListener;
22 | import java.util.concurrent.ArrayBlockingQueue;
23 | import java.util.concurrent.BlockingQueue;
24 |
25 | /**
26 | * Helper to detect taps using Android GestureDetector, and pass the taps between UI thread and
27 | * render thread.
28 | */
29 | public final class TapHelper implements OnTouchListener {
30 | private final GestureDetector gestureDetector;
31 | private final BlockingQueue queuedSingleTaps = new ArrayBlockingQueue<>(16);
32 |
33 | /**
34 | * Creates the tap helper.
35 | *
36 | * @param context the application's context.
37 | */
38 | public TapHelper(Context context) {
39 | gestureDetector =
40 | new GestureDetector(
41 | context,
42 | new GestureDetector.SimpleOnGestureListener() {
43 | @Override
44 | public boolean onSingleTapUp(MotionEvent e) {
45 | // Queue tap if there is space. Tap is lost if queue is full.
46 | queuedSingleTaps.offer(e);
47 | return true;
48 | }
49 |
50 | @Override
51 | public boolean onDown(MotionEvent e) {
52 | return true;
53 | }
54 | });
55 | }
56 |
57 | /**
58 | * Polls for a tap.
59 | *
60 | * @return if a tap was queued, a MotionEvent for the tap. Otherwise null if no taps are queued.
61 | */
62 | public MotionEvent poll() {
63 | return queuedSingleTaps.poll();
64 | }
65 |
66 | @Override
67 | public boolean onTouch(View view, MotionEvent motionEvent) {
68 | return gestureDetector.onTouchEvent(motionEvent);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/part4_completed/src/main/java/com/google/ar/core/codelab/common/helpers/TrackingStateHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.helpers;
16 |
17 | import android.app.Activity;
18 | import android.view.WindowManager;
19 | import com.google.ar.core.Camera;
20 | import com.google.ar.core.TrackingFailureReason;
21 | import com.google.ar.core.TrackingState;
22 |
23 | /** Gets human readibly tracking failure reasons and suggested actions. */
24 | public final class TrackingStateHelper {
25 | private static final String INSUFFICIENT_FEATURES_MESSAGE =
26 | "Can't find anything. Aim device at a surface with more texture or color.";
27 | private static final String EXCESSIVE_MOTION_MESSAGE = "Moving too fast. Slow down.";
28 | private static final String INSUFFICIENT_LIGHT_MESSAGE =
29 | "Too dark. Try moving to a well-lit area.";
30 | private static final String BAD_STATE_MESSAGE =
31 | "Tracking lost due to bad internal state. Please try restarting the AR experience.";
32 | private static final String CAMERA_UNAVAILABLE_MESSAGE =
33 | "Another app is using the camera. Tap on this app or try closing the other one.";
34 |
35 | private final Activity activity;
36 |
37 | private TrackingState previousTrackingState;
38 |
39 | public TrackingStateHelper(Activity activity) {
40 | this.activity = activity;
41 | }
42 |
43 | /** Keep the screen unlocked while tracking, but allow it to lock when tracking stops. */
44 | public void updateKeepScreenOnFlag(TrackingState trackingState) {
45 | if (trackingState == previousTrackingState) {
46 | return;
47 | }
48 |
49 | previousTrackingState = trackingState;
50 | switch (trackingState) {
51 | case PAUSED:
52 | case STOPPED:
53 | activity.runOnUiThread(
54 | () -> activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
55 | break;
56 | case TRACKING:
57 | activity.runOnUiThread(
58 | () -> activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
59 | break;
60 | }
61 | }
62 |
63 | public static String getTrackingFailureReasonString(Camera camera) {
64 | TrackingFailureReason reason = camera.getTrackingFailureReason();
65 | switch (reason) {
66 | case NONE:
67 | return "";
68 | case BAD_STATE:
69 | return BAD_STATE_MESSAGE;
70 | case INSUFFICIENT_LIGHT:
71 | return INSUFFICIENT_LIGHT_MESSAGE;
72 | case EXCESSIVE_MOTION:
73 | return EXCESSIVE_MOTION_MESSAGE;
74 | case INSUFFICIENT_FEATURES:
75 | return INSUFFICIENT_FEATURES_MESSAGE;
76 | case CAMERA_UNAVAILABLE:
77 | return CAMERA_UNAVAILABLE_MESSAGE;
78 | }
79 | return "Unknown tracking failure reason: " + reason;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/part4_completed/src/main/java/com/google/ar/core/codelab/common/rendering/ShaderUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Google Inc. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.google.ar.core.codelab.common.rendering;
16 |
17 | import android.content.Context;
18 | import android.opengl.GLES20;
19 | import android.util.Log;
20 | import java.io.BufferedReader;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.io.InputStreamReader;
24 |
25 | /** Shader helper functions. */
26 | public class ShaderUtil {
27 | /**
28 | * Converts a raw text file, saved as a resource, into an OpenGL ES shader.
29 | *
30 | * @param type The type of shader we will be creating.
31 | * @param filename The filename of the asset file about to be turned into a shader.
32 | * @return The shader object handler.
33 | */
34 | public static int loadGLShader(String tag, Context context, int type, String filename)
35 | throws IOException {
36 | String code = readShaderFileFromAssets(context, filename);
37 | int shader = GLES20.glCreateShader(type);
38 | GLES20.glShaderSource(shader, code);
39 | GLES20.glCompileShader(shader);
40 |
41 | // Get the compilation status.
42 | final int[] compileStatus = new int[1];
43 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
44 |
45 | // If the compilation failed, delete the shader.
46 | if (compileStatus[0] == 0) {
47 | Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader));
48 | GLES20.glDeleteShader(shader);
49 | shader = 0;
50 | }
51 |
52 | if (shader == 0) {
53 | throw new RuntimeException("Error creating shader.");
54 | }
55 |
56 | return shader;
57 | }
58 |
59 | /**
60 | * Checks if we've had an error inside of OpenGL ES, and if so what that error is.
61 | *
62 | * @param label Label to report in case of error.
63 | * @throws RuntimeException If an OpenGL error is detected.
64 | */
65 | public static void checkGLError(String tag, String label) {
66 | int lastError = GLES20.GL_NO_ERROR;
67 | // Drain the queue of all errors.
68 | int error;
69 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
70 | Log.e(tag, label + ": glError " + error);
71 | lastError = error;
72 | }
73 | if (lastError != GLES20.GL_NO_ERROR) {
74 | throw new RuntimeException(label + ": glError " + lastError);
75 | }
76 | }
77 |
78 | /**
79 | * Converts a raw shader file into a string.
80 | *
81 | * @param filename The filename of the shader file about to be turned into a shader.
82 | * @return The context of the text file, or null in case of error.
83 | */
84 | private static String readShaderFileFromAssets(Context context, String filename)
85 | throws IOException {
86 | try (InputStream inputStream = context.getAssets().open(filename);
87 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
88 | StringBuilder sb = new StringBuilder();
89 | String line;
90 | while ((line = reader.readLine()) != null) {
91 | String[] tokens = line.split(" ", -1);
92 | if (tokens[0].equals("#include")) {
93 | String includeFilename = tokens[1];
94 | includeFilename = includeFilename.replace("\"", "");
95 | if (includeFilename.equals(filename)) {
96 | throw new IOException("Do not include the calling file.");
97 | }
98 | sb.append(readShaderFileFromAssets(context, includeFilename));
99 | } else {
100 | sb.append(line).append("\n");
101 | }
102 | }
103 | return sb.toString();
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/part4_completed/src/main/java/com/google/ar/core/codelab/depth/DepthTextureHandler.java:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package com.google.ar.core.codelab.depth;
16 |
17 | import static android.opengl.GLES20.GL_CLAMP_TO_EDGE;
18 | import static android.opengl.GLES20.GL_TEXTURE_2D;
19 | import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
20 | import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
21 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_S;
22 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_T;
23 | import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
24 | import static android.opengl.GLES20.glBindTexture;
25 | import static android.opengl.GLES20.glGenTextures;
26 | import static android.opengl.GLES20.glTexImage2D;
27 | import static android.opengl.GLES20.glTexParameteri;
28 | import static android.opengl.GLES30.GL_LINEAR;
29 | import static android.opengl.GLES30.GL_RG;
30 | import static android.opengl.GLES30.GL_RG8;
31 |
32 | import android.media.Image;
33 | import com.google.ar.core.Frame;
34 | import com.google.ar.core.exceptions.NotYetAvailableException;
35 |
36 | /** Handle RG8 GPU texture containing a DEPTH16 depth image. */
37 | public final class DepthTextureHandler {
38 |
39 | private int depthTextureId = -1;
40 | private int depthTextureWidth = -1;
41 | private int depthTextureHeight = -1;
42 |
43 | /**
44 | * Creates and initializes the depth texture. This method needs to be called on a
45 | * thread with a EGL context attached.
46 | */
47 | public void createOnGlThread() {
48 | int[] textureId = new int[1];
49 | glGenTextures(1, textureId, 0);
50 | depthTextureId = textureId[0];
51 | glBindTexture(GL_TEXTURE_2D, depthTextureId);
52 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
53 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
54 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
55 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
56 | }
57 |
58 | /**
59 | * Updates the depth texture with the content from acquireDepthImage().
60 | * This method needs to be called on a thread with a EGL context attached.
61 | */
62 | public void update(final Frame frame) {
63 | try {
64 | Image depthImage = frame.acquireDepthImage16Bits();
65 | depthTextureWidth = depthImage.getWidth();
66 | depthTextureHeight = depthImage.getHeight();
67 | glBindTexture(GL_TEXTURE_2D, depthTextureId);
68 | glTexImage2D(
69 | GL_TEXTURE_2D,
70 | 0,
71 | GL_RG8,
72 | depthTextureWidth,
73 | depthTextureHeight,
74 | 0,
75 | GL_RG,
76 | GL_UNSIGNED_BYTE,
77 | depthImage.getPlanes()[0].getBuffer());
78 | depthImage.close();
79 | } catch (NotYetAvailableException e) {
80 | // This normally means that depth data is not available yet.
81 | }
82 | }
83 |
84 | public int getDepthTexture() {
85 | return depthTextureId;
86 | }
87 |
88 | public int getDepthWidth() {
89 | return depthTextureWidth;
90 | }
91 |
92 | public int getDepthHeight() {
93 | return depthTextureHeight;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/part4_completed/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google-ar/codelab-depth-api/039f27984888ffc4935b9daecbf033400a0f651e/part4_completed/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/part4_completed/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
16 |
21 |
22 |
27 |
28 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/part4_completed/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | Depth Codelab
19 | Show Depth
20 | Hide Depth
21 | Depth Not Available
22 |
23 |
--------------------------------------------------------------------------------
/part4_completed/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
22 |
29 |
30 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':part0_work', 'part1', 'part2', 'part3', 'part4_completed'
--------------------------------------------------------------------------------