Commit 0c8f47ee authored by Piotr Bialecki's avatar Piotr Bialecki Committed by Commit Bot

WebXR - anchor and plane pose can be null coming from the device

Other changes:
- rename anchor and plane pose in mojo to mojo_from_xxxxxx to match convention
- adjust samples to account for the possibility that anchors and planes
  can have their poses unknown
- send null poses from device if tracking is paused
- ARCore device now does not treat planes and anchors whose tracking is
  paused as removed
- add DVLOGs all around to help with issue investigation
- add test page for experiments with local space stability & drift

Note: the test mentioned above is not exposed via proposals/index.html.
Change-Id: I786e86d69b69badbace57ce62585e3d5fd1ae756
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2130778Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarKlaus Weidner <klausw@chromium.org>
Commit-Queue: Piotr Bialecki <bialpio@chromium.org>
Cr-Commit-Position: refs/heads/master@{#757560}
parent c2bd3712
......@@ -28,9 +28,13 @@ ArCoreAnchorManager::ArCoreAnchorManager(util::PassKey<ArCoreImpl> pass_key,
ArCoreAnchorManager::~ArCoreAnchorManager() = default;
mojom::XRAnchorsDataPtr ArCoreAnchorManager::GetAnchorsData() const {
DVLOG(3) << __func__ << ": anchor_id_to_anchor_info_.size()="
<< anchor_id_to_anchor_info_.size()
<< ", updated_anchor_ids_.size()=" << updated_anchor_ids_.size();
std::vector<uint64_t> all_anchors_ids;
all_anchors_ids.reserve(anchor_id_to_anchor_object_.size());
for (const auto& anchor_id_and_object : anchor_id_to_anchor_object_) {
all_anchors_ids.reserve(anchor_id_to_anchor_info_.size());
for (const auto& anchor_id_and_object : anchor_id_to_anchor_info_) {
all_anchors_ids.push_back(anchor_id_and_object.first.GetUnsafeValue());
}
......@@ -38,18 +42,28 @@ mojom::XRAnchorsDataPtr ArCoreAnchorManager::GetAnchorsData() const {
updated_anchors.reserve(updated_anchor_ids_.size());
for (const auto& anchor_id : updated_anchor_ids_) {
const device::internal::ScopedArCoreObject<ArAnchor*>& anchor =
anchor_id_to_anchor_object_.at(anchor_id);
// pose
ArAnchor_getPose(arcore_session_, anchor.get(), ar_pose_.get());
mojom::Pose pose = GetMojomPoseFromArPose(arcore_session_, ar_pose_.get());
DVLOG(3) << __func__ << ": anchor id: " << anchor_id.GetUnsafeValue()
<< ", position=" << pose.position.ToString()
<< ", orientation=" << pose.orientation.ToString();
updated_anchors.push_back(mojom::XRAnchorData::New(
anchor_id.GetUnsafeValue(), device::mojom::Pose::New(pose)));
anchor_id_to_anchor_info_.at(anchor_id).anchor;
if (anchor_id_to_anchor_info_.at(anchor_id).tracking_state ==
AR_TRACKING_STATE_TRACKING) {
// pose
ArAnchor_getPose(arcore_session_, anchor.get(), ar_pose_.get());
mojom::Pose pose =
GetMojomPoseFromArPose(arcore_session_, ar_pose_.get());
DVLOG(3) << __func__ << ": anchor_id: " << anchor_id.GetUnsafeValue()
<< ", position=" << pose.position.ToString()
<< ", orientation=" << pose.orientation.ToString();
updated_anchors.push_back(mojom::XRAnchorData::New(
anchor_id.GetUnsafeValue(), device::mojom::Pose::New(pose)));
} else {
DVLOG(3) << __func__ << ": anchor_id: " << anchor_id.GetUnsafeValue()
<< ", position=untracked, orientation=untracked";
updated_anchors.push_back(
mojom::XRAnchorData::New(anchor_id.GetUnsafeValue(), nullptr));
}
}
return mojom::XRAnchorsData::New(std::move(all_anchors_ids),
......@@ -73,7 +87,7 @@ void ArCoreAnchorManager::ForEachArCoreAnchor(ArAnchorList* arcore_anchors,
ArTrackingState tracking_state;
ArAnchor_getTrackingState(arcore_session_, anchor.get(), &tracking_state);
if (tracking_state != ArTrackingState::AR_TRACKING_STATE_TRACKING) {
if (tracking_state == ArTrackingState::AR_TRACKING_STATE_STOPPED) {
// Skip all anchors that are not currently tracked.
continue;
}
......@@ -100,7 +114,7 @@ void ArCoreAnchorManager::Update(ArFrame* ar_frame) {
std::tie(anchor_id, created) = CreateOrGetAnchorId(ar_anchor.get());
DVLOG(3) << __func__
<< ": anchor updated, anchor id=" << anchor_id.GetUnsafeValue()
<< ": anchor updated, anchor_id=" << anchor_id.GetUnsafeValue()
<< ", tracking_state=" << tracking_state;
DCHECK(!created)
......@@ -118,44 +132,54 @@ void ArCoreAnchorManager::Update(ArFrame* ar_frame) {
// Collect the objects of all currently tracked anchors.
// |ar_plane_address_to_id_| should *not* grow.
std::map<AnchorId, device::internal::ScopedArCoreObject<ArAnchor*>>
anchor_id_to_anchor_object;
std::map<AnchorId, AnchorInfo> new_anchor_id_to_anchor_info;
ForEachArCoreAnchor(arcore_anchors_.get(), [this,
&anchor_id_to_anchor_object](
&new_anchor_id_to_anchor_info,
&updated_anchor_ids](
device::internal::
ScopedArCoreObject<
ArAnchor*> ar_anchor,
ArAnchor*> anchor,
ArTrackingState
tracking_state) {
// ID
AnchorId anchor_id;
bool created;
std::tie(anchor_id, created) = CreateOrGetAnchorId(ar_anchor.get());
std::tie(anchor_id, created) = CreateOrGetAnchorId(anchor.get());
DVLOG(3) << __func__
<< ": anchor present, anchor id=" << anchor_id.GetUnsafeValue()
<< ": anchor present, anchor_id=" << anchor_id.GetUnsafeValue()
<< ", tracking state=" << tracking_state;
DCHECK(!created)
<< "Anchor creation is app-initiated - we should never encounter an "
"anchor that was created outside of `ArCoreImpl::CreateAnchor()`.";
anchor_id_to_anchor_object[anchor_id] = std::move(ar_anchor);
// Inspect the tracking state of this anchor in the previous frame. If it
// changed, mark the anchor as updated.
if (base::Contains(anchor_id_to_anchor_info_, anchor_id) &&
anchor_id_to_anchor_info_.at(anchor_id).tracking_state !=
tracking_state) {
updated_anchor_ids.insert(anchor_id);
}
AnchorInfo new_anchor_info = AnchorInfo(std::move(anchor), tracking_state);
new_anchor_id_to_anchor_info.emplace(anchor_id, std::move(new_anchor_info));
});
DVLOG(3) << __func__ << ": anchor_id_to_anchor_object.size()="
<< anchor_id_to_anchor_object.size();
DVLOG(3) << __func__ << ": new_anchor_id_to_anchor_info.size()="
<< new_anchor_id_to_anchor_info.size();
// Shrink |ar_plane_address_to_id_|, removing all planes that are no longer
// tracked or were subsumed - if they do not show up in
// |plane_id_to_plane_object| map, they are no longer tracked.
base::EraseIf(
ar_anchor_address_to_id_,
[&anchor_id_to_anchor_object](const auto& anchor_address_and_id) {
return !base::Contains(anchor_id_to_anchor_object,
[&new_anchor_id_to_anchor_info](const auto& anchor_address_and_id) {
return !base::Contains(new_anchor_id_to_anchor_info,
anchor_address_and_id.second);
});
anchor_id_to_anchor_object_.swap(anchor_id_to_anchor_object);
anchor_id_to_anchor_info_.swap(new_anchor_id_to_anchor_info);
updated_anchor_ids_.swap(updated_anchor_ids);
}
......@@ -196,7 +220,8 @@ base::Optional<AnchorId> ArCoreAnchorManager::CreateAnchor(
DCHECK(created) << "This should always be a new anchor, not something we've "
"seen previously.";
anchor_id_to_anchor_object_[anchor_id] = std::move(ar_anchor);
anchor_id_to_anchor_info_.emplace(
anchor_id, AnchorInfo(std::move(ar_anchor), AR_TRACKING_STATE_TRACKING));
return anchor_id;
}
......@@ -222,38 +247,47 @@ base::Optional<AnchorId> ArCoreAnchorManager::CreateAnchor(
DCHECK(created) << "This should always be a new anchor, not something we've "
"seen previously.";
anchor_id_to_anchor_object_[anchor_id] = std::move(ar_anchor);
anchor_id_to_anchor_info_.emplace(
anchor_id, AnchorInfo(std::move(ar_anchor), AR_TRACKING_STATE_TRACKING));
return anchor_id;
}
void ArCoreAnchorManager::DetachAnchor(AnchorId anchor_id) {
auto it = anchor_id_to_anchor_object_.find(anchor_id);
if (it == anchor_id_to_anchor_object_.end()) {
auto it = anchor_id_to_anchor_info_.find(anchor_id);
if (it == anchor_id_to_anchor_info_.end()) {
return;
}
ArAnchor_detach(arcore_session_, it->second.get());
ArAnchor_detach(arcore_session_, it->second.anchor.get());
anchor_id_to_anchor_object_.erase(it);
anchor_id_to_anchor_info_.erase(it);
}
bool ArCoreAnchorManager::AnchorExists(AnchorId id) const {
return base::Contains(anchor_id_to_anchor_object_, id);
return base::Contains(anchor_id_to_anchor_info_, id);
}
base::Optional<gfx::Transform> ArCoreAnchorManager::GetMojoFromAnchor(
AnchorId id) const {
auto it = anchor_id_to_anchor_object_.find(id);
if (it == anchor_id_to_anchor_object_.end()) {
auto it = anchor_id_to_anchor_info_.find(id);
if (it == anchor_id_to_anchor_info_.end()) {
return base::nullopt;
}
ArAnchor_getPose(arcore_session_, it->second.get(), ar_pose_.get());
ArAnchor_getPose(arcore_session_, it->second.anchor.get(), ar_pose_.get());
mojom::Pose mojo_pose =
GetMojomPoseFromArPose(arcore_session_, ar_pose_.get());
return mojo::ConvertTo<gfx::Transform>(mojo_pose);
}
ArCoreAnchorManager::AnchorInfo::AnchorInfo(
device::internal::ScopedArCoreObject<ArAnchor*> anchor,
ArTrackingState tracking_state)
: anchor(std::move(anchor)), tracking_state(tracking_state) {}
ArCoreAnchorManager::AnchorInfo::AnchorInfo(AnchorInfo&& other) = default;
ArCoreAnchorManager::AnchorInfo::~AnchorInfo() = default;
} // namespace device
......@@ -49,9 +49,20 @@ class ArCoreAnchorManager {
void DetachAnchor(AnchorId anchor_id);
private:
struct AnchorInfo {
device::internal::ScopedArCoreObject<ArAnchor*> anchor;
ArTrackingState tracking_state;
AnchorInfo(device::internal::ScopedArCoreObject<ArAnchor*> anchor,
ArTrackingState tracking_state);
AnchorInfo(AnchorInfo&& other);
~AnchorInfo();
};
// Executes |fn| for each still tracked, anchor present in |arcore_anchors|.
// |fn| will receive a `device::internal::ScopedArCoreObject<ArAnchor*>` that
// can be stored, as well as ArTrackingState of the passed in anchor.
// can be stored, as well as ArTrackingState of the passed in anchor. An
// anchor is tracked if its state is not AR_TRACKING_STATE_STOPPED.
template <typename FunctionType>
void ForEachArCoreAnchor(ArAnchorList* arcore_anchors, FunctionType fn);
......@@ -72,10 +83,9 @@ class ArCoreAnchorManager {
// Mapping from anchor address to anchor ID. It should be modified only during
// calls to |Update()| and anchor creation.
std::map<void*, AnchorId> ar_anchor_address_to_id_;
// Mapping from anchor ID to ARCore anchor object. It should be modified only
// during calls to |Update()|.
std::map<AnchorId, device::internal::ScopedArCoreObject<ArAnchor*>>
anchor_id_to_anchor_object_;
// Mapping from anchor ID to ARCore anchor information. It should be modified
// only during calls to |Update()|.
std::map<AnchorId, AnchorInfo> anchor_id_to_anchor_info_;
// Set containing IDs of anchors updated in the last frame. It should be
// modified only during calls to |Update()|.
std::set<AnchorId> updated_anchor_ids_;
......
......@@ -63,10 +63,21 @@ class ArCorePlaneManager {
const device::mojom::Pose& pose) const;
private:
struct PlaneInfo {
device::internal::ScopedArCoreObject<ArTrackable*> plane;
ArTrackingState tracking_state;
PlaneInfo(device::internal::ScopedArCoreObject<ArTrackable*> plane,
ArTrackingState tracking_state);
PlaneInfo(PlaneInfo&& other);
~PlaneInfo();
};
// Executes |fn| for each still tracked, non-subsumed plane present in
// |arcore_planes|. |fn| will receive 3 parameters - a
// `ScopedArCoreObject<ArAnchor*>` that can be stored, the non-owning ArPlane*
// typecast from the first parameter, and ArTrackingState.
// typecast from the first parameter, and ArTrackingState. A plane is tracked
// if its state is not AR_TRACKING_STATE_STOPPED.
template <typename FunctionType>
void ForEachArCorePlane(ArTrackableList* arcore_planes, FunctionType fn);
......@@ -89,10 +100,9 @@ class ArCorePlaneManager {
// Mapping from plane address to plane ID. It should be modified only during
// calls to |Update()|.
std::map<void*, PlaneId> ar_plane_address_to_id_;
// Mapping from plane ID to ARCore plane object. It should be modified only
// during calls to |Update()|.
std::map<PlaneId, device::internal::ScopedArCoreObject<ArTrackable*>>
plane_id_to_plane_object_;
// Mapping from plane ID to ARCore plane information. It should be modified
// only during calls to |Update()|.
std::map<PlaneId, PlaneInfo> plane_id_to_plane_info_;
// Set containing IDs of planes updated in the last frame. It should be
// modified only during calls to |Update()|.
std::set<PlaneId> updated_plane_ids_;
......
......@@ -18,7 +18,7 @@ import "ui/gfx/mojom/transform.mojom";
//
// Note on terminology: unless otherwise noted, all poses passed across mojo are
// expressed in device space, aka mojo space.
// expressed in device space, aka mojo space, aka world space.
// TODO(https://crbug.com/966099): Use EnableIf to only define values on
// platforms that have implementations.
......@@ -376,7 +376,9 @@ struct XRPlaneData {
// Pose of the plane's center. Defines new coordinate space.
// Y axis of the coordinate space describes plane's normal, the rotation of
// X and Z around the Y axis is arbitrary.
Pose pose;
// Null if the device does not know where the plane is located in the world
// space (tracking loss), but the tracking can still be recovered.
Pose? mojo_from_plane;
// Vertices of 2D convex polygon approximating the plane.
array<XRPlanePointData> polygon;
......@@ -405,8 +407,10 @@ struct XRAnchorData {
// Unique (within a session) identifier of the anchor.
uint64 id;
// Pose of the anchor.
Pose pose;
// Pose of the anchor. Null if the device does not know where the anchor is
// located in the world space (tracking loss), but the tracking can still be
// recovered.
Pose? mojo_from_anchor;
};
// Struct containing information about all tracked & updated anchors in a given
......
......@@ -14,18 +14,20 @@ XRAnchor::XRAnchor(uint64_t id,
XRSession* session,
const device::mojom::blink::XRAnchorData& anchor_data)
: id_(id), session_(session) {
// No need for else - if pose is not present, the default-constructed unique
// ptr is fine.
if (anchor_data.pose) {
SetMojoFromAnchor(
mojo::ConvertTo<blink::TransformationMatrix>(anchor_data.pose));
// No need for else - if mojo_from_anchor is not present, the
// default-constructed unique ptr is fine. It would signify that the anchor
// exists and is tracked by the underlying system, but its current location is
// unknown.
if (anchor_data.mojo_from_anchor) {
SetMojoFromAnchor(mojo::ConvertTo<blink::TransformationMatrix>(
anchor_data.mojo_from_anchor));
}
}
void XRAnchor::Update(const device::mojom::blink::XRAnchorData& anchor_data) {
if (anchor_data.pose) {
SetMojoFromAnchor(
mojo::ConvertTo<blink::TransformationMatrix>(anchor_data.pose));
if (anchor_data.mojo_from_anchor) {
SetMojoFromAnchor(mojo::ConvertTo<blink::TransformationMatrix>(
anchor_data.mojo_from_anchor));
} else {
mojo_from_anchor_ = nullptr;
}
......@@ -36,8 +38,6 @@ uint64_t XRAnchor::id() const {
}
XRSpace* XRAnchor::anchorSpace() const {
DCHECK(mojo_from_anchor_);
if (!anchor_space_) {
anchor_space_ =
MakeGarbageCollected<XRObjectSpace<XRAnchor>>(session_, this);
......
......@@ -44,12 +44,8 @@ class XRAnchor : public ScriptWrappable {
Member<XRSession> session_;
// |mojo_from_anchor_| will be non-null in an XRAnchor after the anchor was
// updated for the first time - this *must* happen in the same frame in which
// the anchor was created for the anchor to be fully usable. It is currently
// ensured by XRSession - anchors that got created prior to receiving the
// result from mojo call to GetFrameData are not returned to the application
// until their poses are known.
// Anchor's pose in device (mojo) space. Nullptr if the pose of the anchor is
// unknown in the current frame.
std::unique_ptr<TransformationMatrix> mojo_from_anchor_;
// Cached anchor space - it will be created by `anchorSpace()` if it's not
......
......@@ -13,8 +13,14 @@ namespace blink {
class XRSession;
// Helper class that returns an XRSpace that tracks the position of object of
// type T (for example XRPlane, XRAnchor). The type T has to have a poseMatrix()
// method.
// type T (for example XRPlane, XRAnchor). The type T has to have a
// MojoFromObject() method, returning a base::Optional<TransformationMatrix>.
//
// If the object's MojoFromObject() method returns a base::nullopt, it means
// that the object is not localizable in the current frame (i.e. its pose is
// unknown) - the `frame.getPose(objectSpace, otherSpace)` will return null.
// That does not necessarily mean that object tracking is lost - it may be that
// the object's location will become known in subsequent frames.
template <typename T>
class XRObjectSpace : public XRSpace {
public:
......
......@@ -24,11 +24,13 @@ XRPlane::XRPlane(uint64_t id,
mojo::ConvertTo<HeapVector<Member<DOMPointReadOnly>>>(
plane_data.polygon),
timestamp) {
// No need for else - if pose is not present, the default-constructed unique
// ptr is fine.
if (plane_data.pose) {
SetMojoFromPlane(
mojo::ConvertTo<blink::TransformationMatrix>(plane_data.pose));
// No need for else - if mojo_from_plane is not present, the
// default-constructed unique ptr is fine. It would signify that the plane
// exists and is tracked by the underlying system, but its current location is
// unknown.
if (plane_data.mojo_from_plane) {
SetMojoFromPlane(mojo::ConvertTo<blink::TransformationMatrix>(
plane_data.mojo_from_plane));
}
}
......@@ -125,9 +127,9 @@ void XRPlane::Update(const device::mojom::blink::XRPlaneData& plane_data,
orientation_ = mojo::ConvertTo<base::Optional<blink::XRPlane::Orientation>>(
plane_data.orientation);
if (plane_data.pose) {
SetMojoFromPlane(
mojo::ConvertTo<blink::TransformationMatrix>(plane_data.pose));
if (plane_data.mojo_from_plane) {
SetMojoFromPlane(mojo::ConvertTo<blink::TransformationMatrix>(
plane_data.mojo_from_plane));
} else {
mojo_from_plane_ = nullptr;
}
......
......@@ -68,7 +68,8 @@ class XRPlane : public ScriptWrappable {
HeapVector<Member<DOMPointReadOnly>> polygon_;
base::Optional<Orientation> orientation_;
// Plane center's pose in device (mojo) space.
// Plane center's pose in device (mojo) space. Nullptr if the pose of the
// anchor is unknown in the current frame.
std::unique_ptr<TransformationMatrix> mojo_from_plane_;
Member<XRSession> session_;
......
......@@ -188,6 +188,10 @@ export class PlaneNode extends Node {
if(this.polygon)
throw new Error(`Polygon is set on a plane where it shouldn't be!`);
if(polygon.length === 0) {
return Promise.resolve();
}
this.createPlanePrimitive(polygon);
// eagerly clean up render primitive's VAO
......
......@@ -119,6 +119,10 @@ let calculateHitMatrix = function(ray_vector, plane_normal, point) {
// single plane hit test - doesn't take into account the plane's polygon
function hitTestPlane(frame, ray, plane, frameOfReference) {
const plane_pose = frame.getPose(plane.planeSpace, frameOfReference);
if(!plane_pose) {
return null;
}
const plane_normal = transform_point_by_matrix(
plane_pose.transform.matrix, {x : 0, y : 1.0, z : 0, w : 0});
const plane_center = normalize_perspective(
......
......@@ -431,8 +431,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
});
tracked_anchors.forEach(anchor => {
anchor.context.sceneObject.matrix = frame.getPose(anchor.anchorSpace, xrRefSpace).transform.matrix;
anchor.context.sceneObject.visible = true;
const anchorPose = frame.getPose(anchor.anchorSpace, xrRefSpace);
if(anchorPose) {
anchor.context.sceneObject.matrix = anchorPose.transform.matrix;
anchor.context.sceneObject.visible = true;
} else {
anchor.context.sceneObject.visible = false;
}
});
all_previous_anchors = tracked_anchors;
......
......@@ -261,8 +261,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
});
tracked_anchors.forEach(anchor => {
anchor.context.sceneObject.matrix = frame.getPose(anchor.anchorSpace, xrRefSpace).transform.matrix;
anchor.context.sceneObject.visible = true;
const anchorPose = frame.getPose(anchor.anchorSpace, xrRefSpace);
if(anchorPose) {
anchor.context.sceneObject.matrix = anchorPose.transform.matrix;
anchor.context.sceneObject.visible = true;
} else {
anchor.context.sceneObject.visible = false;
}
});
all_previous_anchors = tracked_anchors;
......@@ -274,25 +279,30 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
all_previous_anchors = new Set();
}
if(xrAnchor) {
if (xrAnchor) {
const anchorPose = frame.getPose(xrAnchor.anchorSpace, xrRefSpace);
const pos = anchorPose.transform.position;
const rot = anchorPose.transform.orientation;
const degs = getAngle(
quat.fromValues(rot.x, rot.y, rot.z, rot.w),
quat.create()
) * 180 / Math.PI;
anchorPoseElement.innerText = pos.x.toFixed(3) + "m,"
+ pos.y.toFixed(3) + "m,"
+ pos.z.toFixed(3) + "m,"
+ degs.toFixed(3) + "deg";
const drift = Math.sqrt(pos.x * pos.x + pos.y * pos.y + pos.z * pos.z);
anchorDriftElement.innerText = drift.toFixed(3) + "m";
console.debug(pos, rot, drift);
if (anchorPose) {
const pos = anchorPose.transform.position;
const rot = anchorPose.transform.orientation;
const degs = getAngle(
quat.fromValues(rot.x, rot.y, rot.z, rot.w),
quat.create()
) * 180 / Math.PI;
anchorPoseElement.innerText = pos.x.toFixed(3) + "m,"
+ pos.y.toFixed(3) + "m,"
+ pos.z.toFixed(3) + "m,"
+ degs.toFixed(3) + "deg";
const drift = Math.sqrt(pos.x * pos.x + pos.y * pos.y + pos.z * pos.z);
anchorDriftElement.innerText = drift.toFixed(3) + "m";
console.debug(pos, rot, drift);
} else {
anchorPoseElement.innerText = "Anchor pose null.";
anchorDriftElement.innerText = "Anchor pose null.";
}
} else if(anchorRemoved) {
anchorPoseElement.innerText = "Anchor already gone.";
anchorDriftElement.innerText = "Anchor already gone.";
......
......@@ -445,10 +445,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
planeFrameOfReference.addNode(zRay);
plane_node.addNode(planeFrameOfReference);
plane.scene_node = plane_node;
plane.scene_node.matrix = frame.getPose(plane.planeSpace, xrRefSpace).transform.matrix;
const planePose = frame.getPose(plane.planeSpace, xrRefSpace);
if (planePose) {
plane.scene_node.matrix = planePose.transform.matrix;
plane.scene_node.visible = true;
} else {
plane.scene_node.visible = false;
}
plane.extended_polygon = extendPolygon(plane.polygon);
plane.extended_polygon_node = new PlaneNode({
polygon : plane.extended_polygon,
......@@ -464,7 +469,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
{
// old plane that was updated in current frame
plane.scene_node.onPlaneChanged(plane.polygon);
plane.scene_node.matrix = frame.getPose(plane.planeSpace, xrRefSpace).transform.matrix;
const planePose = frame.getPose(plane.planeSpace, xrRefSpace);
if (planePose) {
plane.scene_node.matrix = planePose.transform.matrix;
plane.scene_node.visible = true;
} else {
plane.scene_node.visible = false;
}
plane.extended_polygon = extendPolygon(plane.polygon);
plane.extended_polygon_node.onPlaneChanged(plane.extended_polygon);
}
......@@ -526,8 +537,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
});
tracked_anchors.forEach(anchor => {
anchor.context.sceneObject.matrix = frame.getPose(anchor.anchorSpace, xrRefSpace).transform.matrix;
anchor.context.sceneObject.visible = true;
const anchorPose = frame.getPose(anchor.anchorSpace, xrRefSpace);
if (anchorPose) {
anchor.context.sceneObject.matrix = anchorPose.transform.matrix;
anchor.context.sceneObject.visible = true;
} else {
anchor.context.sceneObject.visible = false;
}
});
all_previous_anchors = tracked_anchors;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment