public class InstantPlacementPoint
Trackable Instant Placement point returned by Frame.hitTestInstantPlacement(float, float, float)
.
If ARCore has an accurate 3D pose for the InstantPlacementPoint
returned by Frame.hitTestInstantPlacement(float, float, float)
it will start with tracking method InstantPlacementPoint.TrackingMethod.FULL_TRACKING
. Otherwise, it will start with tracking method InstantPlacementPoint.TrackingMethod.SCREENSPACE_WITH_APPROXIMATE_DISTANCE
, and will transition to InstantPlacementPoint.TrackingMethod.FULL_TRACKING
once ARCore has an accurate 3D pose. Once the tracking method is InstantPlacementPoint.TrackingMethod.FULL_TRACKING
it will not revert to InstantPlacementPoint.TrackingMethod.SCREENSPACE_WITH_APPROXIMATE_DISTANCE
.
When the tracking method changes from InstantPlacementPoint.TrackingMethod.SCREENSPACE_WITH_APPROXIMATE_DISTANCE
in one frame to InstantPlacementPoint.TrackingMethod.FULL_TRACKING
in the next frame, the pose will jump from its initial location
based on the provided approximate distance to a new location at an accurate distance.
This instantaneous change in pose will change the apparent scale of any objects that are
anchored to the InstantPlacementPoint
. That is, an object will suddenly appear larger or
smaller than it was in the previous frame.
To avoid the visual jump due to the sudden change in apparent object scale, use the following procedure:
- Keep track of the pose and tracking method of the
InstantPlacementPoint
in each frame. - Wait for the tracking method to change to
InstantPlacementPoint.TrackingMethod.FULL_TRACKING
. - Use the pose from the previous frame and the pose in the current frame to determine the object's distance to the device in both frames.
- Calculate the apparent change in scale due to the change in distance from the camera.
- Adjust the scale of the object to counteract the perceived change in scale, so that visually the object does not appear to change in size.
- Optionally, smoothly adjust the scale of the object back to its original value over several frames.
The following snippet shows how to use Instant Placement to place one object. The wrapper below shows how to use steps 1 through 5 to avoid the visual jump.
class
ArPlacementActivity
{
private
Session
session
=
null
;
private
placementIsDone
=
false
;
public
void
createSession
()
{
session
=
new
Session
(
this
);
Config
config
=
new
Config
(
session
);
config
.
setInstantPlacementMode
(
InstantPlacementMode
.
LOCAL_Y_UP
);
session
.
configure
(
config
);
}
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 how we expect the app to be used by users.
float
approximateDistanceMeters
=
1.0f
;
List<HitResult>
results
=
frame
.
hitTestInstantPlacement
(
tapX
,
tapY
,
approximateDistanceMeters
);
if
(
!
results
.
isEmpty
())
{
HitResult
hit
=
results
.
get
(
0
);
InstantPlacementPoint
point
=
(
InstantPlacementPoint
)
hit
.
getTrackable
();
anchor
=
point
.
createAnchor
(
point
.
getPose
());
placementIsDone
=
true
;
disableInstantPlacement
();
}
}
}
private
void
disableInstantPlacement
()
{
// When the placement is done, you can disable Instant Placement to save computing.
Config
config
=
new
Config
(
session
);
config
.
setInstantPlacementMode
(
InstantPlacementMode
.
DISABLED
);
session
.
configure
(
config
);
}
}
This wrapper of InstantPlacementPoint can be used to offset the apparent scale shift that
occurs when the tracking method changes from InstantPlacementPoint.TrackingMethod.SCREENSPACE_WITH_APPROXIMATE_DISTANCE
to InstantPlacementPoint.TrackingMethod.FULL_TRACKING
.
For AR experiences where a sudden apparent scale change is acceptable, no wrapper is required.
class
WrappedInstantPlacement
{
public
InstantPlacementPoint
point
;
public
TrackingMethod
previousTrackingMethod
;
public
float
previousDistanceToCamera
;
public
float
scaleFactor
=
1.0f
;
public
WrappedInstantPlacement
(
InstantPlacementPoint
point
,
TrackingMethod
previousTrackingMethod
,
float
previousDistanceToCamera
)
{
this
.
point
=
point
;
this
.
previousTrackingMethod
=
previousTrackingMethod
;
this
.
previousDistanceToCamera
=
previousDistanceToCamera
;
}
}
ArrayList<WrappedInstantPlacement>
wrappedPoints
=
new
ArrayList<WrappedInstantPlacement>
();
public
void
onDrawFrame
(
GL10
gl
)
{
Frame
frame
=
session
.
update
();
// Place an object on tap.
if
(
didUserTap
())
{
// Use estimated distance from the user's device to the real world, based
// on how we expect the app to be used by users.
float
approximateDistanceMeters
=
2.0f
;
// Returns a single result if the hit test was successful.
List<HitResult>
results
=
frame
.
hitTestInstantPlacement
(
tapX
,
tapY
,
approximateDistanceMeters
);
for
(
HitResult
hit
:
results
)
{
InstantPlacementPoint
point
=
(
InstantPlacementPoint
)
hit
.
getTrackable
();
wrappedPoints
.
add
(
new
WrappedInstantPlacement
(
point
,
point
.
getTrackingMethod
(),
distance
(
camera
.
getPose
(),
point
.
getPose
())));
}
}
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 estimated depth and pose. Record distance to 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
.
previousPoseType
==
TrackingMethod
.
SCREENSPACE_WITH_APPROXIMATE_DISTANCE
)
{
// Transition from estimated pose to real pose. Adjust object scale to
// counter-act apparent change is size due to pose jump.
wrappedPoint
.
scaleFactor
=
distance
(
point
.
getPose
(),
camera
.
getPose
())
/
wrappedPoint
.
previousDistanceToCamera
);
// TODO: Apply the scale factor to the model.
// ...
previousPoseType
=
TrackingMethod
.
FULL_TRACKING
;
}
}
}
}
Nested Classes
Public Methods
Anchor
|
createAnchor
( Pose
pose)
Creates an anchor that is attached to this trackable, using the given initial pose in the world
coordinate space.
|
boolean
|
|
Collection
< Anchor
>
|
getAnchors
()
Gets the Anchors attached to this trackable.
|
Pose
|
getPose
()
Gets the pose of the Instant Placement point.
|
InstantPlacementPoint.TrackingMethod
|
|
TrackingState
|
|
int
|
hashCode
()
Returns a hash code value for the object.
|
Inherited Methods
Public Methods
public Anchor createAnchor ( Pose pose)
createAnchor
public Anchor createAnchor ( Pose pose )
Creates an anchor that is attached to this trackable, using the given initial pose in the world coordinate space. The type of trackable will determine the semantics of attachment and how the anchor's pose will be updated to maintain this relationship. Note that the relative offset between the pose of multiple anchors attached to a trackable may adjust slightly over time as ARCore updates its model of the world.
pose
public boolean equals ( Object obj)
equals
public boolean equals ( Object obj )
Indicates whether some other object is a Trackable
referencing the same logical
trackable as this one.
obj
true
if this object is the same as the obj argument; false
otherwise.public Collection < Anchor > getAnchors ()
getAnchors
public Collection < Anchor > getAnchors ()
Gets the Anchors attached to this trackable.
public Pose getPose ()
getPose
public Pose getPose ()
Gets the pose of the Instant Placement point. Use getTrackingMethod()
to determine
whether depth and scale are accurate or are based on the estimated depth provided to Frame.hitTestInstantPlacement(float, float, float)
.
If the tracking method is InstantPlacementPoint.TrackingMethod.SCREENSPACE_WITH_APPROXIMATE_DISTANCE
, the
pose will be based on the approximate distance provided to Frame.hitTestInstantPlacement(float, float, float)
.
When the tracking method changes from InstantPlacementPoint.TrackingMethod.SCREENSPACE_WITH_APPROXIMATE_DISTANCE
to InstantPlacementPoint.TrackingMethod.FULL_TRACKING
,
there will be a noticeable pose jump as the depth changes, from one that's estimated based on
the approximate distance provided to Frame.hitTestInstantPlacement(float, float, float)
to the actual distance as determined by ARCore.
Consequently, the on-screen size, or apparent scale, of any object anchored to the pose will
appear to change abruptly. To prevent a visible pop in 3D asset size when the tracking method
changes, the scale of the object can be adjusted to counteract the apparent scale change when
the tracking method changes. See the InstantPlacementPoint
class-level documentation
for an example.
public InstantPlacementPoint.TrackingMethod getTrackingMethod ()
getTrackingMethod
public InstantPlacementPoint . TrackingMethod getTrackingMethod ()
Returns the current InstantPlacementPoint.TrackingMethod
for this InstantPlacementPoint
.
public TrackingState getTrackingState ()
getTrackingState
public TrackingState getTrackingState ()
Gets this trackable's TrackingState
.
public int hashCode ()
hashCode
public int hashCode ()
Returns a hash code value for the object. This method is supported for the benefit of hash
tables such as those provided by HashMap
.