diff --git a/LICENSE b/LICENSE index 974d9bd6f..3be7b564b 100644 --- a/LICENSE +++ b/LICENSE @@ -2666,6 +2666,16 @@ this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +------------------ + +Files: + +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. ******************************************************************************* Protocol Buffers for Java ******************************************************************************* @@ -2908,6 +2918,35 @@ TCMalloc See the License for the specific language governing permissions and limitations under the License. +******************************************************************************* +libexecinfo +******************************************************************************* +Copyright (c) 2003 Maxim Sobolev +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +$Id: execinfo.c,v 1.3 2004/07/19 05:21:09 sobomax Exp $ + ******************************************************************************* tz database ******************************************************************************* diff --git a/libraries/include/arcore_c_api.h b/libraries/include/arcore_c_api.h index 59d5413fa..478b840b0 100644 --- a/libraries/include/arcore_c_api.h +++ b/libraries/include/arcore_c_api.h @@ -986,8 +986,7 @@ AR_DEFINE_ENUM(ArCloudAnchorState){ AR_CLOUD_ANCHOR_STATE_ERROR_INTERNAL = -1, /// The authorization provided by the application is not valid. - /// - The Google Cloud project may not have enabled the ARCore Cloud Anchor - /// API. + /// - The Google Cloud project may not have enabled the ARCore API. /// - It may fail if the operation you are trying to perform is not allowed. /// - When using API key authentication, this will happen if the API key in /// the manifest is invalid, unauthorized or missing. It may also fail if @@ -1004,9 +1003,8 @@ AR_DEFINE_ENUM(ArCloudAnchorState){ "ARCore SDK 1.12. See release notes to learn more.") = -3, /// The application has exhausted the request quota allotted to the given - /// API key. The developer should request additional quota for the ARCore - /// Cloud Anchor service for their API key from the Google Developers - /// Console. + /// API key. The developer should request additional quota for the ARCore API + /// for their API key from the Google Developers Console. AR_CLOUD_ANCHOR_STATE_ERROR_RESOURCE_EXHAUSTED = -4, /// Hosting failed, because the server could not successfully process the @@ -1780,7 +1778,11 @@ void ArConfig_setAugmentedImageDatabase( /// @ingroup ArConfig /// Returns the image database from the session configuration. /// -/// This function returns a copy of the internally stored image database. +/// This function returns a copy of the internally stored image database, so any +/// changes to the copy will not affect the current configuration or session. +/// +/// If no @c ::ArAugmentedImageDatabase has been configured, a new empty +/// database will be constructed using @c ::ArAugmentedImageDatabase_create. void ArConfig_getAugmentedImageDatabase( const ArSession *session, const ArConfig *config, @@ -5522,13 +5524,15 @@ void ArEarth_getCameraGeospatialPose( ArGeospatialPose *out_camera_geospatial_pose); /// @ingroup ArEarth -/// Creates a new @c ::ArAnchor at the specified geodetic location and +/// Creates a new @c ::ArAnchor at the specified geospatial location and /// orientation relative to the Earth. /// /// Latitude and longitude are defined by the /// WGS84 /// specification, and altitude values are defined as the elevation above -/// the WGS84 ellipsoid in meters. +/// the WGS84 ellipsoid in meters. To create an anchor using an altitude +/// relative to the Earth's terrain instead of altitude above the WGS84 +/// ellipsoid, use @c ::ArEarth_resolveAndAcquireNewAnchorOnTerrain. /// /// The rotation provided by @p eus_quaternion_4 is a rotation with respect to /// an east-up-south coordinate frame. An identity rotation will have the anchor @@ -5536,17 +5540,18 @@ void ArEarth_getCameraGeospatialPose( /// of the earth, and Z+ points to the south. /// /// To create an anchor that has the +Z axis pointing in the same direction as -/// heading obtained from @c ::ArGeospatialPose, use the following formula: +/// heading contained in an @c ::ArGeospatialPose, use the following formula: /// /// \code /// {qx, qy, qz, qw} = {0, sin((pi - heading * M_PI / 180.0) / 2), 0, cos((pi - /// heading * M_PI / 180.0) / 2)}}. /// \endcode /// -/// An anchor's @c ::ArTrackingState will be @c #AR_TRACKING_STATE_PAUSED while -/// @c ::ArEarth is @c #AR_TRACKING_STATE_PAUSED. The tracking state will -/// permanently become @c #AR_TRACKING_STATE_STOPPED if the @c ::ArSession -/// configuration is set to @c #AR_GEOSPATIAL_MODE_DISABLED. +/// An anchor's @c ::ArTrackingState will be @c #AR_TRACKING_STATE_PAUSED +/// while @c ::ArEarth's @c ::ArTrackingState is @c #AR_TRACKING_STATE_PAUSED. +/// Its tracking state will permanently become @c +/// #AR_TRACKING_STATE_STOPPED if @c ::ArSession_configure sets the Geospatial +/// mode to @c #AR_GEOSPATIAL_MODE_DISABLED. /// /// Creating anchors near the north pole or south pole is not supported. If the /// latitude is within 0.1 degrees of the north pole or south pole (90 degrees @@ -5579,6 +5584,151 @@ ArStatus ArEarth_acquireNewAnchor(ArSession *session, const float *eus_quaternion_4, ArAnchor **out_anchor); +/// @ingroup ArEarth +/// Creates a new @c ::ArAnchor at a specified horizontal position and altitude +/// relative to the horizontal position’s terrain. Terrain means the ground or +/// ground floor inside a building with VPS coverage. If the altitude relative +/// to the WGS84 ellipsoid is known, use @c ::ArEarth_acquireNewAnchor instead. +/// +/// The specified @p altitude_above_terrain is interpreted to be relative to the +/// Earth's terrain (or floor) at the specified latitude/longitude geospatial +/// coordinates, rather than relative to the WGS84 ellipsoid. Specifying an +/// altitude of 0 will position the anchor directly on the terrain (or floor) +/// whereas specifying a positive altitude will position the anchor above the +/// terrain (or floor), against the direction of gravity. +/// +/// This creates a new @c ::ArAnchor and schedules a task to resolve the +/// anchor's pose using the given parameters. You may resolve multiple anchors +/// at a time, but a session cannot be tracking more than 40 Terrain Anchors at +/// time. Attempting to resolve more than 40 Terrain Anchors will result in +/// resolve calls returning status @c #AR_ERROR_RESOURCE_EXHAUSTED. +/// +/// If this function returns @c #AR_SUCCESS, the Terrain Anchor state of @p +/// out_terrain_anchor will be @c #AR_TERRAIN_ANCHOR_STATE_TASK_IN_PROGRESS, and +/// its tracking state will be @c #AR_TRACKING_STATE_PAUSED. The anchor +/// remains in this state until its pose has been successfully resolved. If +/// the resolving task results in an error, its tracking state will be +/// permanently set to @c #AR_TRACKING_STATE_STOPPED, and @c +/// ::ArAnchor_getTerrainAnchorState details the error that occurred using @c +/// ::ArTerrainAnchorState. If this function's return value is not @c +/// #AR_SUCCESS, then @p out_anchor will be set to @c NULL. +/// +/// Creating a Terrain Anchor requires an active @c ::ArEarth which is @c +/// #AR_EARTH_STATE_ENABLED. If it is not, then this function returns @c +/// #AR_ERROR_ILLEGAL_STATE. This call also requires a working internet +/// connection to communicate with the ARCore API on Google Cloud. ARCore will +/// continue to retry if it is unable to establish a connection to the ARCore +/// service. +/// +/// A Terrain Anchor's @c ::ArTrackingState will be @c #AR_TRACKING_STATE_PAUSED +/// while @c ::ArEarth's @c ::ArTrackingState is @c #AR_TRACKING_STATE_PAUSED. +/// The anchor's tracking state will permanently become @c +/// #AR_TRACKING_STATE_STOPPED if @c ::ArSession_configure is used to set @c +/// #AR_GEOSPATIAL_MODE_DISABLED. +/// +/// +/// Latitude and longitude are defined by the +/// WGS84 +/// specification. +/// +/// The rotation provided by @p eus_quaternion_4 is a rotation with respect to +/// an east-up-south coordinate frame. An identity rotation will have the anchor +/// oriented such that X+ points to the east, Y+ points up away from the center +/// of the earth, and Z+ points to the south. +/// +/// To create an anchor that has the +Z axis pointing in the same direction as +/// heading contained in an @c ::ArGeospatialPose, use the following formula: +/// +/// \code +/// {qx, qy, qz, qw} = {0, sin((pi - heading * M_PI / 180.0) / 2), 0, cos((pi - +/// heading * M_PI / 180.0) / 2)}}. +/// \endcode +/// +/// @param[in] session The ARCore session. +/// @param[in] earth The @c ::ArEarth handle. +/// @param[in] latitude The latitude of the anchor relative to the +/// WGS84 ellipsoid. +/// @param[in] longitude The longitude of the anchor relative to the +/// WGS84 ellipsoid. +/// @param[in] altitude_above_terrain The altitude of the anchor above the +/// Earth's terrain (or floor). +/// @param[in] eus_quaternion_4 The rotation quaternion as {qx, qy, qx, qw}. +/// @param[out] out_anchor The newly-created anchor. +/// @return @c #AR_SUCCESS or any of: +/// - @c #AR_ERROR_ILLEGAL_STATE if @p earth's @c ::ArEarthState is not +/// @c #AR_EARTH_STATE_ENABLED. +/// - @c #AR_ERROR_INVALID_ARGUMENT if @p latitude is outside the allowable +/// range, or if either @p session, @p earth, or @p eus_quaternion_4 is @c +/// NULL. +/// - @c #AR_ERROR_RESOURCE_EXHAUSTED if too many terrain anchors are currently +/// held. +ArStatus ArEarth_resolveAndAcquireNewAnchorOnTerrain( + ArSession *session, + ArEarth *earth, + double latitude, + double longitude, + double altitude_above_terrain, + const float *eus_quaternion_4, + ArAnchor **out_anchor); + +/// @ingroup ArAnchor +/// Describes the current Terrain Anchor state of an @c ::ArAnchor. Obtained by +/// @c ::ArAnchor_getTerrainAnchorState. +AR_DEFINE_ENUM(ArTerrainAnchorState){ + /// This is not a Terrain Anchor, or the Terrain Anchor has become invalid + /// due to @c ::ArEarth having @c #AR_TRACKING_STATE_STOPPED + /// due to @c #AR_GEOSPATIAL_MODE_DISABLED being set on the @c ::ArSession. + /// All Terrain Anchors transition to @c #AR_TERRAIN_ANCHOR_STATE_NONE + /// when @c #AR_GEOSPATIAL_MODE_DISABLED becomes active on the @c + /// ::ArSession. + AR_TERRAIN_ANCHOR_STATE_NONE = 0, + + /// Resolving the Terrain Anchor is in progress. Once the task completes in + /// the background, the anchor will get a new state after the next @c + /// ::ArSession_update call. + AR_TERRAIN_ANCHOR_STATE_TASK_IN_PROGRESS = 1, + + /// A resolving task for this Terrain Anchor has finished successfully. + AR_TERRAIN_ANCHOR_STATE_SUCCESS = 2, + + /// Resolving task for this Terrain Anchor finished with an internal + /// error. The app should not attempt to recover from this error. + AR_TERRAIN_ANCHOR_STATE_ERROR_INTERNAL = -1, + + /// The authorization provided by the application is not valid. + /// - The Google Cloud project may not have enabled the ARCore API. + /// - When using API key authentication, this will happen if the API key in + /// the manifest is invalid or unauthorized. It may also fail if the API + /// key is restricted to a set of apps not including the current one. + /// - When using keyless authentication, this may happen when no OAuth + /// client has been created, or when the signing key and package name + /// combination does not match the values used in the Google Cloud + /// project. It may also fail if Google Play Services isn't installed, + /// is too old, or is malfunctioning for some reason (e.g. killed + /// due to memory pressure). + AR_TERRAIN_ANCHOR_STATE_ERROR_NOT_AUTHORIZED = -2, + + /// There is no terrain info at this location, such as the center of the + /// ocean. + AR_TERRAIN_ANCHOR_STATE_ERROR_UNSUPPORTED_LOCATION = -3, +}; + +/// @ingroup ArAnchor +/// Gets the current Terrain Anchor state of the anchor. This state is +/// guaranteed not to change until @c ::ArSession_update is called. For Anchors +/// that are not Terrain Anchors, this function returns @c +/// #AR_TERRAIN_ANCHOR_STATE_NONE. See @c ::ArTerrainAnchorState for the +/// possible Terrain Anchor states. +/// +/// @param[in] session The ARCore session. +/// @param[in] anchor The anchor to retrieve the terrain anchor state of. +/// @param[inout] out_state The current terrain anchor state of the anchor. +/// Non-terrain anchors will always be in +/// @c #AR_TERRAIN_ANCHOR_STATE_NONE state. +void ArAnchor_getTerrainAnchorState(const ArSession *session, + const ArAnchor *anchor, + ArTerrainAnchorState *out_state); + // === ArGeospatialPose functions === /// @ingroup ArGeospatialPose diff --git a/samples/augmented_faces_java/app/build.gradle b/samples/augmented_faces_java/app/build.gradle index 75c9f8a84..be8828ce4 100644 --- a/samples/augmented_faces_java/app/build.gradle +++ b/samples/augmented_faces_java/app/build.gradle @@ -1,14 +1,14 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 32 + compileSdkVersion 33 defaultConfig { applicationId "com.google.ar.core.examples.java.augmentedfaces" // AR Optional apps must declare minSdkVersion >= 14. // AR Required apps must declare minSdkVersion >= 24. minSdkVersion 24 - targetSdkVersion 32 + targetSdkVersion 33 versionCode 1 versionName '1.0' } @@ -26,7 +26,7 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.32.0' + implementation 'com.google.ar:core:1.33.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/augmented_image_c/app/build.gradle b/samples/augmented_image_c/app/build.gradle index 5f9b42029..b0909c179 100644 --- a/samples/augmented_image_c/app/build.gradle +++ b/samples/augmented_image_c/app/build.gradle @@ -10,14 +10,14 @@ def arcore_libpath = "${buildDir}/arcore-native" configurations { natives } android { - compileSdkVersion 32 + compileSdkVersion 33 defaultConfig { applicationId "com.google.ar.core.examples.c.augmentedimage" // "AR Optional" apps must declare minSdkVersion >= 14. // "AR Required" apps must declare minSdkVersion >= 24. minSdkVersion 24 - targetSdkVersion 32 + targetSdkVersion 33 versionCode 1 versionName '1.0' @@ -53,8 +53,8 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.32.0' - natives 'com.google.ar:core:1.32.0' + implementation 'com.google.ar:core:1.33.0' + natives 'com.google.ar:core:1.33.0' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'com.google.android.material:material:1.1.0' diff --git a/samples/augmented_image_java/app/build.gradle b/samples/augmented_image_java/app/build.gradle index 8d5bf446e..f16ee01a4 100644 --- a/samples/augmented_image_java/app/build.gradle +++ b/samples/augmented_image_java/app/build.gradle @@ -1,14 +1,14 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 32 + compileSdkVersion 33 defaultConfig { applicationId "com.google.ar.core.examples.java.augmentedimage" // "AR Optional" apps must declare minSdkVersion >= 14. // "AR Required" apps must declare minSdkVersion >= 24. minSdkVersion 24 - targetSdkVersion 32 + targetSdkVersion 33 versionCode 1 versionName '1.0' } @@ -26,7 +26,7 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.32.0' + implementation 'com.google.ar:core:1.33.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/cloud_anchor_java/app/build.gradle b/samples/cloud_anchor_java/app/build.gradle index d9a96280f..dafcbc2e7 100644 --- a/samples/cloud_anchor_java/app/build.gradle +++ b/samples/cloud_anchor_java/app/build.gradle @@ -1,14 +1,14 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 32 + compileSdkVersion 33 defaultConfig { applicationId "com.google.ar.core.examples.java.cloudanchor" // "AR Optional" apps must declare minSdkVersion >= 14. // "AR Required" apps must declare minSdkVersion >= 24. minSdkVersion 24 - targetSdkVersion 32 + targetSdkVersion 33 versionCode 1 versionName '1.0' } @@ -26,7 +26,7 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.32.0' + implementation 'com.google.ar:core:1.33.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/computervision_c/app/build.gradle b/samples/computervision_c/app/build.gradle index bd940f574..0b7977cd6 100644 --- a/samples/computervision_c/app/build.gradle +++ b/samples/computervision_c/app/build.gradle @@ -10,14 +10,14 @@ def arcore_libpath = "${buildDir}/arcore-native" configurations { natives } android { - compileSdkVersion 32 + compileSdkVersion 33 defaultConfig { applicationId "com.google.ar.core.examples.c.computervision" // "AR Optional" apps must declare minSdkVersion >= 14. // "AR Required" apps must declare minSdkVersion >= 24. minSdkVersion 24 - targetSdkVersion 32 + targetSdkVersion 33 versionCode 1 versionName '1.0' @@ -53,8 +53,8 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.32.0' - natives 'com.google.ar:core:1.32.0' + implementation 'com.google.ar:core:1.33.0' + natives 'com.google.ar:core:1.33.0' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'com.google.android.material:material:1.1.0' diff --git a/samples/computervision_java/app/build.gradle b/samples/computervision_java/app/build.gradle index 4cdd2c821..28ea3c641 100644 --- a/samples/computervision_java/app/build.gradle +++ b/samples/computervision_java/app/build.gradle @@ -1,14 +1,14 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 32 + compileSdkVersion 33 defaultConfig { applicationId "com.google.ar.core.examples.java.computervision" // "AR Optional" apps must declare minSdkVersion >= 14. // "AR Required" apps must declare minSdkVersion >= 24. minSdkVersion 24 - targetSdkVersion 32 + targetSdkVersion 33 versionCode 1 versionName '1.0' } @@ -26,7 +26,7 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.32.0' + implementation 'com.google.ar:core:1.33.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/geospatial_java/app/build.gradle b/samples/geospatial_java/app/build.gradle index 5669ae941..5030fd330 100644 --- a/samples/geospatial_java/app/build.gradle +++ b/samples/geospatial_java/app/build.gradle @@ -1,14 +1,14 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 32 + compileSdkVersion 33 defaultConfig { applicationId "com.google.ar.core.examples.java.geospatial" // AR Optional apps must declare minSdkVersion >= 14. // AR Required apps must declare minSdkVersion >= 24. minSdkVersion 24 - targetSdkVersion 32 + targetSdkVersion 33 versionCode 1 versionName '1.0' } @@ -26,7 +26,7 @@ android { dependencies { // ARCore (Google Play Services for AR) library. - implementation 'com.google.ar:core:1.32.0' + implementation 'com.google.ar:core:1.33.0' implementation 'com.google.android.gms:play-services-location:19.0.1' // Obj - a simple Wavefront OBJ file loader diff --git a/samples/geospatial_java/app/src/main/assets/models/spatial_marker_yellow.png b/samples/geospatial_java/app/src/main/assets/models/spatial_marker_yellow.png new file mode 100644 index 000000000..501ac8ae0 Binary files /dev/null and b/samples/geospatial_java/app/src/main/assets/models/spatial_marker_yellow.png differ diff --git a/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/common/samplerender/arcore/SpecularCubemapFilter.java b/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/common/samplerender/arcore/SpecularCubemapFilter.java index 51c653ddf..a8708ce28 100644 --- a/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/common/samplerender/arcore/SpecularCubemapFilter.java +++ b/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/common/samplerender/arcore/SpecularCubemapFilter.java @@ -18,9 +18,9 @@ import static java.lang.Math.max; import static java.lang.Math.min; +import android.media.Image; import android.opengl.GLES30; import android.util.Log; -import com.google.ar.core.ArImage; import com.google.ar.core.ImageFormat; import com.google.ar.core.examples.java.common.samplerender.GLError; import com.google.ar.core.examples.java.common.samplerender.Mesh; @@ -231,9 +231,9 @@ public void close() { * com.google.ar.core.LightEstimate.acquireEnvironmentalHdrCubeMap()} to update the filtered * cubemap texture, accessible via {@link getFilteredCubemapTexture()}. * - *

The given {@link ArImage}s will be closed by this method, even if an exception occurs. + *

The given {@link Image}s will be closed by this method, even if an exception occurs. */ - public void update(ArImage[] images) { + public void update(Image[] images) { try { GLES30.glBindTexture(GLES30.GL_TEXTURE_CUBE_MAP, radianceCubemap.getTextureId()); GLError.maybeThrowGLException("Failed to bind radiance cubemap texture", "glBindTexture"); @@ -244,7 +244,7 @@ public void update(ArImage[] images) { } for (int i = 0; i < NUMBER_OF_CUBE_FACES; ++i) { - ArImage image = images[i]; + Image image = images[i]; // Sanity check for the format of the cubemap. if (image.getFormat() != ImageFormat.RGBA_FP16) { throw new IllegalArgumentException( @@ -293,7 +293,7 @@ public void update(ArImage[] images) { } } } finally { - for (ArImage image : images) { + for (Image image : images) { image.close(); } } @@ -306,7 +306,7 @@ public int getNumberOfMipmapLevels() { /** * Returns the filtered cubemap texture whose contents are updated with each call to {@link - * #update(ArImage[])}. + * #update(Image[])}. */ public Texture getFilteredCubemapTexture() { return ldCubemap; diff --git a/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/geospatial/GeospatialActivity.java b/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/geospatial/GeospatialActivity.java index 1977e3e1b..d4623db51 100644 --- a/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/geospatial/GeospatialActivity.java +++ b/samples/geospatial_java/app/src/main/java/com/google/ar/core/examples/java/geospatial/GeospatialActivity.java @@ -21,6 +21,7 @@ import android.opengl.GLSurfaceView; import android.opengl.Matrix; import android.os.Bundle; +import android.os.SystemClock; import android.util.Log; import android.view.View; import android.widget.Button; @@ -29,6 +30,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.DialogFragment; import com.google.ar.core.Anchor; +import com.google.ar.core.Anchor.TerrainAnchorState; import com.google.ar.core.ArCoreApk; import com.google.ar.core.Camera; import com.google.ar.core.Config; @@ -53,6 +55,7 @@ import com.google.ar.core.exceptions.CameraNotAvailableException; import com.google.ar.core.exceptions.FineLocationPermissionNotGrantedException; import com.google.ar.core.exceptions.GooglePlayServicesLocationLibraryNotLinkedException; +import com.google.ar.core.exceptions.ResourceExhaustedException; import com.google.ar.core.exceptions.UnavailableApkTooOldException; import com.google.ar.core.exceptions.UnavailableArcoreNotInstalledException; import com.google.ar.core.exceptions.UnavailableDeviceNotCompatibleException; @@ -61,8 +64,10 @@ import com.google.ar.core.exceptions.UnsupportedConfigurationException; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -96,7 +101,8 @@ public class GeospatialActivity extends AppCompatActivity private static final double LOCALIZED_HEADING_ACCURACY_HYSTERESIS_DEGREES = 10; private static final int LOCALIZING_TIMEOUT_SECONDS = 180; - private static final int MAXIMUM_ANCHORS = 10; + private static final int MAXIMUM_ANCHORS = 5; + private static final long DURATION_FOR_NO_TERRAIN_ANCHOR_RESULT_MS = 10000; // Rendering. The Renderers are created here, and initialized when the GL surface is created. private GLSurfaceView surfaceView; @@ -106,6 +112,8 @@ public class GeospatialActivity extends AppCompatActivity /** Timer to keep track of how much time has passed since localizing has started. */ private long localizingStartTimestamp; + /** Deadline for showing resolving terrain anchors no result yet message. */ + private long deadlineForMessageMillis; enum State { /** The Geospatial API has not yet been initialized. */ @@ -138,11 +146,14 @@ enum State { private final TrackingStateHelper trackingStateHelper = new TrackingStateHelper(this); private SampleRender render; private SharedPreferences sharedPreferences; + private final HashMap pendingTerrainAnchors = + new HashMap<>(); private String lastStatusText; private TextView geospatialPoseTextView; private TextView statusTextView; private Button setAnchorButton; + private Button setTerrainAnchorButton; private Button clearAnchorsButton; private BackgroundRenderer backgroundRenderer; @@ -151,7 +162,9 @@ enum State { // Virtual object (ARCore geospatial) private Mesh virtualObjectMesh; - private Shader virtualObjectShader; + private Shader geospatialAnchorVirtualObjectShader; + // Virtual object (ARCore geospatial terrain) + private Shader terrainAnchorVirtualObjectShader; private final List anchors = new ArrayList<>(); @@ -172,9 +185,11 @@ protected void onCreate(Bundle savedInstanceState) { geospatialPoseTextView = findViewById(R.id.geospatial_pose_view); statusTextView = findViewById(R.id.status_text_view); setAnchorButton = findViewById(R.id.set_anchor_button); + setTerrainAnchorButton = findViewById(R.id.set_terrain_anchor_button); clearAnchorsButton = findViewById(R.id.clear_anchors_button); setAnchorButton.setOnClickListener(view -> handleSetAnchorButton()); + setTerrainAnchorButton.setOnClickListener(view -> handleSetTerrainAnchorButton()); clearAnchorsButton.setOnClickListener(view -> handleClearAnchorsButton()); displayRotationHelper = new DisplayRotationHelper(/*context=*/ this); @@ -245,6 +260,8 @@ private void createSession() { } // Create the session. + // Plane finding mode is default on, which will help the dynamic alignment of terrain + // anchors on ground. session = new Session(/* context= */ this); } catch (UnavailableArcoreNotInstalledException | UnavailableUserDeclinedInstallationException e) { @@ -372,7 +389,7 @@ public void onSurfaceCreated(SampleRender render) { Texture.ColorFormat.SRGB); virtualObjectMesh = Mesh.createFromAsset(render, "models/geospatial_marker.obj"); - virtualObjectShader = + geospatialAnchorVirtualObjectShader = Shader.createFromAssets( render, "shaders/ar_unlit_object.vert", @@ -380,6 +397,21 @@ public void onSurfaceCreated(SampleRender render) { /*defines=*/ null) .setTexture("u_Texture", virtualObjectTexture); + // Virtual object to render (Terrain Anchor marker) + Texture terrainAnchorVirtualObjectTexture = + Texture.createFromAsset( + render, + "models/spatial_marker_yellow.png", + Texture.WrapMode.CLAMP_TO_EDGE, + Texture.ColorFormat.SRGB); + terrainAnchorVirtualObjectShader = + Shader.createFromAssets( + render, + "shaders/ar_unlit_object.vert", + "shaders/ar_unlit_object.frag", + /*defines=*/ null) + .setTexture("u_Texture", terrainAnchorVirtualObjectTexture); + backgroundRenderer.setUseDepthVisualization(render, false); backgroundRenderer.setUseOcclusion(render, false); } catch (IOException e) { @@ -462,25 +494,30 @@ public void onDrawFrame(SampleRender render) { message = getResources().getString(R.string.status_localize_timeout); break; case LOCALIZED: - if (anchors.size() > 0) { - message = - getResources() - .getQuantityString(R.plurals.status_anchors_set, anchors.size(), anchors.size()); - - } else if (clearedAnchorsAmount != null) { - message = - getResources() - .getQuantityString( - R.plurals.status_anchors_cleared, clearedAnchorsAmount, clearedAnchorsAmount); - } else { + if (pendingTerrainAnchors.size() > 0) { + // If there is a terrain anchor, show terrain anchor state. + for (Map.Entry entry : + pendingTerrainAnchors.entrySet()) { + Anchor anchor = entry.getKey(); + TerrainAnchorResolveListener listener = entry.getValue(); + if (anchor.getTerrainAnchorState() != TerrainAnchorState.TASK_IN_PROGRESS) { + listener.onTaskComplete(anchor); + pendingTerrainAnchors.remove(anchor); + } + if (deadlineForMessageMillis > 0 + && SystemClock.uptimeMillis() > deadlineForMessageMillis) { + listener.onDeadlineExceeded(); + deadlineForMessageMillis = 0; + pendingTerrainAnchors.remove(anchor); + } + } + } else if (anchors.size() == 0 && clearedAnchorsAmount == null) { message = getResources().getString(R.string.status_localize_complete); } break; } - if (message == null) { - lastStatusText = null; - runOnUiThread(() -> statusTextView.setVisibility(View.INVISIBLE)); - } else if (lastStatusText != message) { + + if (message != null && lastStatusText != message) { lastStatusText = message; runOnUiThread( () -> { @@ -515,16 +552,29 @@ public void onDrawFrame(SampleRender render) { for (Anchor anchor : anchors) { // Get the current pose of an Anchor in world space. The Anchor pose is updated // during calls to session.update() as ARCore refines its estimate of the world. + + // Only render resolved Terrain Anchors and Geospatial anchors. + if (anchor.getTerrainAnchorState() != TerrainAnchorState.SUCCESS + && anchor.getTerrainAnchorState() != TerrainAnchorState.NONE) { + continue; + } anchor.getPose().toMatrix(modelMatrix, 0); // Calculate model/view/projection matrices Matrix.multiplyMM(modelViewMatrix, 0, viewMatrix, 0, modelMatrix, 0); Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, modelViewMatrix, 0); - // Update shader properties and draw - virtualObjectShader.setMat4("u_ModelViewProjection", modelViewProjectionMatrix); - - render.draw(virtualObjectMesh, virtualObjectShader, virtualSceneFramebuffer); + if (anchor.getTerrainAnchorState() == TerrainAnchorState.SUCCESS) { + terrainAnchorVirtualObjectShader.setMat4( + "u_ModelViewProjection", modelViewProjectionMatrix); + + render.draw(virtualObjectMesh, terrainAnchorVirtualObjectShader, virtualSceneFramebuffer); + } else { + geospatialAnchorVirtualObjectShader.setMat4( + "u_ModelViewProjection", modelViewProjectionMatrix); + render.draw( + virtualObjectMesh, geospatialAnchorVirtualObjectShader, virtualSceneFramebuffer); + } } // Compose the virtual scene with the background. @@ -594,6 +644,7 @@ private void updateLocalizingState(Earth earth) { runOnUiThread( () -> { setAnchorButton.setVisibility(View.VISIBLE); + setTerrainAnchorButton.setVisibility(View.VISIBLE); }); return; } @@ -628,6 +679,7 @@ private void updateLocalizedState(Earth earth) { runOnUiThread( () -> { setAnchorButton.setVisibility(View.INVISIBLE); + setTerrainAnchorButton.setVisibility(View.INVISIBLE); clearAnchorsButton.setVisibility(View.INVISIBLE); }); return; @@ -673,7 +725,30 @@ private void handleSetAnchorButton() { double headingDegrees = geospatialPose.getHeading(); createAnchor(earth, latitude, longitude, altitude, headingDegrees); storeAnchorParameters(latitude, longitude, altitude, headingDegrees); - runOnUiThread(() -> clearAnchorsButton.setVisibility(View.VISIBLE)); + clearAnchorsButton.setVisibility(View.VISIBLE); + if (clearedAnchorsAmount != null) { + clearedAnchorsAmount = null; + } + String message = + getResources() + .getQuantityString(R.plurals.status_anchors_set, anchors.size(), anchors.size()); + + statusTextView.setVisibility(View.VISIBLE); + statusTextView.setText(message); + } + + private void handleSetTerrainAnchorButton() { + Earth earth = session.getEarth(); + if (earth == null || earth.getTrackingState() != TrackingState.TRACKING) { + return; + } + + GeospatialPose geospatialPose = earth.getCameraGeospatialPose(); + double latitude = geospatialPose.getLatitude(); + double longitude = geospatialPose.getLongitude(); + double headingDegrees = geospatialPose.getHeading(); + createTerrainAnchor(earth, latitude, longitude, headingDegrees); + clearAnchorsButton.setVisibility(View.VISIBLE); if (clearedAnchorsAmount != null) { clearedAnchorsAmount = null; } @@ -681,9 +756,22 @@ private void handleSetAnchorButton() { private void handleClearAnchorsButton() { clearedAnchorsAmount = anchors.size(); + String message = + getResources() + .getQuantityString( + R.plurals.status_anchors_cleared, clearedAnchorsAmount, clearedAnchorsAmount); + + statusTextView.setVisibility(View.VISIBLE); + statusTextView.setText(message); + + for (Anchor anchor : anchors) { + anchor.detach(); + } anchors.clear(); clearAnchorsFromSharedPreferences(); clearAnchorsButton.setVisibility(View.INVISIBLE); + setAnchorButton.setVisibility(View.VISIBLE); + setTerrainAnchorButton.setVisibility(View.VISIBLE); } /** Create an anchor at a specific geodetic location using a heading. */ @@ -701,8 +789,42 @@ private void createAnchor( 0.0f, (float) Math.cos(angleRadians / 2)); anchors.add(anchor); - if (anchors.size() > MAXIMUM_ANCHORS) { - anchors.remove(0); + if (anchors.size() >= MAXIMUM_ANCHORS) { + setAnchorButton.setVisibility(View.INVISIBLE); + setTerrainAnchorButton.setVisibility(View.INVISIBLE); + } + } + + /** Create a terrain anchor at a specific geodetic location using a heading. */ + private void createTerrainAnchor( + Earth earth, double latitude, double longitude, double headingDegrees) { + // Convert a heading to a EUS quaternion: + double angleRadians = Math.toRadians(180.0f - headingDegrees); + Anchor anchor = null; + try { + anchor = + earth.resolveAnchorOnTerrain( + latitude, + longitude, + /* altitudeAboveTerrain= */ 0.0f, + 0.0f, + (float) Math.sin(angleRadians / 2), + 0.0f, + (float) Math.cos(angleRadians / 2)); + anchors.add(anchor); + if (anchors.size() >= MAXIMUM_ANCHORS) { + setAnchorButton.setVisibility(View.INVISIBLE); + setTerrainAnchorButton.setVisibility(View.INVISIBLE); + } + } catch (ResourceExhaustedException e) { + messageSnackbarHelper.showMessageWithDismiss( + this, getResources().getString(R.string.terrain_anchor_resource_exhausted)); + Log.d(TAG, "Exception creating terrain anchor", e); + } + deadlineForMessageMillis = + SystemClock.uptimeMillis() + DURATION_FOR_NO_TERRAIN_ANCHOR_RESULT_MS; + if (anchor != null) { + pendingTerrainAnchors.put(anchor, new TerrainAnchorResolveListener()); } } @@ -760,4 +882,25 @@ public void onDialogPositiveClick(DialogFragment dialog) { } createSession(); } + + /** Listener for the results of a resolving terrain anchor operation. */ + private final class TerrainAnchorResolveListener { + public void onTaskComplete(Anchor anchor) { + TerrainAnchorState state = anchor.getTerrainAnchorState(); + runOnUiThread( + () -> { + statusTextView.setVisibility(View.VISIBLE); + statusTextView.setText(getString(R.string.status_terrain_anchor, state)); + }); + } + + public void onDeadlineExceeded() { + runOnUiThread( + () -> { + statusTextView.setVisibility(View.VISIBLE); + statusTextView.setText(getResources().getString(R.string.terrain_anchor_no_result_yet)); + }); + deadlineForMessageMillis = 0; + } + } } diff --git a/samples/geospatial_java/app/src/main/res/layout/activity_main.xml b/samples/geospatial_java/app/src/main/res/layout/activity_main.xml index 0c0c9ccc9..1a4efdce9 100644 --- a/samples/geospatial_java/app/src/main/res/layout/activity_main.xml +++ b/samples/geospatial_java/app/src/main/res/layout/activity_main.xml @@ -29,7 +29,7 @@ +