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
enum
|
InstantPlacementPoint.TrackingMethod |
Tracking methods for InstantPlacementPoint . |
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
|
getTrackingMethod()
Returns the current
InstantPlacementPoint.TrackingMethod for this InstantPlacementPoint . |
TrackingState
|
getTrackingState()
Gets this trackable's
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.
Details | |||
---|---|---|---|
Parameters |
|
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.
Details | |||
---|---|---|---|
Parameters |
|
||
Returns | true if this object is the same as the obj argument; false otherwise. |
||
See Also |
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
.
Details | |
---|---|
Returns | a hash code value for this object. |
See Also |