Instant Placement developer guide for Android

Learn how to use the Instant Placement API in your own apps.

Prerequisites

Make sure that you understand fundamental AR concepts and how to configure an ARCore session before proceeding.

Configure a new session with Instant Placement

In a new ARCore session, enable Instant Placement mode .

Java

  // Create the ARCore session. 
 public 
  
 void 
  
 createSession 
 () 
  
 { 
  
 session 
  
 = 
  
 new 
  
 Session 
 ( 
 applicationContext 
 ); 
  
 Config 
  
 config 
  
 = 
  
 new 
  
 Config 
 ( 
 session 
 ); 
  
 // Set the Instant Placement mode. 
  
 config 
 . 
 setInstantPlacementMode 
 ( 
 InstantPlacementMode 
 . 
 LOCAL_Y_UP 
 ); 
  
 session 
 . 
 configure 
 ( 
 config 
 ); 
 } 
 

Kotlin

  // Create the ARCore session. 
 fun 
  
 createSession 
 () 
  
 { 
  
 session 
  
 = 
  
 Session 
 ( 
 applicationContext 
 ); 
  
 val 
  
 config 
  
 = 
  
 Config 
 ( 
 session 
 ) 
  
 // Set the Instant Placement mode. 
  
 config 
 . 
 instantPlacementMode 
  
 = 
  
 Config 
 . 
 InstantPlacementMode 
 . 
 LOCAL_Y_UP 
  
 session 
 . 
 configure 
 ( 
 config 
 ) 
 } 
 

Place an object

Use Frame.hitTestInstantPlacement() to create a trackable Instant Placement point given a screen tap position. Retrieve the current pose with the getPose() method.

Java

  private 
  
 placementIsDone 
  
 = 
  
 false 
 ; 
 public 
  
 void 
  
 onDrawFrame 
 ( 
 GL10 
  
 gl 
 ) 
  
 { 
  
 Frame 
  
 frame 
  
 = 
  
 session 
 . 
 update 
 (); 
  
 // Place an object on tap. 
  
 if 
  
 ( 
 ! 
 placementIsDone 
 && 
 didUserTap 
 ()) 
  
 { 
  
 // Use estimated distance from the user's device to the real world, based 
  
 // on expected user interaction and behavior. 
  
 float 
  
 approximateDistanceMeters 
  
 = 
  
 2.0f 
 ; 
  
 // Performs a ray cast given a screen tap position. 
  
 List<HitResult> 
  
 results 
  
 = 
  
 frame 
 . 
 hitTestInstantPlacement 
 ( 
 tapX 
 , 
  
 tapY 
 , 
  
 approximateDistanceMeters 
 ); 
  
 if 
  
 ( 
 ! 
 results 
 . 
 isEmpty 
 ()) 
  
 { 
  
 InstantPlacementPoint 
  
 point 
  
 = 
  
 ( 
 InstantPlacementPoint 
 ) 
  
 results 
 . 
 get 
 ( 
 0 
 ). 
 getTrackable 
 (); 
  
 // Create an Anchor from the point's pose. 
  
 Anchor 
  
 anchor 
  
 = 
  
 point 
 . 
 createAnchor 
 ( 
 point 
 . 
 getPose 
 ()); 
  
 placementIsDone 
  
 = 
  
 true 
 ; 
  
 disableInstantPlacement 
 (); 
  
 } 
  
 } 
 } 
 

Kotlin

  var 
  
 placementIsDone 
  
 = 
  
 false 
 ; 
 fun 
  
 onDrawFrame 
 ( 
 gl 
 : 
  
 GL10 
 ) 
  
 { 
  
 val 
  
 frame 
  
 = 
  
 session 
 . 
 update 
 (); 
  
 // Place an object on tap. 
  
 if 
  
 ( 
 ! 
 placementIsDone 
 && 
 didUserTap 
 ()) 
  
 { 
  
 // Use estimated distance from the user's device to the real world, based 
  
 // on expected user interaction and behavior. 
  
 val 
  
 approximateDistanceMeters 
  
 = 
  
 2.0f 
 ; 
  
 // Performs a ray cast given a screen tap position. 
  
 val 
  
 results 
  
 = 
  
 frame 
 . 
 hitTestInstantPlacement 
 ( 
 tapX 
 , 
  
 tapY 
 , 
  
 approximateDistanceMeters 
 ) 
  
 if 
  
 ( 
 results 
 . 
 isNotEmpty 
 ()) 
  
 { 
  
 val 
  
 point 
  
 = 
  
 results 
 [ 
 0 
 ] 
 . 
 trackable 
  
 as 
  
 InstantPlacementPoint 
  
 // Create an Anchor from the point's pose. 
  
 val 
  
 anchor 
  
 = 
  
 point 
 . 
 createAnchor 
 ( 
 point 
 . 
 pose 
 ) 
  
 placementIsDone 
  
 = 
  
 true 
  
 disableInstantPlacement 
 () 
  
 } 
  
 } 
 } 
 

Instant Placement supports screen space tracking with approximate distance , automatically switching to full tracking once the Instant Placement point is anchored in the real world. Retrieve the current pose with getPose() . Get the current tracking method with getTrackingMethod() .

Although ARCore can perform Instant Placement hit tests against surfaces of any orientation, hit results will always return a pose with +Y up, against the direction of gravity. On horizontal surfaces, hit tests return accurate positions much faster.

Smooth the tracking method transition

When true depth becomes available, ARCore will change a InstantPlacementPoint 's tracking method from SCREENSPACE_WITH_APPROXIMATE_DISTANCE to FULL_TRACKING . The point's pose will also change to reflect true depth. This may lead to the object appearing to suddenly grow or shrink. To avoid this sudden change, add an InstantPlacementPoint wrapper.

Java

  // Wrapper class to track state to reduce sudden visual changes in object size 
 class 
 WrappedInstantPlacement 
  
 { 
  
 public 
  
 InstantPlacementPoint 
  
 point 
 ; 
  
 public 
  
 InstantPlacementPoint 
 . 
 TrackingMethod 
  
 previousTrackingMethod 
 ; 
  
 public 
  
 float 
  
 previousDistanceToCamera 
 ; 
  
 public 
  
 float 
  
 scaleFactor 
  
 = 
  
 1.0f 
 ; 
  
 public 
  
 WrappedInstantPlacement 
 ( 
  
 InstantPlacementPoint 
  
 point 
 , 
  
 InstantPlacementPoint 
 . 
 TrackingMethod 
  
 previousTrackingMethod 
 , 
  
 float 
  
 previousDistanceToCamera 
 ) 
  
 { 
  
 this 
 . 
 point 
  
 = 
  
 point 
 ; 
  
 this 
 . 
 previousTrackingMethod 
  
 = 
  
 previousTrackingMethod 
 ; 
  
 this 
 . 
 previousDistanceToCamera 
  
 = 
  
 previousDistanceToCamera 
 ; 
  
 } 
 } 
 

Kotlin

  // Wrapper class to track state to reduce sudden visual changes in object size 
 class 
  
 WrappedInstantPlacement 
 ( 
  
 var 
  
 point 
 : 
  
 InstantPlacementPoint 
 , 
  
 var 
  
 previousTrackingMethod 
 : 
  
 InstantPlacementPoint 
 . 
 TrackingMethod 
 , 
  
 var 
  
 previousDistanceToCamera 
 : 
  
 Float 
 , 
  
 var 
  
 scaleFactor 
 : 
  
 Float 
  
 = 
  
 1.0f 
 ) 
 

Then, add the following to your activity.

Java

  List<WrappedInstantPlacement> 
  
 wrappedPoints 
  
 = 
  
 new 
  
 ArrayList 
<> (); 
 public 
  
 void 
  
 onDrawFrame 
 ( 
 GL10 
  
 gl 
 ) 
  
 { 
  
 Frame 
  
 frame 
  
 = 
  
 session 
 . 
 update 
 (); 
  
 Camera 
  
 camera 
  
 = 
  
 frame 
 . 
 getCamera 
 (); 
  
 // Place an object on tap. 
  
 if 
  
 ( 
 didUserTap 
 ()) 
  
 { 
  
 // Instant Placement should only be applied if no results are available through hitTest. 
  
 List<HitResult> 
  
 results 
  
 = 
  
 frame 
 . 
 hitTest 
 ( 
 tapX 
 , 
  
 tapY 
 ); 
  
 if 
  
 ( 
 results 
 . 
 isEmpty 
 ()) 
  
 { 
  
 // Use the estimated distance from the user's device to the closest 
  
 // available surface, based on expected user interaction and behavior. 
  
 float 
  
 approximateDistanceMeters 
  
 = 
  
 2.0f 
 ; 
  
 // Returns a single result if the hit test was successful. 
  
 results 
  
 = 
  
 frame 
 . 
 hitTestInstantPlacement 
 ( 
 tapX 
 , 
  
 tapY 
 , 
  
 approximateDistanceMeters 
 ); 
  
 if 
  
 ( 
 ! 
 results 
 . 
 isEmpty 
 ()) 
  
 { 
  
 // Instant placement was successful. 
  
 InstantPlacementPoint 
  
 point 
  
 = 
  
 ( 
 InstantPlacementPoint 
 ) 
  
 results 
 . 
 get 
 ( 
 0 
 ). 
 getTrackable 
 (); 
  
 wrappedPoints 
 . 
 add 
 ( 
 new 
  
 WrappedInstantPlacement 
 ( 
 point 
 , 
  
 point 
 . 
 getTrackingMethod 
 (), 
  
 distance 
 ( 
 camera 
 . 
 getPose 
 (), 
  
 point 
 . 
 getPose 
 ()))); 
  
 } 
  
 } 
  
 else 
  
 { 
  
 // results contain valid hit tests which can be used directly, so instant placement is not required. 
  
 } 
  
 } 
  
 for 
  
 ( 
 WrappedInstantPlacement 
  
 wrappedPoint 
  
 : 
  
 wrappedPoints 
 ) 
  
 { 
  
 InstantPlacementPoint 
  
 point 
  
 = 
  
 wrappedPoint 
 . 
 point 
 ; 
  
 if 
  
 ( 
 point 
 . 
 getTrackingState 
 () 
  
 == 
  
 TrackingState 
 . 
 STOPPED 
 ) 
  
 { 
  
 wrappedPoints 
 . 
 remove 
 ( 
 wrappedPoint 
 ); 
  
 continue 
 ; 
  
 } 
  
 if 
  
 ( 
 point 
 . 
 getTrackingState 
 () 
  
 == 
  
 TrackingState 
 . 
 PAUSED 
 ) 
  
 { 
  
 continue 
 ; 
  
 } 
  
 if 
  
 ( 
 point 
 . 
 getTrackingMethod 
 () 
  
 == 
  
 TrackingMethod 
 . 
 SCREENSPACE_WITH_APPROXIMATE_DISTANCE 
 ) 
  
 { 
  
 // Continue to use the estimated depth and pose. Record the distance to 
  
 // the camera for use in the next frame if the transition to full 
  
 // tracking happens. 
  
 wrappedPoint 
 . 
 previousDistanceToCamera 
  
 = 
  
 distance 
 ( 
 point 
 . 
 getPose 
 (), 
  
 camera 
 . 
 getPose 
 ()); 
  
 } 
  
 else 
  
 if 
  
 ( 
 point 
 . 
 getTrackingMethod 
 () 
  
 == 
  
 TrackingMethod 
 . 
 FULL_TRACKING 
 ) 
  
 { 
  
 if 
  
 ( 
 wrappedPoint 
 . 
 previousTrackingMethod 
  
 == 
  
 TrackingMethod 
 . 
 SCREENSPACE_WITH_APPROXIMATE_DISTANCE 
 ) 
  
 { 
  
 // Change from the estimated pose to the accurate pose. Adjust the 
  
 // object scale to counteract the apparent change due to pose jump. 
  
 wrappedPoint 
 . 
 scaleFactor 
  
 = 
  
 distance 
 ( 
 point 
 . 
 getPose 
 (), 
  
 camera 
 . 
 getPose 
 ()) 
  
 / 
  
 wrappedPoint 
 . 
 previousDistanceToCamera 
 ; 
  
 // Apply the scale factor to the model. 
  
 // ... 
  
 wrappedPoint 
 . 
 previousTrackingMethod 
  
 = 
  
 TrackingMethod 
 . 
 FULL_TRACKING 
 ; 
  
 } 
  
 } 
  
 } 
 } 
 float 
  
 distance 
 ( 
 Pose 
  
 p 
 , 
  
 Pose 
  
 q 
 ) 
  
 { 
  
 return 
  
 Math 
 . 
 sqrt 
 ( 
 Math 
 . 
 pow 
 ( 
 p 
 . 
 tx 
 () 
  
 - 
  
 q 
 . 
 tx 
 (), 
  
 2 
 ) 
  
 + 
  
 Math 
 . 
 pow 
 ( 
 p 
 . 
 ty 
 () 
  
 - 
  
 q 
 . 
 ty 
 (), 
  
 2 
 ) 
  
 + 
  
 Math 
 . 
 pow 
 ( 
 p 
 . 
 tz 
 () 
  
 - 
  
 q 
 . 
 tz 
 (), 
  
 2 
 )); 
 } 
 

Kotlin

  var 
  
 wrappedPoints 
  
 = 
  
 mutableListOf<WrappedInstantPlacement> 
 () 
 fun 
  
 onDrawFrame 
 ( 
 gl 
 : 
  
 GL10?) 
  
 { 
  
 val 
  
 frame 
  
 = 
  
 session 
 . 
 update 
 () 
  
 val 
  
 camera 
  
 = 
  
 frame 
 . 
 camera 
  
 // Place an object on tap. 
  
 if 
  
 ( 
 didUserTap 
 ()) 
  
 { 
  
 // Instant Placement should only be applied if no results are available through hitTest. 
  
 var 
  
 results 
  
 = 
  
 frame 
 . 
 hitTest 
 ( 
 tapX 
 , 
  
 tapY 
 ); 
  
 if 
  
 ( 
 results 
 . 
 isEmpty 
 ()) 
  
 { 
  
 // Use the estimated distance from the user's device to the closest 
  
 // available surface, based on expected user interaction and behavior. 
  
 val 
  
 approximateDistanceMeters 
  
 = 
  
 2.0f 
 ; 
  
 // Returns a single result if the hit test was successful. 
  
 results 
  
 = 
  
 frame 
 . 
 hitTestInstantPlacement 
 ( 
 tapX 
 , 
  
 tapY 
 , 
  
 approximateDistanceMeters 
 ); 
  
 if 
  
 ( 
 results 
 . 
 isNotEmpty 
 ()) 
  
 { 
  
 // Instant placement was successful. 
  
 val 
  
 point 
  
 = 
  
 results 
 [ 
 0 
 ] 
 . 
 trackable 
  
 as 
  
 InstantPlacementPoint 
  
 val 
  
 wrapped 
  
 = 
  
 WrappedInstantPlacement 
 ( 
 point 
 , 
  
 point 
 . 
 trackingMethod 
 , 
  
 point 
 . 
 pose 
 . 
 distance 
 ( 
 camera 
 . 
 pose 
 )) 
  
 wrappedPoints 
 . 
 add 
 ( 
 wrapped 
 ) 
  
 } 
  
 } 
  
 else 
  
 { 
  
 // Results contain valid hit tests which can be used directly, so Instant Placement 
  
 // is not required. 
  
 } 
  
 } 
  
 loop@ 
  
 for 
  
 ( 
 wrappedPoint 
  
 in 
  
 wrappedPoints 
 ) 
  
 { 
  
 val 
  
 point 
  
 = 
  
 wrappedPoint 
 . 
 point 
  
 when 
  
 { 
  
 point 
 . 
 trackingState 
  
 == 
  
 TrackingState 
 . 
 STOPPED 
  
 - 
>  
 { 
  
 wrappedPoints 
 . 
 remove 
 ( 
 wrappedPoint 
 ) 
  
 continue 
 @loop 
  
 } 
  
 point 
 . 
 trackingState 
  
 == 
  
 TrackingState 
 . 
 PAUSED 
  
 - 
>  
 continue 
 @loop 
  
 point 
 . 
 trackingMethod 
  
 == 
  
 TrackingMethod 
 . 
 SCREENSPACE_WITH_APPROXIMATE_DISTANCE 
  
 - 
>  
 { 
  
 // Continue to use the estimated depth and pose. Record the distance to 
  
 // the camera for use in the next frame if the transition to full 
  
 // tracking happens. 
  
 wrappedPoint 
 . 
 previousDistanceToCamera 
  
 = 
  
 point 
 . 
 pose 
 . 
 distance 
 ( 
 camera 
 . 
 pose 
 ) 
  
 } 
  
 wrappedPoint 
 . 
 previousTrackingMethod 
  
 == 
  
 TrackingMethod 
 . 
 SCREENSPACE_WITH_APPROXIMATE_DISTANCE 
  
&&  
 point 
 . 
 trackingMethod 
  
 == 
  
 TrackingMethod 
 . 
 FULL_TRACKING 
  
 - 
>  
 { 
  
 // Change from the estimated pose to the accurate pose. Adjust the 
  
 // object scale to counteract the apparent change due to pose jump. 
  
 wrappedPoint 
 . 
 scaleFactor 
  
 = 
  
 point 
 . 
 pose 
 . 
 distance 
 ( 
 camera 
 . 
 pose 
 ) 
  
 / 
  
 wrappedPoint 
 . 
 previousDistanceToCamera 
  
 // Apply the scale factor to the model. 
  
 // ... 
  
 wrappedPoint 
 . 
 previousTrackingMethod 
  
 = 
  
 TrackingMethod 
 . 
 FULL_TRACKING 
  
 } 
  
 } 
  
 } 
 } 
 fun 
  
 Pose 
 . 
 distance 
 ( 
 other 
 : 
  
 Pose 
 ) 
  
 = 
  
 sqrt 
 ( 
  
 ( 
 tx 
 () 
  
 - 
  
 other 
 . 
 tx 
 ()). 
 pow 
 ( 
 2.0f 
 ) 
  
 + 
  
 ( 
 ty 
 () 
  
 - 
  
 other 
 . 
 ty 
 ()). 
 pow 
 ( 
 2.0f 
 ) 
  
 + 
  
 ( 
 tz 
 () 
  
 - 
  
 other 
 . 
 tz 
 ()). 
 pow 
 ( 
 2.0f 
 ) 
 ) 
 

Increase efficiency after object placement

Disable Instant Placement when the object is correctly placed to save CPU cycles and power.

Java

  void 
  
 disableInstantPlacement 
 () 
  
 { 
  
 Config 
  
 config 
  
 = 
  
 new 
  
 Config 
 ( 
 session 
 ); 
  
 config 
 . 
 setInstantPlacementMode 
 ( 
 Config 
 . 
 InstantPlacementMode 
 . 
 DISABLED 
 ); 
  
 session 
 . 
 configure 
 ( 
 config 
 ); 
 } 
 

Kotlin

  fun 
  
 disableInstantPlacement 
 () 
  
 { 
  
 val 
  
 config 
  
 = 
  
 Config 
 ( 
 session 
 ) 
  
 // Set the Instant Placement mode. 
  
 config 
 . 
 instantPlacementMode 
  
 = 
  
 Config 
 . 
 InstantPlacementMode 
 . 
 DISABLED 
  
 session 
 . 
 configure 
 ( 
 config 
 ) 
 } 
 
Design a Mobile Site
View Site in Mobile | Classic
Share by: