0

WebXR - anchors - fix anchor creation from hit test

Anchor creation based off of hit test result was incorrectly using
unstable native origin (planes' origins may change diametrically from
frame to frame) - this CL fixes the issue. Additionally, hit test logic
did not correctly treat hit test results as computed based off of plane
intersection - the issue did not cause any problems with hit test API,
but is problematic for anchor creation API.

Changes:
- plane-attached anchor creation now accepts native origin information
and pose relative to passed in native origin - this is done to ensure
that anchor creation uses a frame of reference that is stable w.r.t.
the environment (plane pose is not a correct choice as it changes when
plane extents are changing)
- fixed an issue in ArCoreImpl::RequestHitTest() - it would not report
results as computed based off of a plane even if they were
- mojom's hit test result now uses pose instead of matrix - pose is
directly provided by ARCore SDK and has smaller cognitive load as it
does not require considering column-major vs. row-major memory layouts
- IDL - anchor creation based on hit test result and on plane no longer
accepts initial pose since the spec draft has changed - initial pose
was considered confusing and unnecessary since it did not extend the
capabilities of the API
- JS-exposed anchor creation from XRHitTestResult and from XRPlane no
longer accepts an XRRigidTransform - the spec draft was already changed
to account for this

All other changes (parameter renames, comment updates, fixing call
sites to account for parameter count changes, etc.) are related to
the above major changes.

Change-Id: I5acb872c5a9d9003f1f85173edd82e6e6fa002bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2236592
Commit-Queue: Piotr Bialecki <bialpio@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/master@{#777463}
This commit is contained in:
Piotr Bialecki
2020-06-11 20:14:07 +00:00
committed by Commit Bot
parent 09012467f8
commit 828ed3231d
19 changed files with 243 additions and 158 deletions

@ -114,9 +114,11 @@ class ArCore {
// Creates plane-attached anchor. This call will be deferred and the actual
// call may be postponed until ARCore is in correct state and the pose of
// the plane is known.
virtual void CreatePlaneAttachedAnchor(const mojom::Pose& plane_from_anchor,
uint64_t plane_id,
CreateAnchorCallback callback) = 0;
virtual void CreatePlaneAttachedAnchor(
const mojom::XRNativeOriginInformation& native_origin_information,
const mojom::Pose& native_origin_from_anchor,
uint64_t plane_id,
CreateAnchorCallback callback) = 0;
// Starts processing anchor creation requests created by calls to
// |CreateAnchor()| & |CreatePlaneAttachedAnchor()| (see above). It should be

@ -797,14 +797,19 @@ void ArCoreGl::CreateAnchor(
std::move(callback));
}
void ArCoreGl::CreatePlaneAnchor(mojom::PosePtr plane_from_anchor,
uint64_t plane_id,
CreatePlaneAnchorCallback callback) {
void ArCoreGl::CreatePlaneAnchor(
mojom::XRNativeOriginInformationPtr native_origin_information,
mojom::PosePtr native_origin_from_anchor,
uint64_t plane_id,
CreatePlaneAnchorCallback callback) {
DVLOG(2) << __func__ << ": plane_id=" << plane_id;
DCHECK(plane_from_anchor);
DCHECK(native_origin_information);
DCHECK(native_origin_from_anchor);
DCHECK(plane_id);
arcore_->CreatePlaneAttachedAnchor(*plane_from_anchor, plane_id,
arcore_->CreatePlaneAttachedAnchor(*native_origin_information,
*native_origin_from_anchor, plane_id,
std::move(callback));
}

@ -129,9 +129,11 @@ class ArCoreGl : public mojom::XRFrameDataProvider,
mojom::XRNativeOriginInformationPtr native_origin_information,
mojom::PosePtr native_origin_from_anchor,
CreateAnchorCallback callback) override;
void CreatePlaneAnchor(mojom::PosePtr anchor_pose,
uint64_t plane_id,
CreatePlaneAnchorCallback callback) override;
void CreatePlaneAnchor(
mojom::XRNativeOriginInformationPtr native_origin_information,
mojom::PosePtr native_origin_from_anchor,
uint64_t plane_id,
CreatePlaneAnchorCallback callback) override;
void DetachAnchor(uint64_t anchor_id) override;

@ -647,6 +647,11 @@ ArCoreImpl::GetHitTestSubscriptionResults(
mojom::XRHitTestSubscriptionResultsDataPtr result =
mojom::XRHitTestSubscriptionResultsData::New();
DVLOG(3) << __func__
<< ": calculating hit test subscription results, "
"hit_test_subscription_id_to_data_.size()="
<< hit_test_subscription_id_to_data_.size();
for (auto& subscription_id_and_data : hit_test_subscription_id_to_data_) {
// First, check if we can find the current transformation for a ray. If not,
// skip processing this subscription.
@ -666,17 +671,23 @@ ArCoreImpl::GetHitTestSubscriptionResults(
*maybe_mojo_from_native_origin));
}
for (const auto& subscribtion_id_and_data :
DVLOG(3)
<< __func__
<< ": calculating hit test subscription results for transient input, "
"hit_test_subscription_id_to_transient_hit_test_data_.size()="
<< hit_test_subscription_id_to_transient_hit_test_data_.size();
for (const auto& subscription_id_and_data :
hit_test_subscription_id_to_transient_hit_test_data_) {
auto input_source_ids_and_transforms =
GetMojoFromInputSources(subscribtion_id_and_data.second.profile_name,
GetMojoFromInputSources(subscription_id_and_data.second.profile_name,
mojo_from_viewer, input_state);
result->transient_input_results.push_back(
GetTransientHitTestSubscriptionResult(
HitTestSubscriptionId(subscribtion_id_and_data.first),
*subscribtion_id_and_data.second.ray,
subscribtion_id_and_data.second.entity_types,
HitTestSubscriptionId(subscription_id_and_data.first),
*subscription_id_and_data.second.ray,
subscription_id_and_data.second.entity_types,
input_source_ids_and_transforms));
}
@ -954,9 +965,10 @@ bool ArCoreImpl::RequestHitTest(
// Only consider trackables listed in arcore_entity_types.
if (!base::Contains(arcore_entity_types, ar_trackable_type)) {
DVLOG(2)
<< __func__
<< ": hit a trackable that is not in entity types set, ignoring it";
DVLOG(2) << __func__
<< ": hit a trackable that is not in entity types set, ignoring "
"it. ar_trackable_type="
<< ar_trackable_type;
continue;
}
@ -976,16 +988,19 @@ bool ArCoreImpl::RequestHitTest(
// within the actual detected polygon and not just within than the larger
// plane.
uint64_t plane_id = 0;
if (!hit_results->empty() && ar_trackable_type == AR_TRACKABLE_PLANE) {
int32_t in_polygon = 0;
if (ar_trackable_type == AR_TRACKABLE_PLANE) {
ArPlane* ar_plane = ArAsPlane(ar_trackable.get());
ArPlane_isPoseInPolygon(arcore_session_.get(), ar_plane,
arcore_pose.get(), &in_polygon);
if (!in_polygon) {
DVLOG(2) << __func__
<< ": hit a trackable that is not within detected polygon, "
"ignoring it";
continue;
if (!hit_results->empty()) {
int32_t in_polygon = 0;
ArPlane_isPoseInPolygon(arcore_session_.get(), ar_plane,
arcore_pose.get(), &in_polygon);
if (!in_polygon) {
DVLOG(2) << __func__
<< ": hit a trackable that is not within detected polygon, "
"ignoring it";
continue;
}
}
base::Optional<PlaneId> maybe_plane_id =
@ -995,24 +1010,27 @@ bool ArCoreImpl::RequestHitTest(
}
}
std::array<float, 16> matrix;
ArPose_getMatrix(arcore_session_.get(), arcore_pose.get(), matrix.data());
mojom::XRHitResultPtr mojo_hit = mojom::XRHitResult::New();
// ArPose_getMatrix returns the matrix in WebGL style column-major order
// and gfx::Transform expects row major order.
// clang-format off
mojo_hit->hit_matrix = gfx::Transform(
matrix[0], matrix[4], matrix[8], matrix[12],
matrix[1], matrix[5], matrix[9], matrix[13],
matrix[2], matrix[6], matrix[10], matrix[14],
matrix[3], matrix[7], matrix[11], matrix[15]
);
// clang-format on
mojo_hit->plane_id = plane_id;
{
std::array<float, 7> raw_pose;
ArPose_getPoseRaw(arcore_session_.get(), arcore_pose.get(),
raw_pose.data());
gfx::Quaternion orientation(raw_pose[0], raw_pose[1], raw_pose[2],
raw_pose[3]);
gfx::Point3F position(raw_pose[4], raw_pose[5], raw_pose[6]);
mojo_hit->mojo_from_result = mojom::Pose::New(orientation, position);
DVLOG(3) << __func__
<< ": adding hit test result, position=" << position.ToString()
<< ", orientation=" << orientation.ToString()
<< ", plane_id=" << plane_id << " (0 means no plane)";
}
// Insert new results at head to preserver order from ArCore
hit_results->insert(hit_results->begin(), std::move(mojo_hit));
}
@ -1040,20 +1058,25 @@ void ArCoreImpl::CreateAnchor(
std::move(callback));
}
void ArCoreImpl::CreatePlaneAttachedAnchor(const mojom::Pose& plane_from_anchor,
uint64_t plane_id,
CreateAnchorCallback callback) {
DVLOG(2) << __func__ << ": plane_id=" << plane_id
<< ", plane_from_anchor.position="
<< plane_from_anchor.position.ToString()
<< ", plane_from_anchor.orientation="
<< plane_from_anchor.orientation.ToString();
void ArCoreImpl::CreatePlaneAttachedAnchor(
const mojom::XRNativeOriginInformation& native_origin_information,
const mojom::Pose& native_origin_from_anchor,
uint64_t plane_id,
CreateAnchorCallback callback) {
DVLOG(2) << __func__ << ": native_origin_information.which()="
<< static_cast<uint32_t>(native_origin_information.which())
<< ", plane_id=" << plane_id
<< ", native_origin_from_anchor.position="
<< native_origin_from_anchor.position.ToString()
<< ", native_origin_from_anchor.orientation="
<< native_origin_from_anchor.orientation.ToString();
gfx::Transform plane_from_anchor_transform =
mojo::ConvertTo<gfx::Transform>(plane_from_anchor);
gfx::Transform native_origin_from_anchor_transform =
mojo::ConvertTo<gfx::Transform>(native_origin_from_anchor);
create_plane_attached_anchor_requests_.emplace_back(
plane_from_anchor_transform, plane_id, std::move(callback));
native_origin_information, native_origin_from_anchor_transform, plane_id,
std::move(callback));
}
void ArCoreImpl::ProcessAnchorCreationRequests(
@ -1231,10 +1254,12 @@ ArCore::CreateAnchorCallback CreateAnchorRequest::TakeCallback() {
}
CreatePlaneAttachedAnchorRequest::CreatePlaneAttachedAnchorRequest(
const gfx::Transform& plane_from_anchor,
const mojom::XRNativeOriginInformation& native_origin_information,
const gfx::Transform& native_origin_from_anchor,
uint64_t plane_id,
ArCore::CreateAnchorCallback callback)
: plane_from_anchor_(plane_from_anchor),
: native_origin_information_(native_origin_information),
native_origin_from_anchor_(native_origin_from_anchor),
plane_id_(plane_id),
request_start_time_(base::TimeTicks::Now()),
callback_(std::move(callback)) {}
@ -1244,9 +1269,7 @@ CreatePlaneAttachedAnchorRequest::~CreatePlaneAttachedAnchorRequest() = default;
mojom::XRNativeOriginInformation
CreatePlaneAttachedAnchorRequest::GetNativeOriginInformation() const {
mojom::XRNativeOriginInformation result;
result.set_plane_id(plane_id_);
return result;
return native_origin_information_;
}
uint64_t CreatePlaneAttachedAnchorRequest::GetPlaneId() const {
@ -1255,7 +1278,7 @@ uint64_t CreatePlaneAttachedAnchorRequest::GetPlaneId() const {
gfx::Transform CreatePlaneAttachedAnchorRequest::GetNativeOriginFromAnchor()
const {
return plane_from_anchor_;
return native_origin_from_anchor_;
}
base::TimeTicks CreatePlaneAttachedAnchorRequest::GetRequestStartTime() const {

@ -82,14 +82,17 @@ class CreatePlaneAttachedAnchorRequest {
ArCore::CreateAnchorCallback TakeCallback();
CreatePlaneAttachedAnchorRequest(const gfx::Transform& plane_from_anchor,
uint64_t plane_id,
ArCore::CreateAnchorCallback callback);
CreatePlaneAttachedAnchorRequest(
const mojom::XRNativeOriginInformation& native_origin_information,
const gfx::Transform& native_origin_from_anchor,
uint64_t plane_id,
ArCore::CreateAnchorCallback callback);
CreatePlaneAttachedAnchorRequest(CreatePlaneAttachedAnchorRequest&& other);
~CreatePlaneAttachedAnchorRequest();
private:
const gfx::Transform plane_from_anchor_;
const mojom::XRNativeOriginInformation native_origin_information_;
const gfx::Transform native_origin_from_anchor_;
const uint64_t plane_id_;
const base::TimeTicks request_start_time_;
@ -153,9 +156,11 @@ class ArCoreImpl : public ArCore {
const mojom::XRNativeOriginInformation& native_origin_information,
const mojom::Pose& native_origin_from_anchor,
CreateAnchorCallback callback) override;
void CreatePlaneAttachedAnchor(const mojom::Pose& plane_from_anchor,
uint64_t plane_id,
CreateAnchorCallback callback) override;
void CreatePlaneAttachedAnchor(
const mojom::XRNativeOriginInformation& native_origin_information,
const mojom::Pose& native_origin_from_anchor,
uint64_t plane_id,
CreateAnchorCallback callback) override;
void ProcessAnchorCreationRequests(
const gfx::Transform& mojo_from_viewer,

@ -208,8 +208,9 @@ bool FakeArCore::RequestHitTest(
const mojom::XRRayPtr& ray,
std::vector<mojom::XRHitResultPtr>* hit_results) {
mojom::XRHitResultPtr hit = mojom::XRHitResult::New();
// Identity matrix - no translation and default orientation.
hit->hit_matrix = gfx::Transform();
// Default-constructed `hit->mojo_from_result` is fine, no need to set
// anything.
hit->mojo_from_result = mojom::Pose::New();
hit_results->push_back(std::move(hit));
return true;
@ -307,9 +308,11 @@ mojom::XRLightEstimationDataPtr FakeArCore::GetLightEstimationData() {
return result;
}
void FakeArCore::CreatePlaneAttachedAnchor(const mojom::Pose& plane_from_anchor,
uint64_t plane_id,
CreateAnchorCallback callback) {
void FakeArCore::CreatePlaneAttachedAnchor(
const mojom::XRNativeOriginInformation& native_origin_information,
const mojom::Pose& native_origin_from_anchor,
uint64_t plane_id,
CreateAnchorCallback callback) {
// TODO(992035): Fix this when implementing tests.
std::move(callback).Run(mojom::CreateAnchorResult::FAILURE, 0);
}

@ -64,9 +64,11 @@ class FakeArCore : public ArCore {
const mojom::XRNativeOriginInformation& native_origin_information,
const mojom::Pose& native_origin_from_anchor,
CreateAnchorCallback callback) override;
void CreatePlaneAttachedAnchor(const mojom::Pose& plane_from_anchor,
uint64_t plane_id,
CreateAnchorCallback callback) override;
void CreatePlaneAttachedAnchor(
const mojom::XRNativeOriginInformation& native_origin_information,
const mojom::Pose& native_origin_from_anchor,
uint64_t plane_id,
CreateAnchorCallback callback) override;
void ProcessAnchorCreationRequests(
const gfx::Transform& mojo_from_viewer,

@ -262,7 +262,7 @@ struct XRRay {
};
struct XRHitResult {
gfx.mojom.Transform hit_matrix;
Pose mojo_from_result; // Pose of the result (aka intersection point).
uint64 plane_id; // If the hit test result was computed based off of a plane,
// the plane ID will be stored here. 0 signifies no plane.
// TODO(https://crbug.com/657632) - make it optional once
@ -795,7 +795,11 @@ interface XREnvironmentIntegrationProvider {
// ignored.
UnsubscribeFromHitTest(uint64 subscription_id);
// Issues a request to create an anchor attached to a session.
// Issues a request to create a free-floating anchor (not attached to any
// particular real world entity).
// |native_origin_information| specifies native origin relative to which the
// anchor is supposed to be created. |native_origin_from_anchor| describes the
// desired pose of the newly created anchor.
// |result| will contain status code of the request. |anchor_id| will be valid
// only if the |result| is SUCCESS.
CreateAnchor(
@ -807,11 +811,18 @@ interface XREnvironmentIntegrationProvider {
// not interested in obtaining detailed error information from the device.
// Issues a request to create an anchor attached to a plane.
// |native_origin_information| specifies native origin relative to which the
// anchor is supposed to be created. |native_origin_from_anchor| describes the
// desired pose of the newly created anchor. |plane_id| identifies which plane
// the anchor will be attached to.
// |result| will contain status code of the request. |anchor_id| will be valid
// only if the |result| is SUCCESS.
CreatePlaneAnchor(Pose plane_from_anchor, uint64 plane_id) =>
(CreateAnchorResult result, uint64 anchor_id);
// TODO(https://crbug.com/657632): Ditto - make anchor_id a nullable integer..
CreatePlaneAnchor(
XRNativeOriginInformation native_origin_information,
Pose native_origin_from_anchor,
uint64 plane_id)
=> (CreateAnchorResult result, uint64 anchor_id);
// TODO(https://crbug.com/657632): Ditto - make anchor_id a nullable integer.
// Detaches an existing anchor. The |anchor_id| must be a valid id of an
// anchor created by one of the CreateAnchor calls, otherwise the call will be

@ -4,6 +4,7 @@
#include "third_party/blink/renderer/modules/xr/xr_hit_test_result.h"
#include "third_party/blink/renderer/modules/xr/type_converters.h"
#include "third_party/blink/renderer/modules/xr/xr_hit_test_source.h"
#include "third_party/blink/renderer/modules/xr/xr_pose.h"
#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
@ -18,7 +19,7 @@ XRHitTestResult::XRHitTestResult(
const device::mojom::blink::XRHitResult& hit_result)
: session_(session),
mojo_from_this_(std::make_unique<TransformationMatrix>(
hit_result.hit_matrix.matrix())),
mojo::ConvertTo<TransformationMatrix>(hit_result.mojo_from_result))),
plane_id_(hit_result.plane_id != 0
? base::Optional<uint64_t>(hit_result.plane_id)
: base::nullopt) {}
@ -41,7 +42,6 @@ XRPose* XRHitTestResult::getPose(XRSpace* other) {
}
ScriptPromise XRHitTestResult::createAnchor(ScriptState* script_state,
XRRigidTransform* this_from_anchor,
ExceptionState& exception_state) {
DVLOG(2) << __func__;
@ -51,45 +51,45 @@ ScriptPromise XRHitTestResult::createAnchor(ScriptState* script_state,
return {};
}
if (!this_from_anchor) {
// TODO(https://crbug.com/954236): Revisit the approach of plane poses not
// being stable from frame to frame - if we could guarantee that anchor poses
// are not so dynamic, anchor creation could be improved.
//
// Planes are not considered stationary for the purpose of anchor creation
// (their poses may change dramatically on a frame-by-frame basis). Grab an
// information about reference space that is well-suited for anchor creation
// from session:
base::Optional<XRSession::ReferenceSpaceInformation>
reference_space_information = session_->GetStationaryReferenceSpace();
if (!reference_space_information) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
XRSession::kNoRigidTransformSpecified);
XRSession::kUnableToRetrieveMatrix);
return {};
}
const TransformationMatrix& mojo_from_space =
reference_space_information->mojo_from_space;
DCHECK(mojo_from_space.IsInvertible());
auto space_from_mojo = mojo_from_space.Inverse();
auto space_from_anchor = space_from_mojo * (*mojo_from_this_);
if (plane_id_) {
DVLOG(2) << __func__
<< ": hit test result's entity is a plane, creating "
"plane-attached anchor";
return session_->CreatePlaneAnchorHelper(
script_state, this_from_anchor->TransformMatrix(), *plane_id_,
script_state, space_from_anchor,
reference_space_information->native_origin, *plane_id_,
exception_state);
} else {
DVLOG(2) << __func__
<< ": hit test result's entity is unavailable, creating "
"free-floating anchor ";
// Let's create free-floating anchor since plane is unavailable. Grab an
// information about reference space that is well-suited for anchor creation
// from session:
base::Optional<XRSession::ReferenceSpaceInformation>
reference_space_information = session_->GetStationaryReferenceSpace();
if (!reference_space_information) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
XRSession::kUnableToRetrieveMatrix);
return {};
}
const TransformationMatrix& mojo_from_space =
reference_space_information->mojo_from_space;
DCHECK(mojo_from_space.IsInvertible());
auto space_from_mojo = mojo_from_space.Inverse();
auto space_from_anchor = space_from_mojo * (*mojo_from_this_) *
this_from_anchor->TransformMatrix();
// Let's create free-floating anchor since plane is unavailable.
return session_->CreateAnchorHelper(
script_state, space_from_anchor,
reference_space_information->native_origin, exception_state);

@ -16,7 +16,6 @@ class ExceptionState;
class ScriptState;
class TransformationMatrix;
class XRPose;
class XRRigidTransform;
class XRSession;
class XRSpace;
@ -30,7 +29,6 @@ class XRHitTestResult : public ScriptWrappable {
XRPose* getPose(XRSpace* relative_to);
ScriptPromise createAnchor(ScriptState* script_state,
XRRigidTransform* initial_pose,
ExceptionState& exception_state);
void Trace(Visitor* visitor) const override;

@ -7,5 +7,5 @@ interface XRHitTestResult {
XRPose? getPose(XRSpace relative_to);
[RuntimeEnabled=WebXRAnchors, CallWith=ScriptState, RaisesException, MeasureAs=XRHitTestResultCreateAnchor]
Promise<XRAnchor> createAnchor(XRRigidTransform initial_pose);
Promise<XRAnchor> createAnchor();
};

@ -36,7 +36,7 @@ HeapVector<Member<XRHitTestResult>> XRHitTestSource::Results() {
for (const auto& result : last_frame_results_) {
results.emplace_back(
MakeGarbageCollected<XRHitTestResult>(xr_session_, result));
MakeGarbageCollected<XRHitTestResult>(xr_session_, *result));
}
return results;
@ -47,10 +47,12 @@ void XRHitTestSource::Update(
last_frame_results_.clear();
for (auto& result : hit_test_results) {
DVLOG(3) << __func__ << ": processing hit test result, hit matrix: "
<< result->hit_matrix.ToString()
DVLOG(3) << __func__ << ": processing hit test result, position="
<< result->mojo_from_result->position.ToString()
<< ", orientation="
<< result->mojo_from_result->orientation.ToString()
<< ", plane_id=" << result->plane_id;
last_frame_results_.push_back(*result);
last_frame_results_.emplace_back(result->Clone());
}
}

@ -40,7 +40,7 @@ class XRHitTestSource : public ScriptWrappable {
const uint64_t id_;
Member<XRSession> xr_session_;
Vector<device::mojom::blink::XRHitResult> last_frame_results_;
Vector<device::mojom::blink::XRHitResultPtr> last_frame_results_;
};
} // namespace blink

@ -8,9 +8,14 @@
#include "third_party/blink/renderer/modules/xr/type_converters.h"
#include "third_party/blink/renderer/modules/xr/xr_object_space.h"
#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
#include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
namespace {
const char kUnknownPlanePose[] = "Plane pose is unknown.";
}
namespace blink {
XRPlane::XRPlane(uint64_t id,
@ -92,7 +97,6 @@ HeapVector<Member<DOMPointReadOnly>> XRPlane::polygon() const {
}
ScriptPromise XRPlane::createAnchor(ScriptState* script_state,
XRRigidTransform* initial_pose,
ExceptionState& exception_state) {
DVLOG(2) << __func__;
@ -102,14 +106,37 @@ ScriptPromise XRPlane::createAnchor(ScriptState* script_state,
return {};
}
if (!initial_pose) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
XRSession::kNoRigidTransformSpecified);
if (!mojo_from_plane_) {
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
kUnknownPlanePose);
return {};
}
// Planes are not considered stationary for the purpose of anchor creation
// (their poses may change dramatically on a frame-by-frame basis). Grab an
// information about reference space that is well-suited for anchor creation
// from session:
base::Optional<XRSession::ReferenceSpaceInformation>
reference_space_information = session_->GetStationaryReferenceSpace();
if (!reference_space_information) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
XRSession::kUnableToRetrieveMatrix);
return {};
}
const TransformationMatrix& mojo_from_space =
reference_space_information->mojo_from_space;
DCHECK(mojo_from_space.IsInvertible());
auto space_from_mojo = mojo_from_space.Inverse();
// We'll create an anchor located at the current plane's pose:
auto space_from_anchor = space_from_mojo * (*mojo_from_plane_);
return session_->CreatePlaneAnchorHelper(
script_state, initial_pose->TransformMatrix(), id_, exception_state);
script_state, space_from_anchor,
reference_space_information->native_origin, id_, exception_state);
}
void XRPlane::Update(const device::mojom::blink::XRPlaneData& plane_data,

@ -17,7 +17,6 @@
namespace blink {
class ExceptionState;
class XRRigidTransform;
class XRSession;
class XRSpace;
@ -43,7 +42,6 @@ class XRPlane : public ScriptWrappable {
double lastChangedTime() const;
ScriptPromise createAnchor(ScriptState* script_state,
XRRigidTransform* initial_pose,
ExceptionState& exception_state);
// Updates plane data from passed in |plane_data|. The resulting instance

@ -21,5 +21,5 @@ interface XRPlane {
readonly attribute DOMHighResTimeStamp lastChangedTime;
[CallWith=ScriptState, RaisesException, RuntimeEnabled=WebXRAnchors]
Promise<XRAnchor> createAnchor(XRRigidTransform initial_pose);
Promise<XRAnchor> createAnchor();
};

@ -640,7 +640,9 @@ ScriptPromise XRSession::CreateAnchorHelper(
ScriptPromise XRSession::CreatePlaneAnchorHelper(
ScriptState* script_state,
const blink::TransformationMatrix& plane_from_anchor,
const blink::TransformationMatrix& native_origin_from_anchor,
const device::mojom::blink::XRNativeOriginInformation&
native_origin_information,
uint64_t plane_id,
ExceptionState& exception_state) {
DVLOG(2) << __func__ << ", plane_id=" << plane_id;
@ -658,8 +660,9 @@ ScriptPromise XRSession::CreatePlaneAnchorHelper(
return ScriptPromise();
}
TransformationMatrix::DecomposedType decomposed_plane_from_anchor;
if (!plane_from_anchor.Decompose(decomposed_plane_from_anchor)) {
TransformationMatrix::DecomposedType decomposed_native_origin_from_anchor;
if (!native_origin_from_anchor.Decompose(
decomposed_native_origin_from_anchor)) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kUnableToDecomposeMatrix);
return ScriptPromise();
@ -668,13 +671,13 @@ ScriptPromise XRSession::CreatePlaneAnchorHelper(
// TODO(https://crbug.com/929841): Remove negation in quaternion once the bug
// is fixed.
device::mojom::blink::PosePtr pose_ptr = device::mojom::blink::Pose::New(
gfx::Quaternion(-decomposed_plane_from_anchor.quaternion_x,
-decomposed_plane_from_anchor.quaternion_y,
-decomposed_plane_from_anchor.quaternion_z,
decomposed_plane_from_anchor.quaternion_w),
blink::FloatPoint3D(decomposed_plane_from_anchor.translate_x,
decomposed_plane_from_anchor.translate_y,
decomposed_plane_from_anchor.translate_z));
gfx::Quaternion(-decomposed_native_origin_from_anchor.quaternion_x,
-decomposed_native_origin_from_anchor.quaternion_y,
-decomposed_native_origin_from_anchor.quaternion_z,
decomposed_native_origin_from_anchor.quaternion_w),
blink::FloatPoint3D(decomposed_native_origin_from_anchor.translate_x,
decomposed_native_origin_from_anchor.translate_y,
decomposed_native_origin_from_anchor.translate_z));
DVLOG(3) << __func__
<< ": pose_ptr->orientation = " << pose_ptr->orientation.ToString()
@ -684,7 +687,7 @@ ScriptPromise XRSession::CreatePlaneAnchorHelper(
ScriptPromise promise = resolver->Promise();
xr_->xrEnvironmentProviderRemote()->CreatePlaneAnchor(
std::move(pose_ptr), plane_id,
native_origin_information.Clone(), std::move(pose_ptr), plane_id,
WTF::Bind(&XRSession::OnCreateAnchorResult, WrapPersistent(this),
WrapPersistent(resolver)));

@ -148,9 +148,9 @@ class XRSession final
ExceptionState&);
// Helper, not IDL-exposed
// |native_origin_from_anchor| is a matrix describing transform from native
// origin to the initial anchor's position.
// |native_origin_information| describes native origin telative to which the
// |native_origin_from_anchor| is a matrix describing transform between native
// origin and the initial anchor's position.
// |native_origin_information| describes native origin relative to which the
// transform is expressed.
ScriptPromise CreateAnchorHelper(
ScriptState* script_state,
@ -160,12 +160,16 @@ class XRSession final
ExceptionState& exception_state);
// Helper, not IDL-exposed
// |plane_from_anchor| is a matrix describing transform from plane to the
// initial anchor's position.
// |native_origin_from_anchor| is a matrix describing transform between native
// origin and the initial anchor's position.
// |native_origin_information| describes native origin relative to which the
// transform is expressed.
// |plane_id| is the id of the plane to which the anchor should be attached.
ScriptPromise CreatePlaneAnchorHelper(
ScriptState* script_state,
const blink::TransformationMatrix& plane_from_anchor,
const blink::TransformationMatrix& native_origin_from_anchor,
const device::mojom::blink::XRNativeOriginInformation&
native_origin_information,
uint64_t plane_id,
ExceptionState& exception_state);

@ -1201,32 +1201,32 @@ class MockRuntime extends EventTarget {
}
const hitResult = new device.mojom.XRHitResult();
hitResult.hitMatrix = new gfx.mojom.Transform();
hitResult.distance = distance; // Extend the object with additional information used by higher layers.
// It will not be serialized over mojom.
hitResult.hitMatrix.matrix = new Array(16);
const matrix = new Array(16);
hitResult.hitMatrix.matrix[0] = x_axis.x;
hitResult.hitMatrix.matrix[1] = x_axis.y;
hitResult.hitMatrix.matrix[2] = x_axis.z;
hitResult.hitMatrix.matrix[3] = 0;
matrix[0] = x_axis.x;
matrix[1] = x_axis.y;
matrix[2] = x_axis.z;
matrix[3] = 0;
hitResult.hitMatrix.matrix[4] = y_axis.x;
hitResult.hitMatrix.matrix[5] = y_axis.y;
hitResult.hitMatrix.matrix[6] = y_axis.z;
hitResult.hitMatrix.matrix[7] = 0;
matrix[4] = y_axis.x;
matrix[5] = y_axis.y;
matrix[6] = y_axis.z;
matrix[7] = 0;
hitResult.hitMatrix.matrix[8] = z_axis.x;
hitResult.hitMatrix.matrix[9] = z_axis.y;
hitResult.hitMatrix.matrix[10] = z_axis.z;
hitResult.hitMatrix.matrix[11] = 0;
matrix[8] = z_axis.x;
matrix[9] = z_axis.y;
matrix[10] = z_axis.z;
matrix[11] = 0;
hitResult.hitMatrix.matrix[12] = intersection_point.x;
hitResult.hitMatrix.matrix[13] = intersection_point.y;
hitResult.hitMatrix.matrix[14] = intersection_point.z;
hitResult.hitMatrix.matrix[15] = 1;
matrix[12] = intersection_point.x;
matrix[13] = intersection_point.y;
matrix[14] = intersection_point.z;
matrix[15] = 1;
hitResult.mojoFromResult = XRMathHelper.decomposeRigidTransform(matrix);
return hitResult;
}