Commit 2e3ac049 authored by Piotr Bialecki's avatar Piotr Bialecki Committed by Commit Bot

Add Web IDL for transient input variant of hit test subscription

Along with blink-side implementation of the Web IDL.

Change-Id: I1f975c0b36f2a0e8d38400368455fd4a23cb19c0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1919942
Commit-Queue: Piotr Bialecki <bialpio@chromium.org>
Auto-Submit: Piotr Bialecki <bialpio@chromium.org>
Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarKlaus Weidner <klausw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#718819}
parent 31ceb036
......@@ -541,8 +541,8 @@ enum SubscribeToHitTestResult {
};
enum EntityTypeForHitTest {
POINT = 0,
PLANE = 1,
POINT = 1,
PLANE = 2,
};
// Provides functionality for integrating environment information into an
......
......@@ -531,6 +531,8 @@ modules_idl_files =
"xr/xr_session.idl",
"xr/xr_session_event.idl",
"xr/xr_space.idl",
"xr/xr_transient_input_hit_test_result.idl",
"xr/xr_transient_input_hit_test_source.idl",
"xr/xr_view.idl",
"xr/xr_viewer_pose.idl",
"xr/xr_viewport.idl",
......@@ -890,6 +892,7 @@ modules_dictionary_idl_files =
"xr/xr_render_state_init.idl",
"xr/xr_session_event_init.idl",
"xr/xr_session_init.idl",
"xr/xr_transient_input_hit_test_options_init.idl",
"xr/xr_webgl_layer_init.idl",
"xr/xr_world_tracking_state_init.idl",
],
......
......@@ -72,6 +72,10 @@ blink_modules_sources("xr") {
"xr_space.h",
"xr_target_ray_space.cc",
"xr_target_ray_space.h",
"xr_transient_input_hit_test_result.cc",
"xr_transient_input_hit_test_result.h",
"xr_transient_input_hit_test_source.cc",
"xr_transient_input_hit_test_source.h",
"xr_utils.cc",
"xr_utils.h",
"xr_view.cc",
......
......@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h"
#include "third_party/blink/renderer/modules/xr/xr_view.h"
#include "third_party/blink/renderer/modules/xr/xr_viewer_pose.h"
#include "third_party/blink/renderer/modules/xr/xr_world_information.h"
......@@ -133,7 +134,17 @@ void XRFrame::Deactivate() {
HeapVector<Member<XRHitTestResult>> XRFrame::getHitTestResults(
XRHitTestSource* hit_test_source) {
if (!session_->ValidateHitTestSourceExists(hit_test_source))
if (!hit_test_source ||
!session_->ValidateHitTestSourceExists(hit_test_source))
return {};
return hit_test_source->Results();
}
HeapVector<Member<XRTransientInputHitTestResult>>
XRFrame::getHitTestResultsForTransientInput(
XRTransientInputHitTestSource* hit_test_source) {
if (!hit_test_source ||
!session_->ValidateHitTestSourceExists(hit_test_source))
return {};
return hit_test_source->Results();
}
......
......@@ -17,6 +17,7 @@
namespace blink {
class ExceptionState;
class XRAnchorSet;
class XRHitTestResult;
class XRHitTestSource;
class XRInputSource;
......@@ -24,8 +25,9 @@ class XRPose;
class XRReferenceSpace;
class XRSession;
class XRSpace;
class XRTransientInputHitTestResult;
class XRTransientInputHitTestSource;
class XRViewerPose;
class XRAnchorSet;
class XRWorldInformation;
class XRFrame final : public ScriptWrappable {
......@@ -54,6 +56,10 @@ class XRFrame final : public ScriptWrappable {
HeapVector<Member<XRHitTestResult>> getHitTestResults(
XRHitTestSource* hit_test_source);
HeapVector<Member<XRTransientInputHitTestResult>>
getHitTestResultsForTransientInput(
XRTransientInputHitTestSource* hit_test_source);
bool EmulatedPosition() const { return emulated_position_; }
private:
......
......@@ -19,5 +19,8 @@
[RaisesException] XRViewerPose? getViewerPose(XRReferenceSpace referenceSpace);
[RaisesException] XRPose? getPose(XRSpace space, XRSpace relativeTo);
[RuntimeEnabled=WebXRHitTest] FrozenArray<XRHitTestResult> getHitTestResults(XRHitTestSource hitTestSource);
[RuntimeEnabled=WebXRHitTest]
FrozenArray<XRHitTestResult> getHitTestResults(XRHitTestSource hitTestSource);
[RuntimeEnabled=WebXRHitTest]
FrozenArray<XRTransientInputHitTestResult> getHitTestResultsForTransientInput(XRTransientInputHitTestSource hitTestSource);
};
......@@ -2,7 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
enum XRHitTestTrackableType {
"point",
"plane"
};
dictionary XRHitTestOptionsInit {
required XRSpace space;
FrozenArray<XRHitTestTrackableType> entityTypes;
XRRay offsetRay;
};
......@@ -10,10 +10,8 @@
namespace blink {
XRHitTestResult::XRHitTestResult(XRHitTestSource* hit_test_source,
const TransformationMatrix& pose)
: hit_test_source_(hit_test_source),
pose_(std::make_unique<TransformationMatrix>(pose)) {}
XRHitTestResult::XRHitTestResult(const TransformationMatrix& pose)
: pose_(std::make_unique<TransformationMatrix>(pose)) {}
XRPose* XRHitTestResult::getPose(XRSpace* relative_to) {
DCHECK(relative_to->MojoFromSpace());
......@@ -30,9 +28,4 @@ XRPose* XRHitTestResult::getPose(XRSpace* relative_to) {
return MakeGarbageCollected<XRPose>(other_from_this, false);
}
void XRHitTestResult::Trace(blink::Visitor* visitor) {
visitor->Trace(hit_test_source_);
ScriptWrappable::Trace(visitor);
}
} // namespace blink
......@@ -10,7 +10,6 @@
namespace blink {
class TransformationMatrix;
class XRHitTestSource;
class XRPose;
class XRSpace;
......@@ -18,15 +17,11 @@ class XRHitTestResult : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
XRHitTestResult(XRHitTestSource* hit_test_source,
const TransformationMatrix& pose);
explicit XRHitTestResult(const TransformationMatrix& pose);
XRPose* getPose(XRSpace* relative_to);
void Trace(blink::Visitor* visitor) override;
private:
Member<XRHitTestSource> hit_test_source_;
std::unique_ptr<TransformationMatrix> pose_;
};
......
......@@ -19,7 +19,7 @@ HeapVector<Member<XRHitTestResult>> XRHitTestSource::Results() {
HeapVector<Member<XRHitTestResult>> results;
for (const auto& result : last_frame_results_) {
results.emplace_back(MakeGarbageCollected<XRHitTestResult>(this, *result));
results.emplace_back(MakeGarbageCollected<XRHitTestResult>(*result));
}
return results;
......
......@@ -41,6 +41,8 @@
#include "third_party/blink/renderer/modules/xr/xr_render_state.h"
#include "third_party/blink/renderer/modules/xr/xr_render_state_init.h"
#include "third_party/blink/renderer/modules/xr/xr_session_event.h"
#include "third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_options_init.h"
#include "third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h"
#include "third_party/blink/renderer/modules/xr/xr_view.h"
#include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h"
#include "third_party/blink/renderer/modules/xr/xr_world_information.h"
......@@ -90,6 +92,9 @@ const char kUnableToRetrieveNativeOrigin[] =
const char kHitTestSubscriptionFailed[] = "Hit test subscription failed.";
const char kEntityTypesNotSpecified[] =
"No entityTypes specified: the array cannot be empty!";
const double kDegToRad = M_PI / 180.0;
constexpr wtf_size_t kMinNumberOfBounds = 2;
......@@ -144,6 +149,100 @@ std::unique_ptr<TransformationMatrix> getPoseMatrix(
device::mojom::blink::VRPosePtr>::Convert(pose));
}
base::Optional<device::mojom::blink::EntityTypeForHitTest>
EntityTypeForHitTestFromString(const WTF::String& string) {
if (string == "plane")
return device::mojom::blink::EntityTypeForHitTest::PLANE;
if (string == "point")
return device::mojom::blink::EntityTypeForHitTest::POINT;
NOTREACHED();
return base::nullopt;
}
// Returns a vector of entity types from hit test options, without duplicates.
// OptionsType can be either XRHitTestOptionsInit or
// XRTransientInputHitTestOptionsInit.
template <typename OptionsType>
WTF::Vector<device::mojom::blink::EntityTypeForHitTest>
GetEntityTypesForHitTest(OptionsType* options_init) {
DCHECK(options_init);
WTF::HashSet<device::mojom::blink::EntityTypeForHitTest> result_set;
if (options_init->hasEntityTypes()) {
DVLOG(2) << __func__ << ": options_init->entityTypes().size()="
<< options_init->entityTypes().size();
for (const auto& entity_type_string : options_init->entityTypes()) {
auto maybe_entity_type =
EntityTypeForHitTestFromString(entity_type_string);
if (maybe_entity_type) {
result_set.insert(*maybe_entity_type);
} else {
DVLOG(1) << __func__
<< ": entityTypes entry ignored:" << entity_type_string;
}
}
} else {
result_set.insert(device::mojom::blink::EntityTypeForHitTest::PLANE);
}
DVLOG(2) << __func__ << ": result_set.size()=" << result_set.size();
DCHECK(!result_set.IsEmpty());
WTF::Vector<device::mojom::blink::EntityTypeForHitTest> result;
WTF::CopyToVector(result_set, result);
DVLOG(2) << __func__ << ": result.size()=" << result.size();
return result;
}
// Helper that will remove all entries present in the |id_to_hit_test_source|
// that map to nullptr due to usage of WeakPtr.
// T can be either XRHitTestSource or XRTransientInputHitTestSource.
template <typename T>
void CleanUpUnusedHitTestSourcesHelper(
HeapHashMap<uint64_t, WeakMember<T>>* id_to_hit_test_source) {
DCHECK(id_to_hit_test_source);
// Gather all IDs of unused hit test sources for non-transient input
// sources.
HashSet<uint64_t> unused_hit_test_source_ids;
for (auto& id_and_hit_test_source : *id_to_hit_test_source) {
if (!id_and_hit_test_source.value) {
unused_hit_test_source_ids.insert(id_and_hit_test_source.key);
}
}
// Remove all of the unused hit test sources.
id_to_hit_test_source->RemoveAll(unused_hit_test_source_ids);
}
// Helper that will validate that the passed in |hit_test_source| exists in
// |id_to_hit_test_source| map. The entry can be present but map to nullptr due
// to usage of WeakPtr - in that case, the entry will be removed.
// T can be either XRHitTestSource or XRTransientInputHitTestSource.
template <typename T>
bool ValidateHitTestSourceExistsHelper(
HeapHashMap<uint64_t, WeakMember<T>>* id_to_hit_test_source,
T* hit_test_source) {
DCHECK(id_to_hit_test_source);
DCHECK(hit_test_source);
auto it = id_to_hit_test_source->find(hit_test_source->id());
if (it == id_to_hit_test_source->end()) {
return false;
}
if (!it->value) {
id_to_hit_test_source->erase(it);
return false;
}
return true;
}
} // namespace
class XRSession::XRSessionResizeObserverDelegate final
......@@ -625,8 +724,7 @@ ScriptPromise XRSession::requestHitTestSource(
XRHitTestOptionsInit* options_init,
ExceptionState& exception_state) {
DVLOG(2) << __func__;
DCHECK(options_init); // is this enforced by generated bindings?
DCHECK(options_init);
// 1. Grab the native origin from the passed in XRSpace.
base::Optional<XRNativeOriginInformation> maybe_native_origin =
......@@ -649,6 +747,14 @@ ScriptPromise XRSession::requestHitTestSource(
// wouldn't be set if options_init or space()
// were null.
if (options_init->hasEntityTypes() && options_init->entityTypes().IsEmpty()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kEntityTypesNotSpecified);
return {};
}
auto entity_types = GetEntityTypesForHitTest(options_init);
DVLOG(3) << __func__
<< ": origin_from_space = " << origin_from_space.ToString(true);
......@@ -682,8 +788,7 @@ ScriptPromise XRSession::requestHitTestSource(
ScriptPromise promise = resolver->Promise();
xr_->xrEnvironmentProviderRemote()->SubscribeToHitTest(
maybe_native_origin->ToMojo(),
{device::mojom::blink::EntityTypeForHitTest::PLANE}, std::move(ray_mojo),
maybe_native_origin->ToMojo(), entity_types, std::move(ray_mojo),
WTF::Bind(&XRSession::OnSubscribeToHitTestResult, WrapPersistent(this),
WrapPersistent(resolver)));
request_hit_test_source_promises_.insert(resolver);
......@@ -691,6 +796,44 @@ ScriptPromise XRSession::requestHitTestSource(
return promise;
}
ScriptPromise XRSession::requestHitTestSourceForTransientInput(
ScriptState* script_state,
XRTransientInputHitTestOptionsInit* options_init,
ExceptionState& exception_state) {
DVLOG(2) << __func__;
DCHECK(options_init);
if (options_init->hasEntityTypes() && options_init->entityTypes().IsEmpty()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kEntityTypesNotSpecified);
return {};
}
auto entity_types = GetEntityTypesForHitTest(options_init);
XRRay* offsetRay = options_init && options_init->hasOffsetRay()
? options_init->offsetRay()
: MakeGarbageCollected<XRRay>();
device::mojom::blink::XRRayPtr ray_mojo = device::mojom::blink::XRRay::New();
ray_mojo->origin = {offsetRay->origin()->x(), offsetRay->origin()->y(),
offsetRay->origin()->z()};
ray_mojo->direction = {offsetRay->direction()->x(),
offsetRay->direction()->y(),
offsetRay->direction()->z()};
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
xr_->xrEnvironmentProviderRemote()->SubscribeToHitTestForTransientInput(
options_init->profile(), entity_types, std::move(ray_mojo),
WTF::Bind(&XRSession::OnSubscribeToHitTestForTransientInputResult,
WrapPersistent(this), WrapPersistent(resolver)));
request_hit_test_source_promises_.insert(resolver);
return promise;
}
void XRSession::OnHitTestResults(
ScriptPromiseResolver* resolver,
base::Optional<WTF::Vector<device::mojom::blink::XRHitResultPtr>> results) {
......@@ -736,6 +879,31 @@ void XRSession::OnSubscribeToHitTestResult(
resolver->Resolve(hit_test_source);
}
void XRSession::OnSubscribeToHitTestForTransientInputResult(
ScriptPromiseResolver* resolver,
device::mojom::SubscribeToHitTestResult result,
uint64_t subscription_id) {
DVLOG(2) << __func__ << ": result=" << result
<< ", subscription_id=" << subscription_id;
DCHECK(request_hit_test_source_promises_.Contains(resolver));
request_hit_test_source_promises_.erase(resolver);
if (result != device::mojom::SubscribeToHitTestResult::SUCCESS) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kOperationError, kHitTestSubscriptionFailed));
return;
}
XRTransientInputHitTestSource* hit_test_source =
MakeGarbageCollected<XRTransientInputHitTestSource>(subscription_id);
hit_test_source_ids_to_transient_input_hit_test_sources_.insert(
subscription_id, hit_test_source);
resolver->Resolve(hit_test_source);
}
void XRSession::OnCreateAnchorResult(ScriptPromiseResolver* resolver,
device::mojom::CreateAnchorResult result,
uint64_t id) {
......@@ -847,22 +1015,10 @@ void XRSession::ProcessAnchorsData(
}
void XRSession::CleanUpUnusedHitTestSources() {
// Gather all IDs of unused hit test sources.
HashSet<uint64_t> unused_hit_test_source_ids;
for (auto& subscription_id_and_hit_test_source :
hit_test_source_ids_to_hit_test_sources_) {
if (!subscription_id_and_hit_test_source.value) {
unused_hit_test_source_ids.insert(
subscription_id_and_hit_test_source.key);
}
}
CleanUpUnusedHitTestSourcesHelper(&hit_test_source_ids_to_hit_test_sources_);
// Remove all of the unused hit test sources.
hit_test_source_ids_to_hit_test_sources_.RemoveAll(
unused_hit_test_source_ids);
DVLOG(3) << __func__ << ": removed unused hit test sources, amount: "
<< unused_hit_test_source_ids.size();
CleanUpUnusedHitTestSourcesHelper(
&hit_test_source_ids_to_transient_input_hit_test_sources_);
}
void XRSession::ProcessHitTestData(
......@@ -884,6 +1040,18 @@ void XRSession::ProcessHitTestData(
it->value->Update(hit_test_subscription_data->hit_test_results);
}
}
for (auto& transient_input_hit_test_subscription_data :
hit_test_subscriptions_data->transient_input_results) {
auto it = hit_test_source_ids_to_transient_input_hit_test_sources_.find(
transient_input_hit_test_subscription_data->subscription_id);
if (it !=
hit_test_source_ids_to_transient_input_hit_test_sources_.end()) {
it->value->Update(transient_input_hit_test_subscription_data
->input_source_id_to_hit_test_results,
input_sources_);
}
}
} else {
// We have not received hit test results for any of the hit test
// subscriptions in the current frame - clean up the results on all hit test
......@@ -892,6 +1060,12 @@ void XRSession::ProcessHitTestData(
hit_test_source_ids_to_hit_test_sources_) {
subscription_id_and_hit_test_source.value->Update({});
}
for (auto& subscription_id_and_transient_input_hit_test_source :
hit_test_source_ids_to_transient_input_hit_test_sources_) {
subscription_id_and_transient_input_hit_test_source.value->Update(
{}, nullptr);
}
}
}
......@@ -1222,8 +1396,6 @@ void XRSession::UpdatePresentationFrameState(
emulated_position_ = emulated_position;
UpdateWorldUnderstandingStateForFrame(timestamp, frame_data);
// Process XR input sources
if (frame_pose) {
base::span<const device::mojom::blink::XRInputSourceStatePtr> input_states;
......@@ -1232,6 +1404,8 @@ void XRSession::UpdatePresentationFrameState(
OnInputStateChangeInternal(frame_id, input_states);
UpdateWorldUnderstandingStateForFrame(timestamp, frame_data);
// If this session uses input eventing, XR select events are handled via
// OnButtonEvent, so they need to be ignored here to avoid duplicate events.
if (!uses_input_eventing_) {
......@@ -1536,18 +1710,15 @@ void XRSession::OnExitPresent() {
}
bool XRSession::ValidateHitTestSourceExists(XRHitTestSource* hit_test_source) {
auto it =
hit_test_source_ids_to_hit_test_sources_.find(hit_test_source->id());
if (it == hit_test_source_ids_to_hit_test_sources_.end()) {
return false;
}
if (!it->value) {
hit_test_source_ids_to_hit_test_sources_.erase(it);
return false;
}
return ValidateHitTestSourceExistsHelper(
&hit_test_source_ids_to_hit_test_sources_, hit_test_source);
}
return true;
bool XRSession::ValidateHitTestSourceExists(
XRTransientInputHitTestSource* hit_test_source) {
return ValidateHitTestSourceExistsHelper(
&hit_test_source_ids_to_transient_input_hit_test_sources_,
hit_test_source);
}
void XRSession::SetXRDisplayInfo(
......@@ -1659,6 +1830,7 @@ void XRSession::Trace(blink::Visitor* visitor) {
visitor->Trace(anchor_ids_to_anchors_);
visitor->Trace(prev_base_layer_);
visitor->Trace(hit_test_source_ids_to_hit_test_sources_);
visitor->Trace(hit_test_source_ids_to_transient_input_hit_test_sources_);
EventTargetWithInlineData::Trace(visitor);
}
......
......@@ -48,6 +48,8 @@ class XRRenderState;
class XRRenderStateInit;
class XRRigidTransform;
class XRSpace;
class XRTransientInputHitTestOptionsInit;
class XRTransientInputHitTestSource;
class XRViewData;
class XRWebGLLayer;
class XRWorldInformation;
......@@ -146,6 +148,10 @@ class XRSession final
ScriptPromise requestHitTestSource(ScriptState* script_state,
XRHitTestOptionsInit* options,
ExceptionState& exception_state);
ScriptPromise requestHitTestSourceForTransientInput(
ScriptState* script_state,
XRTransientInputHitTestOptionsInit* options_init,
ExceptionState& exception_state);
ScriptPromise requestHitTest(ScriptState* script_state,
XRRay* ray,
......@@ -235,6 +241,8 @@ class XRSession final
// Returns true if the session recognizes passed in hit_test_source as still
// existing.
bool ValidateHitTestSourceExists(XRHitTestSource* hit_test_source);
bool ValidateHitTestSourceExists(
XRTransientInputHitTestSource* hit_test_source);
void SetXRDisplayInfo(device::mojom::blink::VRDisplayInfoPtr display_info);
......@@ -291,6 +299,15 @@ class XRSession final
void ProcessInputSourceEvents(
base::span<const device::mojom::blink::XRInputSourceStatePtr>
input_states);
// Processes world understanding state for current frame:
// - updates state of hit test sources & fills them out with results
// - updates state of detected planes
// - updates state of anchors
// In order to correctly set the state of hit test sources, this *must* be
// called after updating XRInputSourceArray (performed by
// OnInputStateChangeInternal) as hit test results for transient input sources
// use the mapping of input source id to XRInputSource object.
void UpdateWorldUnderstandingStateForFrame(
double timestamp,
const device::mojom::blink::XRFrameDataPtr& frame_data);
......@@ -313,6 +330,11 @@ class XRSession final
device::mojom::SubscribeToHitTestResult result,
uint64_t subscription_id);
void OnSubscribeToHitTestForTransientInputResult(
ScriptPromiseResolver* resolver,
device::mojom::SubscribeToHitTestResult result,
uint64_t subscription_id);
void OnCreateAnchorResult(ScriptPromiseResolver* resolver,
device::mojom::CreateAnchorResult result,
uint64_t id);
......@@ -368,6 +390,8 @@ class XRSession final
// that we don't keep the XRHitTestSources alive.
HeapHashMap<uint64_t, WeakMember<XRHitTestSource>>
hit_test_source_ids_to_hit_test_sources_;
HeapHashMap<uint64_t, WeakMember<XRTransientInputHitTestSource>>
hit_test_source_ids_to_transient_input_hit_test_sources_;
WTF::Vector<XRViewData> views_;
......@@ -379,8 +403,8 @@ class XRSession final
HeapHashSet<Member<ScriptPromiseResolver>> hit_test_promises_;
// Set of promises returned from CreateAnchor that are still in-flight.
HeapHashSet<Member<ScriptPromiseResolver>> create_anchor_promises_;
// Set of promises returned from requestHitTestSource that are still
// in-flight.
// Set of promises returned from requestHitTestSource and
// requestHitTestSourceForTransientInput that are still in-flight.
HeapHashSet<Member<ScriptPromiseResolver>> request_hit_test_source_promises_;
HeapVector<Member<XRReferenceSpace>> reference_spaces_;
......
......@@ -58,5 +58,9 @@ enum XRVisibilityState {
[CallWith=ScriptState, Measure, RaisesException] Promise<void> end();
[RuntimeEnabled=WebXRHitTest, CallWith=ScriptState, RaisesException] Promise<XRHitTestSource> requestHitTestSource(XRHitTestOptionsInit options);
// https://github.com/immersive-web/hit-test/blob/master/hit-testing-explainer.md
[RuntimeEnabled=WebXRHitTest, CallWith=ScriptState, RaisesException]
Promise<XRHitTestSource> requestHitTestSource(XRHitTestOptionsInit options);
[RuntimeEnabled=WebXRHitTest, CallWith=ScriptState, RaisesException]
Promise<XRTransientInputHitTestSource> requestHitTestSourceForTransientInput(XRTransientInputHitTestOptionsInit options);
};
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
dictionary XRTransientInputHitTestOptionsInit {
required DOMString profile;
FrozenArray<XRHitTestTrackableType> entityTypes;
XRRay offsetRay;
};
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_result.h"
#include "device/vr/public/mojom/vr_service.mojom-blink.h"
#include "third_party/blink/renderer/modules/xr/xr_hit_test_result.h"
#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
namespace blink {
XRTransientInputHitTestResult::XRTransientInputHitTestResult(
XRInputSource* input_source,
const WTF::Vector<device::mojom::blink::XRHitResultPtr>& results)
: input_source_(input_source) {
for (const auto& result : results) {
results_.push_back(
MakeGarbageCollected<XRHitTestResult>(result->hit_matrix.matrix()));
}
}
XRInputSource* XRTransientInputHitTestResult::inputSource() {
return input_source_;
}
HeapVector<Member<XRHitTestResult>> XRTransientInputHitTestResult::results() {
return results_;
}
void XRTransientInputHitTestResult::Trace(blink::Visitor* visitor) {
visitor->Trace(input_source_);
visitor->Trace(results_);
ScriptWrappable::Trace(visitor);
}
} // namespace blink
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_TRANSIENT_INPUT_HIT_TEST_RESULT_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_TRANSIENT_INPUT_HIT_TEST_RESULT_H_
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
namespace blink {
class XRInputSource;
class XRHitTestResult;
class XRTransientInputHitTestResult : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
XRTransientInputHitTestResult(
XRInputSource* input_source,
const WTF::Vector<device::mojom::blink::XRHitResultPtr>& results);
XRInputSource* inputSource();
HeapVector<Member<XRHitTestResult>> results();
void Trace(blink::Visitor* visitor) override;
private:
Member<XRInputSource> input_source_;
HeapVector<Member<XRHitTestResult>> results_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_TRANSIENT_INPUT_HIT_TEST_RESULT_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[SecureContext, Exposed=Window, RuntimeEnabled=WebXRHitTest]
interface XRTransientInputHitTestResult {
[SameObject] readonly attribute XRInputSource inputSource;
[SameObject] readonly attribute FrozenArray<XRHitTestResult> results;
};
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h"
#include "third_party/blink/renderer/modules/xr/xr_input_source_array.h"
#include "third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_result.h"
#include "device/vr/public/mojom/vr_service.mojom-blink.h"
namespace blink {
XRTransientInputHitTestSource::XRTransientInputHitTestSource(uint64_t id)
: id_(id) {}
uint64_t XRTransientInputHitTestSource::id() const {
return id_;
}
void XRTransientInputHitTestSource::Update(
const WTF::HashMap<uint32_t,
WTF::Vector<device::mojom::blink::XRHitResultPtr>>&
hit_test_results,
XRInputSourceArray* input_source_array) {
// TODO: Be smarter about the update - it's possible to add new resulst /
// remove the ones that were removed & update the ones that are being changed.
current_frame_results_.clear();
// If we don't know anything about input sources, we won't be able to
// construct any results so we are done (and current_frame_results_ should
// stay empty).
if (!input_source_array) {
return;
}
for (const auto& source_id_and_results : hit_test_results) {
XRInputSource* input_source =
input_source_array->GetWithSourceId(source_id_and_results.key);
// If the input source with the given ID could not be found, just skip
// processing results for this input source.
if (!input_source)
continue;
current_frame_results_.push_back(
MakeGarbageCollected<XRTransientInputHitTestResult>(
input_source, source_id_and_results.value));
}
}
HeapVector<Member<XRTransientInputHitTestResult>>
XRTransientInputHitTestSource::Results() {
return current_frame_results_;
}
void XRTransientInputHitTestSource::Trace(blink::Visitor* visitor) {
visitor->Trace(current_frame_results_);
ScriptWrappable::Trace(visitor);
}
} // namespace blink
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_TRANSIENT_INPUT_HIT_TEST_SOURCE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_TRANSIENT_INPUT_HIT_TEST_SOURCE_H_
#include <memory>
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
namespace blink {
class XRInputSourceArray;
class XRTransientInputHitTestResult;
class XRTransientInputHitTestSource : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
explicit XRTransientInputHitTestSource(uint64_t id);
uint64_t id() const;
void Update(
const WTF::HashMap<uint32_t,
WTF::Vector<device::mojom::blink::XRHitResultPtr>>&
hit_test_results,
XRInputSourceArray* input_source_array);
HeapVector<Member<XRTransientInputHitTestResult>> Results();
void Trace(blink::Visitor*) override;
private:
HeapVector<Member<XRTransientInputHitTestResult>> current_frame_results_;
const uint64_t id_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_TRANSIENT_INPUT_HIT_TEST_SOURCE_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[SecureContext, Exposed=Window, RuntimeEnabled=WebXRHitTest]
interface XRTransientInputHitTestSource {
};
......@@ -11068,6 +11068,7 @@ interface XRFrame
getter session
method constructor
method getHitTestResults
method getHitTestResultsForTransientInput
method getPose
method getViewerPose
interface XRHitResult
......@@ -11164,6 +11165,7 @@ interface XRSession : EventTarget
method requestAnimationFrame
method requestHitTest
method requestHitTestSource
method requestHitTestSourceForTransientInput
method requestReferenceSpace
method updateRenderState
setter onend
......@@ -11179,6 +11181,14 @@ interface XRSessionEvent : Event
interface XRSpace : EventTarget
attribute @@toStringTag
method constructor
interface XRTransientInputHitTestResult
attribute @@toStringTag
getter inputSource
getter results
method constructor
interface XRTransientInputHitTestSource
attribute @@toStringTag
method constructor
interface XRView
attribute @@toStringTag
getter eye
......
......@@ -80,6 +80,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
let xrViewerSpace = null;
let xrOffsetSpace = null;
let xrViewerSpaceHitTestSource = null;
let xrTransientInputHitTestSource = null;
// WebGL scene globals.
let gl = null;
......@@ -163,6 +164,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
session.addEventListener('select', onSelect);
session.addEventListener('inputsourceschange', onInputSourcesChange);
session.requestHitTestSourceForTransientInput({
profile : "generic-touchscreen"
}).then(transient_input_hit_test_source => {
console.debug("Hit test source for generic touchscreen created!");
xrTransientInputHitTestSource = transient_input_hit_test_source;
});
if (!gl) {
gl = createWebGLContext({
xrCompatible: true
......@@ -245,33 +253,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
let rayDirection = vec3.create();
function onSelect(event) {
if (useReticle.checked && arObject.visible) {
if (arObject.visible) {
// If we're using the reticle then we've already got a mesh positioned
// at the latest hit point and we should just use its matrix to save
// an unnecessary requestHitTest call.
addARObjectAt(arObject.matrix);
} else {
// Otherwise we'll use the target ray from the input source that generated
// this event to fire off a new hit test.
let inputPose = event.frame.getPose(event.inputSource.targetRaySpace, xrRefSpace);
if (inputPose) {
let targetRay = new XRRay(inputPose.transform);
vec3.set(rayOrigin,
targetRay.origin.x,
targetRay.origin.y,
targetRay.origin.z);
vec3.set(rayDirection,
targetRay.direction.x,
targetRay.direction.y,
targetRay.direction.z);
let ray = new XRRay(DOMPointFromVec3(rayOrigin), DOMPointFromVec3(rayDirection));
event.frame.session.requestHitTest(ray, xrRefSpace).then((results) => {
if (results.length) {
addARObjectAt(results[0].hitMatrix);
}
});
}
}
}
......@@ -305,6 +291,16 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
arObject.visible = false;
}
} else if (!useReticle.checked && xrTransientInputHitTestSource) {
let results_by_input_source = frame.getHitTestResultsForTransientInput(xrTransientInputHitTestSource);
if(results_by_input_source.length && results_by_input_source[0].results.length) {
let hitResult = results_by_input_source[0].results[0];
arObject.visible = true;
arObject.matrix = hitResult.getPose(xrRefSpace).transform.matrix;
} else {
arObject.visible = false;
}
} else {
arObject.visible = false;
}
......
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